[
  {
    "path": ".clang-format",
    "content": "BasedOnStyle: Google\nIndentWidth: 4\nTabWidth: 4\nUseTab: Never\nColumnLimit: 120\nBreakBeforeBraces: Attach\nAllowShortFunctionsOnASingleLine: Inline\nPointerAlignment: Left\nDerivePointerAlignment: false\nSpacesInParentheses: false\nSpaceAfterCStyleCast: true\nSpaceBeforeParens: ControlStatements\nSortIncludes: true\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\n\non:\n  pull_request:\n    branches: [ main, dev ]\n\njobs:\n  build-linux:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v4\n        with:\n          submodules: recursive\n\n      - name: Set up Qt\n        uses: jurplel/install-qt-action@v3\n        with:\n          version: '6.6.3'\n          host: linux\n          target: desktop\n\n      - name: Install dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y build-essential cmake ninja-build libcurl4-openssl-dev libjsoncpp-dev libsqlite3-dev libssl-dev libfmt-dev libspdlog-dev\n\n      - name: Configure\n        run: |\n          cmake -S app -B build -G \"Ninja\" -DCMAKE_BUILD_TYPE=Release\n\n      - name: Build\n        run: cmake --build build\n\n      - name: Run ctest\n        run: cd build && ctest --output-on-failure\n\n  build-windows:\n    runs-on: windows-latest\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v4\n        with:\n          submodules: recursive\n\n      - name: Enable long paths\n        run: git config --system core.longpaths true\n\n      - name: Set up vcpkg\n        shell: pwsh\n        run: |\n          git clone https://github.com/microsoft/vcpkg.git \"$env:GITHUB_WORKSPACE\\vcpkg\"\n          & \"$env:GITHUB_WORKSPACE\\vcpkg\\bootstrap-vcpkg.bat\"\n\n      - name: Build llama runtime\n        shell: pwsh\n        run: |\n          $vcpkgRoot = \"$env:GITHUB_WORKSPACE\\vcpkg\"\n          & \"$env:GITHUB_WORKSPACE\\app\\scripts\\build_llama_windows.ps1\" `\n            \"cuda=off\" `\n            \"vulkan=off\" `\n            \"blas=off\" `\n            \"vcpkgroot=$vcpkgRoot\"\n\n      - name: Build and test Windows app\n        shell: pwsh\n        run: |\n          $vcpkgRoot = \"$env:GITHUB_WORKSPACE\\vcpkg\"\n          & \"$env:GITHUB_WORKSPACE\\app\\build_windows.ps1\" `\n            -Configuration Release `\n            -VcpkgRoot $vcpkgRoot `\n            -BuildTests `\n            -RunTests `\n            -Parallel 4\n"
  },
  {
    "path": ".gitignore",
    "content": "# Created by https://www.toptal.com/developers/gitignore/api/c++,visualstudiocode\n# Edit at https://www.toptal.com/developers/gitignore?templates=c++,visualstudiocode\n\n### C++ ###\n# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\nobj/\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Databases\n*.db\n\n# Environment variables\n# .env\nencryption.ini\n\n# Virtual environments\n.venv/\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\nmain\nobfuscate_encrypt\nbin/\n\n# Keep vendored PDFium runtimes in source control.\n!external/pdfium/**/bin/\n!external/pdfium/**/bin/pdfium.dll\n!external/pdfium/**/lib/\n!external/pdfium/**/lib/pdfium.dll.lib\n!external/pdfium/**/lib/libpdfium.so\n!external/pdfium/**/lib/libpdfium.dylib\n\n# Scripts\nreset_key_4_github.sh\ncreate_macos_bundle.sh\ncreate_dmg.sh\n\n# Packaging\n*.nsi\n*.msix\nmsix/\npackage_msix.ps1\nappcert-AIFileSorter.xml\nmsix-layout/\n\n# References\n# includePaths.txt\n\n### VisualStudioCode ###\n.vscode/\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n!.vscode/*.code-snippets\n\n### Visual Studio\nvcpkg_installed/\n\n# Local History for Visual Studio Code\n.history/\n\n# Cache directories\n.cache/\n.ccache*/\n.codacy/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n.ionide\n\n# Temp files\n*.*~\n*~\n\n# Temp notes\ntodos_md/\n\n# Mac files\n.DS_Store\n\n# Script docs + backups\napp/scripts/SCRIPTS-README.md\napp/scripts/local_support_code_signer.py\napp/scripts/__pycache__/\n*.bak\n\n# Ignore llama headers (generated or from external)\napp/include/llama/*.h\n\n# R & D stage\n/assets/\n/docs/\n/scripts/\n!app/scripts/\n/tools/\n/reports/\n/logo-workdir-temp/\n/Testing/\n/changelog/\n/models/\n/rd/\n/prototypes/\n/store/ms-store/\n/.github/workflows/ms-store-listing.yml\n\n# Build artifacts\n\nbuild*/\ndist/\napp/lib/ggml/\n# Generated precompiled llama runtime directories\napp/lib/precompiled*/\nexternal/libzip/build*/\n\n# No longer relevant\napi-key-encryption/\n\n# End of https://www.toptal.com/developers/gitignore/api/c++,visualstudiocode\n\n\n#Ignore vscode AI rules\n.github/instructions/codacy.instructions.md\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"app/include/external/llama.cpp\"]\n\tpath = app/include/external/llama.cpp\n\turl = https://github.com/ggerganov/llama.cpp.git\n\tignore = dirty\n[submodule \"external/Catch2\"]\n\tpath = external/Catch2\n\turl = https://github.com/catchorg/Catch2.git\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "﻿# Changelog\n\n## [1.7.3] - 2026-03-22\n\n- 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.\n- App updates now support separate update streams for Windows, macOS, and Linux, while still accepting the legacy single-stream manifest format for newer clients.\n- 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.\n- The UI translation system was migrated fully to Qt `.ts` / `.qm` catalogs.\n- 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.\n- Recursive scans now tolerate unreadable subfolders and other filesystem errors instead of aborting the overall run.\n- Cached category labels are sanitized more aggressively to avoid malformed UTF-8 data breaking later categorization or display.\n- 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.\n- 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.\n- Added cross-platform diagnostics collection scripts for Linux, macOS, and Windows.\n- Misc improvements.\n- Misc bug fixes.\n\n## [1.7.0] - 2026-03-08\n\n- Progress dialog redesigned into a stage-based table view with explicit stages for Image analysis, Document analysis, and Categorization.\n- Added an image analysis option to append image creation dates (if available) to category names.\n- 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.\n- Bug fixes.\n\n## [1.6.1] - 2026-02-06\n\n- Local text LLM now prompts to switch to CPU when GPU initialization or inference fails.\n\n## [1.6.0] - 2026-02-04\n\n- 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).\n- 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.\n- Improved the LLM selection dialog latency.\n- 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.\n- LLM-derived categorizations and rename suggestions are now saved as you go, so progress isn't lost if the app closes unexpectedly.\n- Image analysis now falls back (with a user prompt) to CPU if the GPU has insufficient available memory.\n- Review dialog now lets you select highlighted rows and bulk edit their categories.\n- Review dialog is now scrollable on smaller screens so action buttons stay visible.\n- Improved subcategory consistency by merging labels that only differ by generic suffixes (e.g., “files”).\n- Added a system compatibility check (benchmarking) to determine the most suitable LLM for your system.\n- Added Korean as an interface language.\n- macOS builds now include variant `make` targets for Apple Silicon (M1 / M2-M3) and Intel outputs, plus improved arch-aware llama.cpp builds.\n- UI, stability, persistence, and usability improvements.\n\n## [1.5.0] - 2026-01-11\n\n- Added content analysis for picture files via LLaVA (visual LLM), with separate model + mmproj downloads in the Select LLM dialog.\n- Added image analysis options in the main window (analyze images, offer rename suggestions, rename-only mode).\n- Added an image-only processing toggle to focus runs on supported picture files and disable standard categorization controls.\n- Added document content analysis (text LLM) with rename-only/document-only modes and optional creation-date suffixes for categories.\n- Added support for document formats including PDF, DOCX, XLSX, PPTX, ODT, ODS, and ODP (plus common text formats).\n- Document analysis now uses embedded PDFium/libzip/pugixml in bundled builds (no pdftotext/unzip requirement).\n- Review dialog now supports rename-only flows, suggested filename edits, and status labels for Renamed / Renamed & Moved.\n- 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.\n- Added Dutch as a selectable interface language.\n- Analysis progress dialog output is now fully localized (status tags, scan/process lines, and file/directory labels) to match the selected UI language.\n- Build/test updates: mtmd progress callback auto-detection, mtmd-cli build fix, and new Catch2 tests for rename-only caching.\n\n## [1.4.5] - 2025-12-05\n\n- Added support for Gemini (a remote LLM) - with your own Gemini API key.\n- Fixed compile under Arch Linux.\n\n## [1.4.0] - 2025-12-05\n\n- Added dry run / preview-only mode with From/To table, no moves performed until you uncheck.\n- Persistent Undo: the latest sort saves a plan file; use Edit -> \"Undo last run\" even after closing dialogs.\n- UI tweaks: Name column auto-resizes, new translations for dry run/undo strings, Undo moved to top of Edit menu.\n- A few more guard rails added.\n- Remote LLM flow now uses your own OpenAI API key (any ChatGPT model supported); the bundled remote key and obfuscation step were removed.\n\n## [1.3.0] - 2025-11-21\n\n- You can now switch between two categorization modes: More Refined and More Consistent. Choose depending on your folder and use case.\n- Added optional Whitelists - limit the number and names of categories when needed.\n- Added sorting by file names, categories, subcategories in the Categorization Review dialog.\n- You can now add a custom Local LLM in the Select LLM dialog.\n- Multilingual categorization: the file categorization labels can now be assigned in Dutch, French, German, Italian, Polish, Portuguese, Spanish, and Turkish.\n- New interface languages: Dutch, German, Italian, Polish, Portugese, Spanish, and Turkish.\n\n## [1.1.0] - 2025-11-08\n\n- New feature: Support for Vulkan. This means that many non-Nvidia graphics cards (GPUs) are now supported for compute acceleration during local LLM inference.\n- New feature: Toggle subcategories in the categorization review dialog.\n- New feature: Undo the recent file sort (move) action.\n- Fixes: Bug fixes and stability improvements.\n- Added a CTest-integrated test suite. Expanded test coverage.\n- Code optimization refactors.\n\n## [1.0.0] - 2025-10-30\n\n- Migrated the entire desktop UI from GTK/Glade to a native Qt6 interface.\n- Added selection boxes for files in the categorization review dialog.\n- Added internatioinalization framework and the French translation for the user interface.\n- Added refreshed menu icons, mnemonic behaviour, and persistent File Explorer settings.\n- Simplified cross-platform builds (Linux/macOS) around Qt6; retired the MSYS2/GTK toolchain.\n- Optimized and cleaned up the code. Fixed error-prone areas.\n- Modernized the build pipeline. Introduced CMake for compilation on Windows.\n\n## [0.9.7] - 2025-10-19\n\n- Added paths to files in LLM requests for more context.\n- Added taxonomy for more consistent assignment of categories across categorizations.\n  (Narrowing down the number of categories and subcategories).\n- Improved the readability of the categorization progress dialog box.\n- Improved the stability of CUDA detection and interaction.\n- Added more logging coverage throughout the code base.\n\n## [0.9.3] - 2025-09-22\n\n- Added compatibility with CUDA 13.\n\n## [0.9.2] - 2025-08-06\n\n- Bug fixes.\n- Increased code coverage with logging.\n\n## [0.9.1] - 2025-08-01\n\n- Bug fixes.\n- Minor improvements for stability.\n- Removed the deprecated GPU backend from the runtime build.\n\n## [0.9.0] - 2025-07-18\n\n- Local LLM support with `llama.cpp`.\n- LLM selection and download dialog.\n- Improved `Makefile` for a more hassle-free build and installation.\n- Minor bug fixes and improvements.\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n\n"
  },
  {
    "path": "README.md",
    "content": "<!-- markdownlint-disable MD046 -->\n# AI File Sorter\n\n[![Code Version](https://img.shields.io/badge/Code-1.7.3-blue)](#)\n[![Release Version](https://img.shields.io/github/v/release/hyperfield/ai-file-sorter?label=Release)](#)\n![filesorter.app Downloads](https://filesorter.app/download-stats/badge.svg)\n[![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)\n[![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)\n[![Donate](https://img.shields.io/badge/Support%20AI%20File%20Sorter-orange)](https://filesorter.app/donate/)\n\n<p align=\"center\">\n  <img src=\"app/resources/images/icon_256x256.png\" alt=\"AI File Sorter logo\" width=\"128\" height=\"128\">\n</p>\n\n<p align=\"center\">\n  <img src=\"images/platform-logos/logo-vulkan.png\" alt=\"Vulkan\" width=\"160\">\n  <img src=\"images/platform-logos/logo-cuda.png\" alt=\"CUDA\" width=\"160\">\n  <img src=\"images/platform-logos/logo-metal.png\" alt=\"Apple Metal\" width=\"160\">\n  <img src=\"images/platform-logos/logo-windows.png\" alt=\"Windows\" width=\"160\">\n  <img src=\"images/platform-logos/logo-macos.png\" alt=\"macOS\" width=\"160\">\n  <img src=\"images/platform-logos/logo-linux.png\" alt=\"Linux\" width=\"160\">\n</p>\n\nAI 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.\n\n<p align=\"center\">\n  <img src=\"images/screenshots/before-after/aifs_before_after_v.png\" alt=\"AI File Sorter before and after organization example\" width=\"600\">\n</p>\n\nThe 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.\n\nAI 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.\n\nInstead 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.\n\nCategories (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.\n\nPrivacy-first by design:\nAI 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.\n\n---\n\n#### How It Works\n\n1. Point the app at a folder or drive  \n2. Files (and image content, when applicable) are analyzed using the selected local or remote model  \n3. Category and rename suggestions are generated  \n4. You review and adjust if needed - done  \n\n---\n\n[![Download ai-file-sorter](https://a.fsdn.com/con/app/sf-download-button)](https://sourceforge.net/projects/ai-file-sorter/files/latest/download)\n\n[![Get it from Microsoft](https://get.microsoft.com/images/en-us%20dark.svg)](https://apps.microsoft.com/detail/9npk4dzd6r6s)\n\n![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)\n\n---\n\n- [AI File Sorter](#ai-file-sorter)\n  - [Changelog](#changelog)\n  - [Features](#features)\n  - [Categorization](#categorization)\n    - [Categorization modes](#categorization-modes)\n    - [Category whitelists](#category-whitelists)\n  - [Image analysis (Visual LLM)](#image-analysis-visual-llm)\n    - [Required visual LLM files](#required-visual-llm-files)\n    - [Main window options](#main-window-options)\n  - [Document analysis (Text LLM)](#document-analysis-text-llm)\n    - [Supported document formats](#supported-document-formats)\n    - [Main window options (documents)](#main-window-options-documents)\n  - [Audio/video metadata filename suggestions](#audiovideo-metadata-filename-suggestions)\n    - [Supported audio/video formats](#supported-audiovideo-formats)\n  - [System compatibility check](#system-compatibility-check)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n    - [Linux](#linux)\n    - [macOS](#macos)\n    - [Windows](#windows)\n  - [Categorization cache database](#categorization-cache-database)\n  - [Uninstallation](#uninstallation)\n  - [Using your OpenAI API key](#using-your-openai-api-key)\n  - [Using your Gemini API key](#using-your-gemini-api-key)\n  - [Testing](#testing)\n  - [Diagnostics](#diagnostics)\n  - [How to Use](#how-to-use)\n  - [Sorting a Remote Directory (e.g., NAS)](#sorting-a-remote-directory-eg-nas)\n  - [Contributing](#contributing)\n  - [Credits](#credits)\n  - [License](#license)\n  - [Donation](#donation)\n\n---\n\n## Changelog\n\n## [1.7.3] - 2026-03-22\n\n- 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.\n- App updates now support separate update streams for Windows, macOS, and Linux, while still accepting the legacy single-stream manifest format for newer clients.\n- 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.\n- The UI translation system was migrated fully to Qt `.ts` / `.qm` catalogs.\n- Local categorization with local LLMs is now more robust.\n- Cached category labels are sanitized more aggressively to avoid malformed UTF-8 data breaking later categorization or display.\n- Misc improvements.\n- Misc bug fixes.\n\nSee [CHANGELOG.md](CHANGELOG.md) for the full history.\n\n---\n\n## Features\n\n- **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).\n- **Offline-Friendly**: Use a local LLM to categorize files entirely - no internet or API key required.\n- **Robust categorization**: Taxonomy and heuristics help keep labels more consistent across runs.\n- **Customizable sorting rules**: Automatically assign categories and subcategories for granular organization.\n- **Two categorization modes**: Pick **More Refined** for detailed labels or **More Consistent** to bias toward uniform categories within a folder.\n- **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.\n- **Multilingual categorization**: Have the LLM assign categories in Dutch, French, German, Italian, Polish, Portuguese, Spanish, or Turkish (model dependent).\n- **Custom local LLMs**: Register your own local GGUF models directly from the **Select LLM** dialog.\n- **Image content analysis (Visual LLM)**: Analyze supported picture files with LLaVA to produce descriptions and optional filename suggestions (rename-only mode supported).\n- **Image date-to-category suffix (optional)**: Append image creation date metadata to image category names when available.\n- **Document content analysis (Text LLM)**: Analyze supported document files to summarize content and suggest filenames; uses the same selected LLM (local or remote).\n- **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.\n- **Sortable review**: Sort the Categorization Review table by file name, category, or subcategory to triage faster.\n- **Qt6 Interface**: Lightweight and responsive UI with refreshed menus and icons.\n- **Interface languages**: English, Dutch, French, German, Italian, Korean, Spanish, and Turkish.\n- **Cross-Platform Compatibility**: Works on Windows, macOS, and Linux.\n- **Local Database Caching**: Speeds up repeated categorization and minimizes remote LLM usage costs.\n- **Sorting Preview**: See how files will be organized before confirming changes.\n- **Dry run** / preview-only mode to inspect planned moves without touching files.\n- **Persistent Undo** (\"Undo last run\") even after closing the sort dialog.\n- **Bring your own key**: Paste your OpenAI or Gemini API key once; it's stored locally and reused for remote runs.\n- **Update Notifications**: Get notified about updates - with optional or required update flows.\n\n---\n\n## Categorization\n\n### Categorization modes\n\n- **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.\n- **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.\n- Switch between the two via the **Categorization type** radio buttons on the main window; your choice is saved for the next run.\n\n### Category whitelists\n\n- Enable **Use a whitelist** to inject the selected whitelist into the LLM prompt; disable it to let the model choose freely.\n- 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.\n- 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.\n- Whitelists apply in either categorization mode; pair them with **More consistent** when you want the strongest adherence to a constrained vocabulary.\n\n---\n\n## Image analysis (Visual LLM)\n\nImage 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.\n\n### Required visual LLM files\n\nThe **Select LLM** dialog now includes an \"Image analysis models (LLaVA)\" section with two downloads:\n\n- **LLaVA text model (GGUF)**: The main language model that produces the description and the filename suggestion.\n- **LLaVA mmproj (vision encoder projection, GGUF)**: The adapter that maps vision embeddings into the LLM token space so the model can accept images.\n\nBoth 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)).\n\n### Main window options\n\nImage analysis adds six related checkboxes to the main window:\n\n- **Analyze picture files by content (can be slow)**: Runs the visual LLM on supported picture files and reports progress in the analysis dialog.\n- **Process picture files only (ignore any other files)**: Restricts the run to supported picture files and disables the categorization controls while active.\n- **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.\n- **Add photo date and place to filename (if available)**: Adds metadata-based date/place prefixes to suggested image filenames when available.\n- **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.\n- **Do not categorize picture files (only rename)**: Skips text categorization for images and keeps them in place while applying (optional) renames.\n\nThe 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).\n\n---\n\n## Document analysis (Text LLM)\n\nDocument 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.\n\n### Supported document formats\n\n- Plain text: `.txt`, `.md`, `.rtf`, `.csv`, `.tsv`, `.json`, `.xml`, `.yml`/`.yaml`, `.ini`/`.cfg`/`.conf`, `.log`, `.html`/`.htm`, `.tex`, `.rst`\n- 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`)\n- Office/OpenOffice: `.docx`, `.xlsx`, `.pptx`, `.odt`, `.ods`, `.odp` (embedded libzip+pugixml in bundled builds; CLI fallback uses `unzip` if you build without vendored libs)\n- Legacy binary formats like `.doc`, `.xls`, `.ppt` are not currently supported.\n\nSource 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`.\n\n### Main window options (documents)\n\n- **Analyze document files by content**: Extracts document text and feeds it into the LLM for summary + rename suggestion.\n- **Process document files only (ignore any other files)**: Restricts the run to supported document files and disables the categorization controls while active.\n- **Offer to rename document files**: Shows a **Suggested filename** column in the Review dialog with the LLM proposal. You can edit it before confirming.\n- **Do not categorize document files (only rename)**: Skips text categorization for documents and keeps them in place while applying (optional) renames.\n- **Add document creation date (if available) to category name**: Appends `YYYY-MM` from metadata when available. Disabled when rename-only is enabled.\n\n---\n\n## Audio/video metadata filename suggestions\n\nLet 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.\n\n### Supported audio/video formats\n\n- Audio extensions: `.aac`, `.aif`, `.aiff`, `.alac`, `.ape`, `.flac`, `.m4a`, `.mp3`, `.ogg`, `.oga`, `.opus`, `.wav`, `.wma`\n- Video extensions: `.3gp`, `.avi`, `.flv`, `.m4v`, `.mkv`, `.mov`, `.mp4`, `.mpeg`, `.mpg`, `.mts`, `.m2ts`, `.ts`, `.webm`, `.wmv`\n- 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).\n- When compiled with package-managed `MediaInfoLib`, the same rename flow can also use metadata exposed by MediaInfo for additional supported containers when available.\n\n---\n\n## System compatibility check\n\nThe **System compatibility check** runs a quick benchmark that estimates how well your system can handle:\n\n- **Categorization** with the selected local LLMs\n- **Document analysis** by content\n- **Image analysis** (visual LLM)\n\nYou 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.\n\nWhat it does:\n\n- Detects available CPU threads and GPU backends (e.g., Vulkan/CUDA)\n- Times a small categorization and document-analysis workload per default model\n- Times a single image-analysis pass if visual LLM files are present\n- Reports speed tiers (optimal / acceptable / a bit long) and suggests a recommended local LLM\n\nTip: quit CPU/GPU‑intensive apps before running the check for more accurate results.\n\n---\n\n## Requirements\n\n- **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.\n- **Compiler**: A C++20-capable compiler (`g++` or `clang++` on Linux/macOS, MSVC 2022 on Windows).\n- **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).\n- **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.\n- **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.\n- **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.\n- **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.\n- **Git** (optional): For cloning this repository. Archives can also be downloaded.\n- **OpenAI or Gemini API key** (optional): Required only when using the remote ChatGPT or Gemini workflow.\n\n---\n\n## Installation\n\nFile 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)).\n\n### Linux\n\n#### Prebuilt Debian/Ubuntu package\n\n1. **Install runtime prerequisites** (Qt6, networking, database, math libraries):\n   - Ubuntu 24.04 / Debian 12:\n     ```bash\n     sudo apt update && sudo apt install -y \\\n       libqt6widgets6 libcurl4 libjsoncpp25 libfmt9 libopenblas0-pthread \\\n       libvulkan1 mesa-vulkan-drivers patchelf\n     ```\n   - Debian 13 (trixie):\n     ```bash\n     sudo apt update && sudo apt install -y \\\n       libqt6widgets6 libcurl4t64 libjsoncpp26 libfmt10 libopenblas0-pthread \\\n       libvulkan1 mesa-vulkan-drivers patchelf\n     ```\n   If you build the Vulkan backend from source, install `glslc` (Debian/Ubuntu package: `glslc`; on some distros: `shaderc` or `shaderc-tools`).\n   On Debian 13, use `libjsoncpp26`, `libfmt10`, and `libcurl4t64` (APT may auto-select `libcurl4t64` if `libcurl4` is not available).\n   Ensure that the Qt platform plugins are installed (on Ubuntu 22.04 this is provided by `qt6-wayland`).\n   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.\n2. **Install the package**\n   ```bash\n   sudo apt install ./aifilesorter_*.deb\n   ```\n   Using `apt install` (rather than `dpkg -i`) ensures any missing dependencies listed above are installed automatically.\n\n#### Build from source\n\n1. **Install dependencies**\n   - Debian / Ubuntu:\n    ```bash\n    sudo apt update && sudo apt install -y \\\n      build-essential cmake git qt6-base-dev qt6-base-dev-tools qt6-l10n-tools qt6-tools-dev-tools \\\n      libcurl4-openssl-dev libjsoncpp-dev libsqlite3-dev libssl-dev libfmt-dev libspdlog-dev libmediainfo-dev \\\n      zlib1g-dev\n    ```\n   - Fedora / RHEL:\n\n    ```bash\n    export PATH=\"/usr/lib64/qt6/libexec:$PATH\"\n    sudo dnf install -y gcc-c++ cmake git qt6-qtbase-devel qt6-qttools-devel \\\n      libcurl-devel jsoncpp-devel sqlite-devel openssl-devel fmt-devel spdlog-devel mediainfo-devel\n    ```\n\n   - Arch / Manjaro:\n\n    ```bash\n     sudo pacman -S --needed base-devel git cmake qt6-base qt6-tools curl jsoncpp sqlite openssl fmt spdlog mediainfo\n    ```\n\n     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.\n     MediaInfo is enforced as package-managed only; vendored `MediaInfoLib` folders or repo-local binaries are rejected by the build.\n\n2. **Clone the repository**\n\n   ```bash\n   git clone https://github.com/hyperfield/ai-file-sorter.git\n   cd ai-file-sorter\n   git submodule update --init --recursive\n   ```\n\n   > **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.\n\n3. **Build vendored libzip** (generates `zipconf.h` and `libzip.a`)\n\n   ```bash\n   cmake -S external/libzip -B external/libzip/build \\\n    -DBUILD_SHARED_LIBS=OFF \\\n    -DBUILD_DOC=OFF \\\n    -DENABLE_BZIP2=OFF \\\n    -DENABLE_LZMA=OFF \\\n    -DENABLE_ZSTD=OFF \\\n    -DENABLE_OPENSSL=OFF \\\n    -DENABLE_GNUTLS=OFF \\\n    -DENABLE_MBEDTLS=OFF \\\n    -DENABLE_COMMONCRYPTO=OFF \\\n    -DENABLE_WINDOWS_CRYPTO=OFF\n\n   cmake --build external/libzip/build\n   ```\n\n   On Ubuntu/Debian you will also need the Zlib development headers (`zlib1g-dev`) or\n   the libzip configure step will fail.\n\n   If you prefer system headers instead, install `libzip-dev` and ensure `zipconf.h` is on your include path.\n\n4. **Build the llama runtime variants** (run once per backend you plan to ship/test)\n\n   ```bash\n   # CPU / OpenBLAS\n   ./app/scripts/build_llama_linux.sh cuda=off vulkan=off\n   # CUDA (optional; requires NVIDIA driver + CUDA toolkit)\n   ./app/scripts/build_llama_linux.sh cuda=on vulkan=off\n   # Vulkan (optional; requires a working Vulkan 1.2+ stack and glslc, e.g. mesa-vulkan-drivers + vulkan-tools + glslc)\n   ./app/scripts/build_llama_linux.sh cuda=off vulkan=on\n   ```\n\n   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.\n\n5. **Compile the application**\n\n   ```bash\n   cd app\n   make -j4\n   ```\n\n   The binary is produced at `app/bin/aifilesorter`.\n   The Makefile requires `pkg-config` + package-managed `libmediainfo`; it intentionally rejects vendored MediaInfo copies.\n\n6. **Install system-wide (optional)**\n\n   ```bash\n   sudo make install\n   ```\n\n7. **Build a Debian package (optional)**\n\n   ```bash\n   ./app/scripts/package_deb.sh\n   ```\n\n   The packaging script always bundles the CPU runtime and auto-includes any staged GPU\n   variants already present under `app/lib/precompiled` (for example `vulkan` after\n   `./app/scripts/build_llama_linux.sh cuda=off vulkan=on`). Use\n   `./app/scripts/package_deb.sh --cpu-only` for a smaller CPU-only package, or\n   `--include-vulkan` / `--include-cuda` if you want the script to fail when a specific\n   staged variant is missing.\n\n### macOS\n\n1. **Install Xcode command-line tools** (`xcode-select --install`).\n2. **Install Homebrew** (if required).\n3. **Install dependencies**\n\n   ```bash\n   brew install qt curl jsoncpp sqlite openssl fmt spdlog mediainfo cmake git pkgconfig libffi\n   ```\n\n   Add Qt to your environment if it is not already present:\n\n   ```bash\n   export PATH=\"$(brew --prefix)/opt/qt/bin:$PATH\"\n   export PKG_CONFIG_PATH=\"$(brew --prefix)/lib/pkgconfig:$(brew --prefix)/share/pkgconfig:$PKG_CONFIG_PATH\"\n   ```\n\n4. **Clone the repository and submodules** (same commands as Linux).\n   > 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.\n\n5. **Build vendored libzip** (generates `zipconf.h` and `libzip.a`)\n\n   ```bash\n   cmake -S external/libzip -B external/libzip/build \\\n     -DBUILD_SHARED_LIBS=OFF \\\n     -DBUILD_DOC=OFF \\\n     -DENABLE_BZIP2=OFF \\\n     -DENABLE_LZMA=OFF \\\n     -DENABLE_ZSTD=OFF \\\n     -DENABLE_OPENSSL=OFF \\\n     -DENABLE_GNUTLS=OFF \\\n     -DENABLE_MBEDTLS=OFF \\\n     -DENABLE_COMMONCRYPTO=OFF \\\n     -DENABLE_WINDOWS_CRYPTO=OFF\n   cmake --build external/libzip/build\n   ```\n\n6. **Build the llama runtime (Metal-enabled on Apple Silicon)**\n\n   ```bash\n   ./app/scripts/build_llama_macos.sh\n   ```\n   The macOS app and `.app` bundles use the runtime staged under `app/lib/precompiled*`; they do not need Homebrew `ggml` or `llama.cpp` libraries.\n   If you have older `ggml` / `llama.cpp` copies installed in generic library locations, prefer unlinking or removing them instead of relying on them implicitly.\n7. **Compile the application**\n\n   ```bash\n   cd app\n   make -j8                 # use -jN to control parallelism\n   sudo make install   # optional\n   ```\n\n   The default build places the binary at `app/bin/aifilesorter`.\n\n   **Variant targets:**\n\n   ```bash\n   make -j8 MACOS_LLAMA_M1    # outputs app/bin/m1/aifilesorter\n   make -j8 MACOS_LLAMA_M2    # outputs app/bin/m2/aifilesorter\n   make -j8 MACOS_LLAMA_INTEL # outputs app/bin/intel/aifilesorter\n   ```\n\n   These targets rebuild the llama.cpp runtime before compiling the app.\n   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.\n   `sudo make install` places the macOS runtime libraries under `/usr/local/lib/aifilesorter` to avoid collisions with unrelated system or Homebrew ggml libraries.\n   Each variant uses distinct build directories to avoid cross-arch collisions:\n   - llama.cpp libs: `app/lib/precompiled-m1`, `app/lib/precompiled-m2`, `app/lib/precompiled-intel`\n   - object files: `app/obj/arm64` or `app/obj/x86_64`\n\n### Windows\n\nBuild now targets native MSVC + Qt6 without MSYS2. Two options are supported; the vcpkg route is simplest.\n\nOption A - CMake + vcpkg (recommended)\n\n1. Install prerequisites:\n   - Visual Studio 2022 with Desktop C++ workload\n   - CMake 3.21+ (Visual Studio ships a recent version)\n   - vcpkg: <https://github.com/microsoft/vcpkg> (clone and bootstrap)\n   - package-managed `libmediainfo` via vcpkg manifest (no vendored MediaInfo submodule/binaries)\n   - **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`.\n2. Clone repo and submodules:\n\n   ```powershell\n   git clone https://github.com/hyperfield/ai-file-sorter.git\n   cd ai-file-sorter\n   git submodule update --init --recursive\n   ```\n\n3. **Build vendored libzip** (generates `zipconf.h` and `libzip.lib`)\n\n   Run from the same x64 Native Tools / VS Developer PowerShell you will use to build the app:\n\n   ```powershell\n   cmake -S external\\libzip -B external\\libzip\\build -A x64 `\n     -DBUILD_SHARED_LIBS=OFF `\n     -DBUILD_DOC=OFF `\n     -DENABLE_BZIP2=OFF `\n     -DENABLE_LZMA=OFF `\n     -DENABLE_ZSTD=OFF `\n     -DENABLE_OPENSSL=OFF `\n     -DENABLE_GNUTLS=OFF `\n     -DENABLE_MBEDTLS=OFF `\n     -DENABLE_COMMONCRYPTO=OFF `\n     -DENABLE_WINDOWS_CRYPTO=OFF\n   cmake --build external\\libzip\\build --config Release\n   ```\n\n4. Determine your vcpkg root. It is the folder that contains `vcpkg.exe` (for example `C:\\dev\\vcpkg`).\n    - If `vcpkg` is on your `PATH`, run this command to print the location:\n\n      ```powershell\n      Split-Path -Parent (Get-Command vcpkg).Source\n      ```\n\n    - Otherwise use the directory where you cloned vcpkg.\n\n   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`.\n5. 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):\n\n   ```powershell\n   # CPU / OpenBLAS only\n   app\\scripts\\build_llama_windows.ps1 cuda=off vulkan=off vcpkgroot=C:\\dev\\vcpkg\n   # CUDA (requires matching NVIDIA toolkit/driver)\n   app\\scripts\\build_llama_windows.ps1 cuda=on vulkan=off vcpkgroot=C:\\dev\\vcpkg\n   # Vulkan (requires LunarG Vulkan SDK or vendor Vulkan 1.2+ runtime)\n   app\\scripts\\build_llama_windows.ps1 cuda=off vulkan=on vcpkgroot=C:\\dev\\vcpkg\n   ```\n  \n  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.\n\n6. 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:\n\n   ```powershell\n   # One-time per shell if script execution is blocked:\n   Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass\n\n   app\\build_windows.ps1 -Configuration Release -VcpkgRoot C:\\dev\\vcpkg\n   ```\n\n   - Replace `C:\\dev\\vcpkg` with the path where you cloned vcpkg; it must contain `scripts\\buildsystems\\vcpkg.cmake`.\n   - The helper produces these output directories by default:\n     - Standard installer build with Windows auto-update enabled: `app\\build-windows\\Release`\n     - Microsoft Store build with update checks disabled: `app\\build-windows-store\\Release`\n     - Standalone Windows build with notification-only/manual updates: `app\\build-windows-standalone\\Release`\n   - Use `-Variants Standard`, `-Variants MsStore`, or `-Variants Standalone` to build only a subset.\n   - `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.\n   - `-VcpkgRoot` is optional if `VCPKG_ROOT`/`VPKG_ROOT` is set or `vcpkg`/`vpkg` is on `PATH`.\n   - 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.\n   - 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.\n\nOption B - CMake + Qt online installer\n\n1. Install prerequisites:\n   - Visual Studio 2022 with Desktop C++ workload\n   - Qt 6.x MSVC kit via Qt Online Installer (e.g., Qt 6.6+ with MSVC 2019/2022)\n   - CMake 3.21+\n   - vcpkg (for non-Qt libs): curl, jsoncpp, sqlite3, openssl, fmt, spdlog, gettext, libmediainfo\n2. **Build vendored libzip** (generates `zipconf.h` and `libzip.lib`)\n\n   Run from the same x64 Native Tools / VS Developer PowerShell you will use to build the app:\n\n   ```powershell\n   cmake -S external\\libzip -B external\\libzip\\build -A x64 `\n     -DBUILD_SHARED_LIBS=OFF `\n     -DBUILD_DOC=OFF `\n     -DENABLE_BZIP2=OFF `\n     -DENABLE_LZMA=OFF `\n     -DENABLE_ZSTD=OFF `\n     -DENABLE_OPENSSL=OFF `\n     -DENABLE_GNUTLS=OFF `\n     -DENABLE_MBEDTLS=OFF `\n     -DENABLE_COMMONCRYPTO=OFF `\n     -DENABLE_WINDOWS_CRYPTO=OFF\n   cmake --build external\\libzip\\build --config Release\n   ```\n\n3. Build the bundled `llama.cpp` runtime (same VS shell). Any missing OpenBLAS/cURL packages are installed automatically via vcpkg:\n\n   ```powershell\n   pwsh .\\app\\scripts\\build_llama_windows.ps1 [cuda=on|off] [vulkan=on|off] [vcpkgroot=C:\\dev\\vcpkg]\n   ```\n\n   This is required before configuring the GUI because the build links against the produced `llama` static libraries/DLLs.\n4. 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):\n\n    ```powershell\n    $env:VCPKG_ROOT = \"C:\\path\\to\\vcpkg\"  # e.g. C:\\dev\\vcpkg\n    $qt = \"C:\\Qt\\6.6.3\\msvc2019_64\"  # example\n    cmake -S app -B build -G \"Ninja\" `\n      -DCMAKE_PREFIX_PATH=$qt `\n     -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\\scripts\\buildsystems\\vcpkg.cmake `\n     -DVCPKG_MANIFEST_DIR=app `\n     -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON `\n     -DVCPKG_TARGET_TRIPLET=x64-windows\n   cmake --build build --config Release\n   ```\n\n   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.\n\nNotes\n\n- 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.\n- Runtime DLLs are copied automatically via `windeployqt` after each successful build; skip this step with `-SkipDeploy` if you manage deployment yourself.\n- 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`.\n- 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.\n- `-BuildTests` and `-RunTests` currently build and execute tests only in the `Standard` variant, which is the primary Windows development/CI configuration.\n\n### Running tests\n\nCatch2-based unit tests are optional. Enable them via CMake:\n\n```bash\ncmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON\ncmake --build build-tests --target ai_file_sorter_tests --parallel $(nproc)\nctest --test-dir build-tests --output-on-failure -j $(nproc)\n```\n\nOn macOS, replace `$(nproc)` with `$(sysctl -n hw.ncpu)`.\n\nOn Windows (PowerShell), use:\n\n```powershell\ncmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON\ncmake --build build-tests --target ai_file_sorter_tests --parallel $env:NUMBER_OF_PROCESSORS\nctest --test-dir build-tests --output-on-failure -j $env:NUMBER_OF_PROCESSORS\n```\n\nNotes\n\n- List individual Catch2 cases: `./build-tests/ai_file_sorter_tests --list-tests`\n- Print each case name (including successes): `./build-tests/ai_file_sorter_tests --verbosity high --success`\n\nOn Windows you can pass `-BuildTests` (and `-RunTests` to execute `ctest`) to `app\\build_windows.ps1`:\n\n```powershell\napp\\build_windows.ps1 -Configuration Release -Variants Standard -BuildTests -RunTests\n```\n\nThe current suite (under `tests/unit`) focuses on core utilities; expand it as new functionality gains coverage.\n\n### Selecting a backend at runtime\n\nBoth the Linux launcher (`app/bin/run_aifilesorter.sh` / `aifilesorter-bin`) and the Windows starter accept the following optional flags:\n\n- `--cuda={on|off}` – force-enable or disable the CUDA backend.\n- `--vulkan={on|off}` – force-enable or disable the Vulkan backend.\n\nWhen 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.\n\n#### Vulkan and VRAM notes\n\n- Vulkan is preferred when available; CUDA is used only if Vulkan is missing or explicitly requested.\n- The app auto-estimates `n_gpu_layers` based on available VRAM. Integrated GPUs are capped to 4 GiB for safety, which can limit offloading.\n- 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.\n- Override auto-estimation with `AI_FILE_SORTER_N_GPU_LAYERS` (`-1` auto, `0` force CPU) or `AI_FILE_SORTER_GPU_BACKEND=cpu`.\n- For image analysis, `AI_FILE_SORTER_VISUAL_USE_GPU=0` forces the visual encoder to run on CPU to avoid VRAM allocation errors.\n\n### Environment variables\n\nRuntime and GPU:\n\n- `AI_FILE_SORTER_GPU_BACKEND` - select GPU backend: `auto` (default), `vulkan`, `cuda`, or `cpu`.\n- `AI_FILE_SORTER_N_GPU_LAYERS` - override `n_gpu_layers` for llama.cpp; `-1` = auto, `0` = force CPU.\n- `AI_FILE_SORTER_CTX_TOKENS` - override local LLM context length (default 2048; clamped 512-8192).\n- `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.\n\nVisual LLM:\n\n- `LLAVA_MODEL_URL` - download URL for the visual LLM GGUF model (required to enable image analysis).\n- `LLAVA_MMPROJ_URL` - download URL for the visual LLM mmproj GGUF file (required to enable image analysis).\n- `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.\n\nTimeouts and logging:\n\n- `AI_FILE_SORTER_LOCAL_LLM_TIMEOUT` - seconds to wait for local LLM responses (default 60).\n- `AI_FILE_SORTER_REMOTE_LLM_TIMEOUT` - seconds to wait for OpenAI/Gemini responses (default 10).\n- `AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT` - seconds to wait for custom OpenAI-compatible API responses (default 60).\n- `AI_FILE_SORTER_LLAMA_LOGS` - enable verbose llama.cpp logs (`1`/`true`); also honors `LLAMA_CPP_DEBUG_LOGS`.\n\nStorage and updates:\n\n- `AI_FILE_SORTER_CONFIG_DIR` - override the base config directory (where `config.ini` lives).\n- `CATEGORIZATION_CACHE_FILE` - override the SQLite cache filename inside the config dir.\n- `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.\n- `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.\n- `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`.\n- `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.\n- `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`.\n- `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.\n\nExample update feed:\n\n```json\n{\n  \"update\": {\n    \"current_version\": \"1.7.1\",\n    \"min_version\": \"1.6.0\",\n    \"download_url\": \"https://filesorter.app/download\",\n    \"windows\": {\n      \"current_version\": \"1.7.1\",\n      \"min_version\": \"1.6.0\",\n      \"download_url\": \"https://filesorter.app/download\",\n      \"installer_url\": \"https://filesorter.app/downloads/AIFileSorterSetup-1.7.1.exe\",\n      \"installer_sha256\": \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n    },\n    \"macos\": {\n      \"current_version\": \"1.7.1\",\n      \"min_version\": \"1.6.0\",\n      \"download_url\": \"https://filesorter.app/download\"\n    },\n    \"linux\": {\n      \"current_version\": \"1.7.1\",\n      \"min_version\": \"1.6.0\",\n      \"download_url\": \"https://filesorter.app/download\"\n    }\n  }\n}\n```\n\nCompatibility note:\n\n- 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.\n- Newer app versions prefer the platform-specific streams and will use `update.windows`, `update.macos`, or `update.linux` when present.\n- The legacy compatibility stream can only represent one generic stream, not separate per-platform versions or installers.\n\nWindows-only direct installer updates:\n\n- `installer_url` - direct URL to the Windows installer package.\n- `installer_sha256` - SHA-256 checksum used to verify the downloaded installer before launch.\n- `installer_url` can now also point to a ZIP archive, as long as the archive contains exactly one installer payload (`.exe` or `.msi`).\n- 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`.\n\nWindows updater live-test mode:\n\n- `aifilesorter.exe` accepts the following flags directly on Windows:\n  `--updater-live-test`\n  `--updater-live-test-url=<https://.../AIFileSorterSetup.zip>`\n  `--updater-live-test-sha256=<sha256-of-the-downloaded-package>`\n  `--updater-live-test-version=<optional-version>`\n  `--updater-live-test-min-version=<optional-min-version>`\n- `StartAiFileSorter.exe` accepts and forwards the same flag family if you still use the bootstrapper path.\n- Live-test mode is Windows-only and intentionally bypasses the normal update JSON feed.\n- If the ZIP contains more than one `.exe` or `.msi`, the updater stops instead of guessing which installer to launch.\n- 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.\n- Command-line flags still win over `live-test.ini`, so you can keep a default file and override just one field when needed.\n\nExample `live-test.ini`:\n\n```ini\n[LiveTest]\ndownload_url = https://files.example.com/AIFileSorterSetup-1.7.3.zip\nsha256 = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\ncurrent_version = 1.7.3\nmin_version = 0.0.0\n```\n\nExample PowerShell launch:\n\n```powershell\n.\\aifilesorter.exe `\n  --development `\n  --updater-live-test\n```\n\n---\n\n## Categorization cache database\n\nAI 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.\n\nWhat is stored:\n\n- Directory path, file name, and file type (used as a unique key).\n- Category/subcategory, taxonomy id, categorization style, and timestamp.\n- Suggested filename (for picture and document rename suggestions).\n- Rename-only flag (used when picture/document rename-only modes are enabled).\n- Rename-applied flag (marks when a rename was executed so it is not offered again).\n\nIf 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).\n\n---\n\n## Uninstallation\n\n- **Debian/Ubuntu package installs**: `sudo apt remove aifilesorter`\n- **Linux source installs**: `cd app && sudo make uninstall`\n- **macOS source installs**: `cd app && sudo make uninstall`\n\nFor 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.\n\n---\n\n## Using your OpenAI API key\n\nWant to use ChatGPT instead of the bundled local models? Bring your own OpenAI API key:\n\n1. Open **Settings -> Select LLM** in the app.\n2. 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`).\n3. 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.\n4. An internet connection is only required while this option is selected.\n\n> The app no longer embeds a bundled key; you always provide your own OpenAI key.\n\n---\n\n## Using your Gemini API key\n\nPrefer Google's models? Use your own Gemini API key:\n\n1. Visit **https://aistudio.google.com** and sign in with your Google account.\n2. 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.\n3. 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`).\n4. Click **OK**. The key is stored locally in your AI File Sorter config and reused for future runs. Clear the field to remove it.\n\n> 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.\n> 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.\n\n---\n\n## Testing\n\n- From the repo root, clean any old cache and run the CTest wrapper:\n  \n  ```bash\n  cd app\n  rm -rf ../build-tests      # clear a cache from another checkout\n  ./scripts/rebuild_and_test.sh\n  ```\n\n- The script configures to `../build-tests`, builds, then runs `ctest`.\n- 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.\n\n---\n\n## Diagnostics\n\nIf you need to report a bug or collect troubleshooting data, use the bundled diagnostics scripts:\n\n- **macOS:** `./app/scripts/collect_macos_diagnostics.sh`\n- **Linux:** `./app/scripts/collect_linux_diagnostics.sh`\n- **Windows (PowerShell):** `.\\app\\scripts\\collect_windows_diagnostics.ps1`\n\nEach 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.\n\n---\n\n## How to Use\n\n1. Launch the application (see the last step in [Installation](#installation) according your OS).\n2. Select a directory to analyze.\n\n### Using dry run and undo\n\n- 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.\n- 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).\n\n3. Tick off the checkboxes on the main window according to your preferences.\n4. Click the **\"Analyze\"** button. The app will scan each file and/or directory based on your selected options.\n5. A review dialog will appear. Verify the assigned categories (and subcategories, if enabled in step 3).\n6. 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.\n\n---\n\n## Sorting a Remote Directory (e.g., NAS)\n\nFollow the steps in [How to Use](#how-to-use), but modify **step 2** as follows:  \n\n- **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)).  \n- **Linux & macOS:** Mount the network share to a local folder using a command like:  \n\n  ```sh\n  sudo mount -t cifs //192.168.1.100/shared_folder /mnt/nas -o username=myuser,password=mypass,uid=$(id -u),gid=$(id -g)\n  ```\n\n(Replace 192.168.1.100/shared_folder with your actual network location path and adjust options as needed.)\n\n---\n\n## Contributing\n\n- Fork the repository and submit pull requests.\n- Report issues or suggest features on the GitHub issue tracker.\n- Follow the existing code style and documentation format.\n\n---\n\n## Credits\n\n- Curl: <https://github.com/curl/curl>\n- Dotenv: <https://github.com/motdotla/dotenv>\n- git-scm: <https://git-scm.com>\n- Hugging Face: <https://huggingface.co>\n- JSONCPP: <https://github.com/open-source-parsers/jsoncpp>\n- Llama: <https://www.llama.com>\n- libzip: <https://libzip.org>\n- Local File Organizer <https://github.com/QiuYannnn/Local-File-Organizer>\n- llama.cpp <https://github.com/ggml-org/llama.cpp>\n- MediaInfoLib: <https://mediaarea.net/en/MediaInfo>\n- Mistral AI: <https://mistral.ai>\n- OpenAI: <https://platform.openai.com/docs/overview>\n- OpenSSL: <https://github.com/openssl/openssl>\n- PDFium: <https://pdfium.googlesource.com/pdfium/>\n- Poppler (pdftotext): <https://poppler.freedesktop.org/>\n- pugixml: <https://pugixml.org>\n- Qt: <https://www.qt.io/>\n- spdlog: <https://github.com/gabime/spdlog>\n- unzip (Info-ZIP): <https://infozip.sourceforge.net/>\n\n## License\n\nThis 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.\n\n---\n\n## Donation\n\nSupport the development of **AI File Sorter** and its future features. Every contribution counts!\n\n- **[Donate](https://filesorter.app/donate/)**\n\n---\n"
  },
  {
    "path": "TESTS.md",
    "content": "# Test Suite Guide\n\nThis 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.\n\n## How to run tests\n- Configure tests (once): `cmake -S app -B build-tests -DAI_FILE_SORTER_BUILD_TESTS=ON -DAI_FILE_SORTER_REQUIRE_MEDIAINFOLIB=ON`\n- Build and run all tests: `cmake --build build-tests` then `ctest --test-dir build-tests --output-on-failure -j $(nproc)`\n- Run a single test case by name: `./build-tests/ai_file_sorter_tests \"<test case name or pattern>\"`\n- MediaInfo is expected from a package manager (`apt`/`dnf`/`pacman`/`brew`/`vcpkg`); vendored MediaInfo directories/binaries are intentionally rejected by the build.\n\n## Unit test catalog\n\n### `tests/unit/test_local_llm_backend.cpp` (skipped when `GGML_USE_METAL` is defined)\n\n#### Test case: detect_preferred_backend reads environment\nPurpose: Verify that the backend preference resolver honors the explicit environment override.\nSetup: Set `AI_FILE_SORTER_GPU_BACKEND` to `cuda` via an environment guard.\nProcedure: Call `detect_preferred_backend()` through the test access layer.\nExpected outcome: The detected preference is `Cuda`.\nRun: `./build-tests/ai_file_sorter_tests \"detect_preferred_backend reads environment\"`\n\n#### Test case: CPU backend is honored when forced\nPurpose: Ensure the GPU layer count is forced to CPU when the backend is set to CPU.\nSetup: Create a temporary GGUF model file and set `AI_FILE_SORTER_GPU_BACKEND=cpu`. Ensure no CUDA disable flag or layer override is set.\nProcedure: Call `prepare_model_params_for_testing()` for the temporary model.\nExpected outcome: `n_gpu_layers` is `0`.\nRun: `./build-tests/ai_file_sorter_tests \"CPU backend is honored when forced\"`\n\n#### Test case: CUDA backend can be forced off via GGML_DISABLE_CUDA\nPurpose: Confirm that the global CUDA disable flag overrides a CUDA backend preference.\nSetup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda` and `GGML_DISABLE_CUDA=1`. Inject a probe that reports CUDA available.\nProcedure: Call `prepare_model_params_for_testing()`.\nExpected outcome: `n_gpu_layers` is `0`, indicating CPU fallback.\nRun: `./build-tests/ai_file_sorter_tests \"CUDA backend can be forced off via GGML_DISABLE_CUDA\"`\n\n#### Test case: CUDA override is applied when backend is available\nPurpose: Validate that an explicit layer override is used when CUDA is available.\nSetup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda`, set `AI_FILE_SORTER_N_GPU_LAYERS=7`, and inject a CUDA-available probe.\nProcedure: Call `prepare_model_params_for_testing()`.\nExpected outcome: `n_gpu_layers` equals `7`.\nRun: `./build-tests/ai_file_sorter_tests \"CUDA override is applied when backend is available\"`\n\n#### Test case: CUDA fallback when no GPU is available\nPurpose: Ensure CUDA preference falls back when no GPU is detected.\nSetup: Set `AI_FILE_SORTER_GPU_BACKEND=cuda`, leave layer override unset, and inject a CUDA-unavailable probe.\nProcedure: Call `prepare_model_params_for_testing()`.\nExpected outcome: `n_gpu_layers` is `0` or `-1` (CPU or auto fallback).\nRun: `./build-tests/ai_file_sorter_tests \"CUDA fallback when no GPU is available\"`\n\n#### Test case: Vulkan backend honors explicit override\nPurpose: Check that Vulkan backend respects a specific GPU layer override.\nSetup: Set `AI_FILE_SORTER_GPU_BACKEND=vulkan`, set `AI_FILE_SORTER_N_GPU_LAYERS=12`, and provide a memory probe that returns no data.\nProcedure: Call `prepare_model_params_for_testing()`.\nExpected outcome: `n_gpu_layers` equals `12`.\nRun: `./build-tests/ai_file_sorter_tests \"Vulkan backend honors explicit override\"`\n\n#### Test case: Vulkan backend derives layer count from memory probe\nPurpose: Verify that Vulkan backend derives a sensible layer count from reported GPU memory.\nSetup: Use a model with 48 blocks, set `AI_FILE_SORTER_GPU_BACKEND=vulkan`, and inject a probe reporting a 3 GB discrete GPU.\nProcedure: Call `prepare_model_params_for_testing()`.\nExpected outcome: `n_gpu_layers` is greater than `0` and less than or equal to `48`.\nRun: `./build-tests/ai_file_sorter_tests \"Vulkan backend derives layer count from memory probe\"`\n\n### `tests/unit/test_main_app_image_options.cpp` (non-Windows only)\n\n#### Test case: Image analysis checkboxes enable and enforce rename-only behavior\nPurpose: Ensure the image analysis options enable correctly and enforce the rename-only rule.\nSetup: Create dummy LLaVA model files, configure settings with image analysis and rename options off, and construct `MainApp` with offscreen Qt.\nProcedure: 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\".\nExpected outcome: The option group enables when analysis is checked; enabling rename-only forces offer-rename on; disabling offer-rename clears rename-only.\nRun: `./build-tests/ai_file_sorter_tests \"Image analysis checkboxes enable and enforce rename-only behavior\"`\n\n#### Test case: Image rename-only does not disable categorization unless processing images only\nPurpose: Confirm that rename-only for images does not disable file categorization by itself.\nSetup: Initialize settings with image analysis off and build `MainApp` with offscreen Qt.\nProcedure: Enable image analysis and rename-only, then check whether \"Categorize files\" remains enabled. Next, enable \"Process picture files only\".\nExpected outcome: Categorization remains enabled with rename-only, but becomes disabled when processing images only.\nRun: `./build-tests/ai_file_sorter_tests \"Image rename-only does not disable categorization unless processing images only\"`\n\n#### Test case: Document rename-only does not disable categorization unless processing documents only\nPurpose: Mirror the image-only behavior for documents.\nSetup: Initialize settings with document analysis off and build `MainApp` with offscreen Qt.\nProcedure: Enable document analysis and rename-only, then check whether \"Categorize files\" remains enabled. Next, enable \"Process document files only\".\nExpected outcome: Categorization remains enabled with rename-only, but becomes disabled when processing documents only.\nRun: `./build-tests/ai_file_sorter_tests \"Document rename-only does not disable categorization unless processing documents only\"`\n\n#### Test case: Document analysis ignores other files when categorize files is off\nPurpose: Verify the entry splitter respects the \"categorize files\" flag when only document analysis is active.\nSetup: Prepare a mixed list of image, document, other file, and a directory entry. Set all flags to analyze documents only and categorize files off.\nProcedure: Call `split_entries_for_analysis()` and inspect the output buckets.\nExpected outcome: Document entries are analyzed, other non-document files are excluded, and directories are still included in the \"other\" bucket.\nRun: `./build-tests/ai_file_sorter_tests \"Document analysis ignores other files when categorize files is off\"`\n\n#### Test case: Image analysis toggle disables when dialog closes without downloads\nPurpose: Ensure the analysis checkbox reverts if the required visual models are not available.\nSetup: Configure settings with image analysis off and inject probes that simulate missing visual models and a prompt acceptance.\nProcedure: Toggle the image analysis checkbox on.\nExpected outcome: The checkbox reverts to unchecked and settings remain unchanged.\nRun: `./build-tests/ai_file_sorter_tests \"Image analysis toggle disables when dialog closes without downloads\"`\n\n#### Test case: Image analysis toggle cancels when user declines download\nPurpose: Verify that declining the download prompt cancels enabling image analysis.\nSetup: Configure settings with image analysis off and inject probes that simulate missing visual models and prompt rejection.\nProcedure: Toggle the image analysis checkbox on.\nExpected outcome: The checkbox remains unchecked, settings remain unchanged, and no download dialog is launched.\nRun: `./build-tests/ai_file_sorter_tests \"Image analysis toggle cancels when user declines download\"`\n\n#### Test case: Already-renamed images skip vision analysis\nPurpose: Confirm that images already renamed are handled without re-analysis.\nSetup: Provide image entries where one is already renamed and a rename-only flag can be toggled.\nProcedure: Run `split_entries_for_analysis()` in two sections: (a) normal categorization and (b) rename-only enabled.\nExpected 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.\nRun: `./build-tests/ai_file_sorter_tests \"Already-renamed images skip vision analysis\"`\n\n### `tests/unit/test_ui_translator.cpp` (non-Windows only)\n\n#### Test case: UiTranslator updates menus, actions, and controls\nPurpose: Validate that the UI translator updates all primary controls, menus, and stateful labels in a consistent pass.\nSetup: 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.\nProcedure: 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.\nExpected outcome: All UI elements show the expected English strings and the French language action is marked checked, demonstrating the retranslate pipeline is correctly wired.\nRun: `./build-tests/ai_file_sorter_tests \"*UiTranslator updates menus*\"`\n\n### `tests/unit/test_utils.cpp`\n\n#### Test case: get_file_name_from_url extracts filename\nPurpose: Ensure URL filename extraction returns the last path component.\nSetup: Use a URL ending with a file name.\nProcedure: Call `Utils::get_file_name_from_url()`.\nExpected outcome: The returned string equals the file name (e.g., `mistral-7b.gguf`).\nRun: `./build-tests/ai_file_sorter_tests \"get_file_name_from_url extracts filename\"`\n\n#### Test case: get_file_name_from_url rejects malformed input\nPurpose: Confirm invalid URLs are rejected.\nSetup: Use a URL with no filename component.\nProcedure: Call `Utils::get_file_name_from_url()` and expect an exception.\nExpected outcome: A `std::runtime_error` is thrown.\nRun: `./build-tests/ai_file_sorter_tests \"get_file_name_from_url rejects malformed input\"`\n\n#### Test case: is_cuda_available honors probe overrides\nPurpose: Verify that CUDA availability probes are honored.\nSetup: Install a test hook that returns `true`, then one that returns `false`.\nProcedure: Call `Utils::is_cuda_available()` after each probe.\nExpected outcome: The function returns `true` and then `false`, matching the probe.\nRun: `./build-tests/ai_file_sorter_tests \"is_cuda_available honors probe overrides\"`\n\n#### Test case: abbreviate_user_path strips home prefix\nPurpose: Ensure user paths are shortened relative to `HOME`.\nSetup: Create a temporary home directory, set `HOME`, and create a file inside `Documents/`.\nProcedure: Call `Utils::abbreviate_user_path()` on the full path.\nExpected outcome: The returned string omits the home prefix and begins with `Documents/`.\nRun: `./build-tests/ai_file_sorter_tests \"abbreviate_user_path strips home prefix\"`\n\n#### Test case: sanitize_path_label strips invalid UTF-8 bytes\nPurpose: Ensure path labels remain valid UTF-8 even when upstream text contains malformed byte sequences.\nSetup: Build a string containing an invalid UTF-8 byte between otherwise valid ASCII text.\nProcedure: Call `Utils::sanitize_path_label()`.\nExpected outcome: The invalid byte is removed and the returned label remains valid UTF-8 text.\nRun: `./build-tests/ai_file_sorter_tests \"sanitize_path_label strips invalid UTF-8 bytes\"`\n\n### `tests/unit/test_llm_selection_dialog_visual.cpp` (non-Windows only)\n\n#### Test case: Visual LLaVA entry shows missing env var state\nPurpose: Confirm UI indicates missing LLaVA download URLs.\nSetup: Clear `LLAVA_MODEL_URL` and `LLAVA_MMPROJ_URL` and construct the dialog.\nProcedure: Fetch the LLaVA entry via test access.\nExpected outcome: The status label reports the missing environment variable and the download button is disabled.\nRun: `./build-tests/ai_file_sorter_tests \"Visual LLaVA entry shows missing env var state\"`\n\n#### Test case: Visual LLaVA entry shows resume state for partial downloads\nPurpose: Validate resume state for partial LLaVA downloads.\nSetup: Create a fake source file and a smaller destination file, inject metadata headers with an expected size.\nProcedure: Update the LLaVA entry state.\nExpected outcome: The status label indicates a partial download and the download button changes to \"Resume download\" and is enabled.\nRun: `./build-tests/ai_file_sorter_tests \"Visual LLaVA entry shows resume state for partial downloads\"`\n\n#### Test case: Visual LLaVA entry reports download errors\nPurpose: Ensure download failures are surfaced in the UI.\nSetup: Inject a network-available override and a download probe that returns a CURL connection error.\nProcedure: Start the LLaVA model download and wait for the label to update.\nExpected outcome: The status label begins with \"Download error:\" indicating the failure is shown to the user.\nRun: `./build-tests/ai_file_sorter_tests \"Visual LLaVA entry reports download errors\"`\n\n### `tests/unit/test_settings_image_options.cpp`\n\n#### Test case: Settings defaults image analysis off even when visual LLM files exist\nPurpose: Verify that image analysis defaults remain off when no settings file exists, even if model files are present.\nSetup: Create dummy LLaVA model files in the expected location and load settings from an empty config directory.\nProcedure: Call `Settings::load()` and read the image analysis flags.\nExpected outcome: `load()` returns false, and both analyze and offer-rename flags are false.\nRun: `./build-tests/ai_file_sorter_tests \"Settings defaults image analysis off even when visual LLM files exist\"`\n\n#### Test case: Settings defaults image analysis off when visual LLM files are missing\nPurpose: Verify default settings are still off when model files are absent.\nSetup: Use a fresh config directory with no LLaVA files.\nProcedure: Call `Settings::load()` and read image analysis flags.\nExpected outcome: `load()` returns false and analysis/offer-rename remain disabled.\nRun: `./build-tests/ai_file_sorter_tests \"Settings defaults image analysis off when visual LLM files are missing\"`\n\n#### Test case: Settings enforces rename-only implies offer rename\nPurpose: Ensure rename-only cannot be enabled without offer-rename.\nSetup: Save settings with analyze on, offer-rename off, and rename-only on.\nProcedure: Reload settings from disk.\nExpected outcome: Offer-rename is forced on while rename-only and process-only settings persist.\nRun: `./build-tests/ai_file_sorter_tests \"Settings enforces rename-only implies offer rename\"`\n\n#### Test case: Settings persists options group expansion state\nPurpose: Ensure the image/document option group expansion states persist across load/save.\nSetup: Use a temporary config directory and set expanded flags for image and document groups.\nProcedure: Save settings, reload into a new `Settings` instance, and read the flags.\nExpected outcome: The expansion flags match the saved values.\nRun: `./build-tests/ai_file_sorter_tests \"Settings persists options group expansion state\"`\n\n### `tests/unit/test_checkbox_matrix.cpp`\n\n#### Test case: Checkbox combinations route entries without renamed files\nPurpose: Exhaustively validate the file-routing logic for every combination of checkbox flags.\nSetup: Define a fixed sample set containing an image, a document, an other file, and a directory. Use an empty set of renamed files.\nProcedure: Iterate all 128 combinations of analysis and filtering flags, call `split_entries_for_analysis()`, and compute the expected bucket for each entry.\nExpected 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.\nRun: `./build-tests/ai_file_sorter_tests \"Checkbox combinations route entries without renamed files\"`\n\n#### Test case: Checkbox combinations route entries with renamed files\nPurpose: Validate routing when image and document entries have already been renamed.\nSetup: Use the same sample set but mark the image and document names as already renamed.\nProcedure: Repeat the 128-combination sweep and compare actual buckets to expected behavior for rename-only and categorization scenarios.\nExpected 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.\nRun: `./build-tests/ai_file_sorter_tests \"Checkbox combinations route entries with renamed files\"`\n\n### `tests/unit/test_llm_downloader.cpp`\n\n#### Test case: LLMDownloader retries full download after a range error\nPurpose: Ensure a failed resume attempt triggers a full restart.\nSetup: 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.\nProcedure: Start the download and wait for completion.\nExpected outcome: Two attempts are recorded, the second starts from offset 0, the final file size matches the expected size, and no error is reported.\nRun: `./build-tests/ai_file_sorter_tests \"LLMDownloader retries full download after a range error\"`\n\n#### Test case: LLMDownloader uses cached metadata for partial downloads\nPurpose: Validate that cached metadata drives download status.\nSetup: Create a partial local file and an `.aifs.meta` file with the expected content length.\nProcedure: Construct the downloader and query its status.\nExpected outcome: Both local and overall download status report `InProgress`, content length is read from metadata, and the downloader is not yet initialized.\nRun: `./build-tests/ai_file_sorter_tests \"LLMDownloader uses cached metadata for partial downloads\"`\n\n#### Test case: LLMDownloader resets to not started when local file is missing\nPurpose: Ensure metadata alone does not imply a partial download.\nSetup: Create metadata without the local file.\nProcedure: Construct the downloader and query its status.\nExpected outcome: The status is `NotStarted` for both local and overall views.\nRun: `./build-tests/ai_file_sorter_tests \"LLMDownloader resets to not started when local file is missing\"`\n\n#### Test case: LLMDownloader treats full local file as complete with cached metadata\nPurpose: Confirm that a complete local file is recognized as complete.\nSetup: Create a local file whose size matches the cached content length.\nProcedure: Construct the downloader and query its status.\nExpected outcome: Both local and overall download status report `Complete`.\nRun: `./build-tests/ai_file_sorter_tests \"LLMDownloader treats full local file as complete with cached metadata\"`\n\n### `tests/unit/test_update_feed.cpp`\n\n#### Test case: UpdateFeed selects the correct platform stream\nPurpose: Ensure the updater resolves the correct platform-specific stream from the shared feed.\nSetup: Build a feed JSON payload with distinct `windows`, `macos`, and `linux` entries.\nProcedure: Parse the feed for each platform enum.\nExpected outcome: Each platform receives its own version and URLs, and the Windows installer checksum is normalized.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateFeed selects the correct platform stream\"`\n\n#### Test case: UpdateFeed falls back to the legacy single-stream schema\nPurpose: Preserve compatibility with existing single-stream feeds.\nSetup: Build a feed JSON payload with the original flat `update` object.\nProcedure: Parse the feed for a platform.\nExpected outcome: The legacy fields are still accepted and returned as update info.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateFeed falls back to the legacy single-stream schema\"`\n\n#### Test case: UpdateInstaller downloads, verifies, and reuses a cached installer\nPurpose: Validate the Windows-style installer preparation flow without network access.\nSetup: Inject a fake installer download callback and a fake launch callback.\nProcedure: Prepare the installer twice and then launch it.\nExpected outcome: The first prepare downloads and verifies the installer, the second reuses the cached artifact, and the launch callback receives the finalized path.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller downloads, verifies, and reuses a cached installer\"`\n\n#### Test case: UpdateInstaller rejects installers that fail SHA-256 verification\nPurpose: Ensure invalid installer downloads are rejected before launch.\nSetup: Inject a fake download callback that writes mismatched bytes.\nProcedure: Prepare the installer with an expected SHA-256 that does not match.\nExpected outcome: Preparation fails and no finalized installer path is returned.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller rejects installers that fail SHA-256 verification\"`\n\n#### Test case: UpdateInstaller redownloads cached installers that fail verification\nPurpose: Ensure corrupted cached installers are not reused silently.\nSetup: Prepare a valid cached installer, then overwrite it with different bytes.\nProcedure: Prepare the installer a second time with the same expected SHA-256.\nExpected outcome: The cached file is rejected, a new download occurs, and the finalized installer contents match the expected payload.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller redownloads cached installers that fail verification\"`\n\n#### Test case: UpdateInstaller reports canceled downloads and removes partial files\nPurpose: Confirm cancelation produces a canceled result instead of a generic failure and cleans up partial output.\nSetup: Inject a fake download callback that writes a partial file and then throws the installer cancelation exception when the cancel probe is true.\nProcedure: Call `prepare()` with a cancel probe that always returns true.\nExpected outcome: Preparation returns `Canceled`, no finalized installer path is returned, and the partial `.part` file is removed.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller reports canceled downloads and removes partial files\"`\n\n#### Test case: UpdateInstaller requires installer metadata before preparing\nPurpose: Reject malformed update feeds that omit required direct-installer fields.\nSetup: Create update info once without `installer_url` and once without `installer_sha256`.\nProcedure: Call `prepare()` for both cases.\nExpected outcome: Both calls fail with messages indicating the missing field.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller requires installer metadata before preparing\"`\n\n#### Test case: UpdateInstaller builds launch requests for EXE and MSI installers\nPurpose: Verify the installer launch plan uses direct execution for `.exe` files and `msiexec /i` for `.msi` packages.\nSetup: Build launch requests for representative `.exe` and `.MSI` paths.\nProcedure: Query the test access helper for both inputs.\nExpected outcome: The `.exe` request launches the installer directly with no extra arguments, while the `.msi` request targets `msiexec.exe` with `/i <path>`.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller builds launch requests for EXE and MSI installers\"`\n\n#### Test case: UpdateInstaller auto-install support remains Windows-only\nPurpose: Confirm the direct-installer flow is currently gated to Windows builds.\nSetup: Create update info with installer metadata.\nProcedure: Query the updater installer support state.\nExpected outcome: Windows builds report support; other platforms do not.\nRun: `./build-tests/ai_file_sorter_tests \"UpdateInstaller auto-install support remains Windows-only\"`\n\n### `tests/unit/test_updater.cpp`\n\n#### Test case: Updater error dialog offers manual update fallback without quitting when not requested\nPurpose: Verify installer-preparation failures still let the user open the normal download page manually for optional updates.\nSetup: Construct an updater with test handlers for opening the download URL and quitting the app, and schedule the error dialog to click `Update manually`.\nProcedure: Invoke the updater error handler with a `download_url` and `quit_after_open=false`.\nExpected outcome: The dialog includes `Update manually`, the download URL handler is called, and the quit handler is not called.\nRun: `./build-tests/ai_file_sorter_tests \"Updater error dialog offers manual update fallback without quitting when not requested\"`\n\n#### Test case: Updater error dialog can request quit after manual fallback\nPurpose: Ensure required-update failures can still fall back to the manual download link and then close the app.\nSetup: Construct an updater with test handlers and schedule the error dialog to click `Update manually`.\nProcedure: Invoke the updater error handler with a `download_url` and `quit_after_open=true`.\nExpected outcome: The manual download handler is called and the quit handler is triggered.\nRun: `./build-tests/ai_file_sorter_tests \"Updater error dialog can request quit after manual fallback\"`\n\n#### Test case: Updater error dialog omits manual fallback when no download URL is available\nPurpose: Confirm the fallback button is only offered when a manual download link exists.\nSetup: Construct an updater with test handlers and invoke the error dialog without a `download_url`.\nProcedure: Attempt to click `Update manually`; the helper falls back to `OK` when the button is absent.\nExpected outcome: No manual fallback button is present, the error handler returns `false`, and neither the download nor quit handler runs.\nRun: `./build-tests/ai_file_sorter_tests \"Updater error dialog omits manual fallback when no download URL is available\"`\n\n### `tests/unit/test_review_dialog_rename_gate.cpp` (non-Windows only)\n\n#### Test case: Review dialog rename-only toggles disabled when renames are not allowed\nPurpose: Verify the review dialog respects the \"Offer to rename\" gating for images and documents.\nSetup: Build a dialog with sample image and document entries and auto-close it using a timer.\nProcedure: Show results once with image/document renames disallowed, then again with renames allowed.\nExpected outcome: The rename-only checkboxes are disabled in the first case and enabled in the second.\nRun: `./build-tests/ai_file_sorter_tests \"Review dialog rename-only toggles disabled when renames are not allowed\"`\n\n### `tests/unit/test_custom_llm.cpp`\n\n#### Test case: Custom LLM entries persist across Settings load/save\nPurpose: Ensure custom LLM definitions persist correctly.\nSetup: Insert a custom LLM entry and set it as active, then save settings.\nProcedure: Reload settings and retrieve the custom LLM by ID.\nExpected outcome: The reloaded entry matches the original fields and the active ID is preserved.\nRun: `./build-tests/ai_file_sorter_tests \"Custom LLM entries persist across Settings load/save\"`\n\n### `tests/unit/test_database_manager_rename_only.cpp`\n\n#### Test case: DatabaseManager keeps rename-only entries with empty labels\nPurpose: Ensure rename-only entries are not removed when categories are empty.\nSetup: Insert one rename-only entry with a suggested name and one empty entry with no rename suggestion.\nProcedure: Call `remove_empty_categorizations()` and then fetch categorized files.\nExpected outcome: Only the truly empty entry is removed; the rename-only entry remains with empty category labels and the suggestion intact.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager keeps rename-only entries with empty labels\"`\n\n#### Test case: DatabaseManager sanitizes invalid UTF-8 in cached labels\nPurpose: Ensure malformed UTF-8 in cached category labels or suggestions does not propagate into the review dialog pipeline.\nSetup: Insert a cached entry whose category, subcategory, and suggested filename contain invalid UTF-8 bytes.\nProcedure: Fetch categorized files from the database.\nExpected outcome: The loaded category, subcategory, and suggested name are returned with invalid UTF-8 bytes removed.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager sanitizes invalid UTF-8 in cached labels\"`\n\n#### Test case: DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching\nPurpose: Verify taxonomy resolution normalizes stopword suffixes like \"files\".\nSetup: Resolve categories with and without the \"files\" suffix (e.g., \"Graphics\" vs \"Graphics files\").\nProcedure: Compare the resolved taxonomy IDs and labels.\nExpected outcome: Both resolutions share the same taxonomy ID and normalized labels, while unrelated subcategories (e.g., \"Photos\") remain unchanged.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching\"`\n\n#### Test case: DatabaseManager normalizes backup category synonyms for taxonomy matching\nPurpose: Ensure backup/archive category variants collapse to a single canonical taxonomy entry.\nSetup: Resolve `Archives` and `backup files` with the same subcategory.\nProcedure: Compare taxonomy IDs and canonical labels.\nExpected outcome: Both labels map to the same taxonomy entry with canonical category `Archives`.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager normalizes backup category synonyms for taxonomy matching\"`\n\n#### Test case: DatabaseManager normalizes image category synonyms and image media aliases\nPurpose: Ensure image-related category variants collapse while non-image media remains distinct.\nSetup: Resolve `Images`, `Graphics`, `Media + Photos`, and `Media + Audio`.\nProcedure: Compare taxonomy IDs and canonical labels.\nExpected outcome: `Images/Graphics/Media+Photos` share taxonomy and canonicalize to `Images`; `Media+Audio` remains `Media`.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager normalizes image category synonyms and image media aliases\"`\n\n#### Test case: DatabaseManager normalizes document category synonyms for taxonomy matching\nPurpose: Ensure document-like category variants collapse to `Documents`.\nSetup: Resolve `Documents`, `Texts`, `Papers`, and `Spreadsheets` with the same subcategory.\nProcedure: Compare taxonomy IDs and canonical labels.\nExpected outcome: All variants map to the same taxonomy entry with canonical category `Documents`.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager normalizes document category synonyms for taxonomy matching\"`\n\n#### Test case: DatabaseManager normalizes installer and update category synonyms for taxonomy matching\nPurpose: Ensure software/install/update category variants collapse to `Software`.\nSetup: Resolve `Software`, `Installers`, `Setup files`, `Software Update`, and `Patches`.\nProcedure: Compare taxonomy IDs and canonical labels.\nExpected outcome: All variants map to the same taxonomy entry with canonical category `Software`.\nRun: `./build-tests/ai_file_sorter_tests \"DatabaseManager normalizes installer and update category synonyms for taxonomy matching\"`\n\n### `tests/unit/test_file_scanner.cpp`\n\n#### Test case: hidden files require explicit flag\nPurpose: Ensure hidden files are filtered unless explicitly requested.\nSetup: Create a hidden file in a temporary directory.\nProcedure: Scan with only `Files`, then with `Files | HiddenFiles`.\nExpected outcome: The hidden file is absent in the first scan and present in the second.\nRun: `./build-tests/ai_file_sorter_tests \"hidden files require explicit flag\"`\n\n#### Test case: junk files are skipped regardless of flags\nPurpose: Confirm that known junk files are always excluded.\nSetup: Create a `.DS_Store` file.\nProcedure: Scan with `Files | HiddenFiles`.\nExpected outcome: The junk file does not appear in the results.\nRun: `./build-tests/ai_file_sorter_tests \"junk files are skipped regardless of flags\"`\n\n#### Test case: application bundles are treated as files\nPurpose: Ensure application bundles are treated as files rather than directories.\nSetup: Create a `Sample.app` directory with a `Contents` subdirectory.\nProcedure: Scan once for files and once for directories.\nExpected outcome: The bundle appears only in the file scan and not in the directory scan.\nRun: `./build-tests/ai_file_sorter_tests \"application bundles are treated as files\"`\n\n#### Test case: recursive scans include nested files\nPurpose: Ensure recursive scans still return files from nested subdirectories.\nSetup: Create one file in the root and one file in a nested subdirectory.\nProcedure: Scan with `Files | Recursive`.\nExpected outcome: Both files appear in the results.\nRun: `./build-tests/ai_file_sorter_tests \"recursive scans include nested files\"`\n\n#### Test case: recursive scans skip unreadable directories and continue\nPurpose: Ensure one inaccessible subdirectory does not abort an otherwise valid recursive scan.\nSetup: Create a readable subtree and a second subtree whose directory permissions are removed (non-Windows only).\nProcedure: Scan with `Files | Recursive`.\nExpected outcome: The readable file is returned, the scan does not throw, and the unreadable subtree is skipped.\nRun: `./build-tests/ai_file_sorter_tests \"recursive scans skip unreadable directories and continue\"`\n\n### `tests/unit/test_support_prompt.cpp`\n\n#### Test case: Support prompt thresholds advance based on response\nPurpose: Verify support prompt scheduling logic under different user responses.\nSetup: Create a fresh settings environment and define a callback that returns a simulated response (`NotSure`, `CannotDonate`, or `Support`).\nProcedure: Increment the categorized file count to the current threshold, observe the prompt, then advance to the next threshold.\nExpected outcome: The prompt fires exactly at thresholds, the total count increments correctly, and the next threshold increases for all response types.\nRun: `./build-tests/ai_file_sorter_tests \"Support prompt thresholds advance based on response\"`\n\n#### Test case: Zero categorized increments do not change totals or trigger prompts\nPurpose: Ensure a zero increment is a no-op.\nSetup: Fresh settings with a baseline threshold.\nProcedure: Call the prompt simulation with an increment of `0`.\nExpected outcome: Total counts and thresholds remain unchanged and the callback is not invoked.\nRun: `./build-tests/ai_file_sorter_tests \"Zero categorized increments do not change totals or trigger prompts\"`\n\n### `tests/unit/test_custom_api_endpoint.cpp`\n\n#### Test case: Custom API endpoints persist across Settings load/save\nPurpose: Ensure custom OpenAI-compatible endpoint definitions persist correctly.\nSetup: Create a custom endpoint with name, description, base URL, API key, and model, then set it active and save.\nProcedure: Reload settings and retrieve the endpoint by ID.\nExpected outcome: All fields match the original, and the active endpoint ID is preserved.\nRun: `./build-tests/ai_file_sorter_tests \"Custom API endpoints persist across Settings load/save\"`\n\n### `tests/unit/test_categorization_dialog.cpp` (non-Windows only)\n\n#### Test case: CategorizationDialog uses subcategory toggle when moving files\nPurpose: Ensure the dialog respects the subcategory visibility toggle during file moves.\nSetup: Create a sample categorized file and attach a move probe.\nProcedure: Toggle the subcategory column state and confirm the dialog.\nExpected outcome: The move probe records the same subcategory setting that was applied.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog uses subcategory toggle when moving files\"`\n\n#### Test case: CategorizationDialog supports sorting by columns\nPurpose: Verify that the table model sorts correctly by different columns.\nSetup: Insert two entries with out-of-order file names and categories.\nProcedure: Sort by the file name column ascending, then by category descending.\nExpected outcome: The first sort yields alphabetical file names; the second yields categories in reverse alphabetical order.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog supports sorting by columns\"`\n\n#### Test case: CategorizationDialog undo restores moved files\nPurpose: Confirm that undo reverses category moves.\nSetup: Create a file on disk with a category and subcategory.\nProcedure: Confirm the dialog to move the file, then trigger undo.\nExpected outcome: The file moves to the category path, then returns to the original location; undo is enabled only when a move exists.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog undo restores moved files\"`\n\n#### Test case: CategorizationDialog undo allows renaming again\nPurpose: Ensure undo resets rename-only operations and allows reapplication.\nSetup: Create a rename-only entry with a suggested name.\nProcedure: Confirm the rename, undo it, and confirm again.\nExpected outcome: Each confirm applies the rename, and undo restores the original filename for a second rename.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog undo allows renaming again\"`\n\n#### Test case: CategorizationDialog rename-only updates cached filename\nPurpose: Verify database updates when a rename-only action occurs.\nSetup: Use a dialog with a database manager and a rename-only file with a suggestion.\nProcedure: Confirm the dialog and query the database.\nExpected outcome: The old name is not cached; the new name is cached with rename-only metadata and the suggested name.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog rename-only updates cached filename\"`\n\n#### Test case: CategorizationDialog allows editing when rename-only checkbox is off\nPurpose: Ensure category fields remain editable when rename-only mode is not enforced.\nSetup: Populate the dialog with one rename-only entry and one categorized entry.\nProcedure: Inspect the category column editability in the model.\nExpected outcome: Both rows remain editable in the category column.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog allows editing when rename-only checkbox is off\"`\n\n#### Test case: CategorizationDialog deduplicates suggested names when rename-only is toggled\nPurpose: Ensure duplicate suggestions are made unique when rename-only is turned on.\nSetup: Provide two image entries with identical suggested names.\nProcedure: Toggle the rename-only checkbox in the dialog.\nExpected outcome: The suggestions are rewritten with numbered suffixes (e.g., `_1`, `_2`).\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog deduplicates suggested names when rename-only is toggled\"`\n\n#### Test case: CategorizationDialog avoids double suffixes for numbered suggestions\nPurpose: Prevent double-numbering when suggestions already contain a suffix.\nSetup: Use two rename-only entries with a suggestion ending in `_1`.\nProcedure: Populate the dialog and read back the suggested names.\nExpected outcome: The first remains `_1`, and the second becomes `_2` without duplicating the suffix.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog avoids double suffixes for numbered suggestions\"`\n\n#### Test case: CategorizationDialog hides suggested names for renamed entries\nPurpose: Hide rename suggestions once the rename has already been applied.\nSetup: Create an entry with `rename_applied=true` and a suggested name.\nProcedure: Populate the dialog and inspect the suggested name cell.\nExpected outcome: The suggested name cell is empty and not editable.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog hides suggested names for renamed entries\"`\n\n#### Test case: CategorizationDialog hides already renamed rows when rename-only is on\nPurpose: Ensure completed renames are hidden when only renaming is requested.\nSetup: Add one renamed entry and one pending entry, then enable the rename-only checkbox.\nProcedure: Toggle rename-only and inspect row visibility.\nExpected outcome: The already renamed row becomes hidden while the pending row remains visible.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog hides already renamed rows when rename-only is on\"`\n\n#### Test case: CategorizationDialog deduplicates suggested picture filenames\nPurpose: Ensure image rename suggestions are unique across multiple rows.\nSetup: Provide two rename-only image entries with identical suggested names.\nProcedure: Populate the dialog and read the suggested names.\nExpected outcome: Suggestions become `_1` and `_2` variants to avoid collisions.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog deduplicates suggested picture filenames\"`\n\n#### Test case: CategorizationDialog avoids existing picture filename collisions\nPurpose: Ensure suggested names do not collide with existing files on disk.\nSetup: Create a file on disk that matches the suggested name and add a rename-only entry with that suggestion.\nProcedure: Populate the dialog and inspect the suggestion.\nExpected outcome: The suggestion is incremented (e.g., `_1`) to avoid the existing file.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog avoids existing picture filename collisions\"`\n\n#### Test case: CategorizationDialog rename-only preserves cached categories without renaming\nPurpose: Ensure rename-only mode keeps existing category assignments even when no rename occurs.\nSetup: Cache a categorization in the database, then run the dialog with a rename-only entry that has no suggested name.\nProcedure: Confirm the dialog and query the cache.\nExpected outcome: The cached category and subcategory are preserved and the entry remains marked rename-only.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog rename-only preserves cached categories without renaming\"`\n\n#### Test case: CategorizationDialog rename-only preserves cached categories when renaming\nPurpose: Ensure rename-only mode keeps cached categories after a rename.\nSetup: Cache a categorization, then run the dialog with a rename-only entry that includes a suggested name.\nProcedure: Confirm the dialog and query the cache for the renamed file.\nExpected outcome: The renamed entry retains the cached category and subcategory with rename-only metadata.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationDialog rename-only preserves cached categories when renaming\"`\n\n### `tests/unit/test_main_app_translation.cpp` (non-Windows only)\n\n#### Test case: MainApp retranslate reflects language changes\nPurpose: Validate that main window labels update for all supported UI languages.\nSetup: Construct `MainApp` with a settings object and a translation manager.\nProcedure: Iterate through supported languages, set the language, trigger a retranslate, and read the analyze button and folder label text.\nExpected outcome: Each language produces the exact expected translations for the two labels.\nRun: `./build-tests/ai_file_sorter_tests \"MainApp retranslate reflects language changes\"`\n\n### `tests/unit/test_whitelist_and_prompt.cpp`\n\n#### Test case: WhitelistStore initializes from settings and persists defaults\nPurpose: Ensure whitelist entries are loaded into settings and persisted.\nSetup: Create a whitelist entry, save it, and initialize the store from settings with a selected whitelist name.\nProcedure: Verify the settings fields and reload the whitelist store from disk.\nExpected outcome: The whitelist name, categories, and subcategories remain consistent across initialization and reload.\nRun: `./build-tests/ai_file_sorter_tests \"WhitelistStore initializes from settings and persists defaults\"`\n\n#### Test case: CategorizationService builds numbered whitelist context\nPurpose: Confirm the whitelist context includes numbered categories and an \"any\" subcategory fallback.\nSetup: Set allowed categories in settings and build a service instance.\nProcedure: Call the test access method to build the whitelist context string.\nExpected outcome: The context includes numbered category lines and indicates that subcategories are unrestricted.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService builds numbered whitelist context\"`\n\n#### Test case: CategorizationService builds category language context when non-English selected\nPurpose: Ensure the category language context is generated for non-English settings.\nSetup: Set the category language to French.\nProcedure: Build the category language context string.\nExpected outcome: The context is non-empty and references \"French\".\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService builds category language context when non-English selected\"`\n\n#### Test case: CategorizationService builds category language context for Spanish\nPurpose: Verify Spanish category language is handled explicitly.\nSetup: Set the category language to Spanish.\nProcedure: Build the category language context string.\nExpected outcome: The context is non-empty and references \"Spanish\".\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService builds category language context for Spanish\"`\n\n#### Test case: CategorizationService parses category output without spaced colon delimiters\nPurpose: Ensure category parsing accepts compact `Category:Subcategory` output.\nSetup: Use a fixed LLM stub response `Documents:Spreadsheets`.\nProcedure: Run `categorize_entries` for one file entry.\nExpected outcome: Parsed category is `Documents` and parsed subcategory is `Spreadsheets`.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService parses category output without spaced colon delimiters\"`\n\n#### Test case: CategorizationService parses labeled category and subcategory lines\nPurpose: Ensure category parsing accepts labeled multiline output.\nSetup: Use a fixed LLM stub response with `Category: ...` and `Subcategory: ...` lines.\nProcedure: Run `categorize_entries` for one file entry.\nExpected outcome: Parsed labels match the provided category and subcategory values.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService parses labeled category and subcategory lines\"`\n\n### `tests/unit/test_cache_interactions.cpp`\n\n#### Test case: CategorizationService uses cached categorization without calling LLM\nPurpose: Ensure cached category/subcategory rows are returned without invoking the LLM.\nSetup: Seed the database with a resolved category for a file entry and prepare a counting LLM stub.\nProcedure: Call `categorize_entries` for that file.\nExpected outcome: The cached category is returned and the LLM call counter stays at zero.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService uses cached categorization without calling LLM\"`\n\n#### Test case: CategorizationService falls back to LLM when cache is empty\nPurpose: Validate cache fallback to LLM and persistence of returned category values.\nSetup: Seed an empty cache record for a file and prepare a counting LLM stub with a valid label response.\nProcedure: Call `categorize_entries` for that file and then read the DB row.\nExpected outcome: The LLM is called once and the resulting category/subcategory are written back to cache.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService falls back to LLM when cache is empty\"`\n\n#### Test case: CategorizationService loads cached entries recursively for analysis\nPurpose: Confirm recursive cache loading obeys the `include_subdirectories` setting.\nSetup: Seed one cached row at root level and one in a child path.\nProcedure: Call `load_cached_entries` with recursion off, then on.\nExpected outcome: Non-recursive mode returns only root rows; recursive mode returns both rows.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService loads cached entries recursively for analysis\"`\n\n#### Test case: ResultsCoordinator respects full-path cache keys for recursive scans\nPurpose: Ensure recursive scans treat same-name files in different folders as distinct when using full-path cache keys.\nSetup: Create duplicate filenames at root and nested paths, then seed cache keys by full path.\nProcedure: Compute uncached entries via `find_files_to_categorize`.\nExpected outcome: Only the truly uncached nested path remains in the result set.\nRun: `./build-tests/ai_file_sorter_tests \"ResultsCoordinator respects full-path cache keys for recursive scans\"`\n\n#### Test case: CategorizationService invokes completion callback per entry\nPurpose: Verify per-entry completion notifications fire for categorization progress tracking.\nSetup: Prepare multiple file entries and callbacks that count queued/completed events.\nProcedure: Run `categorize_entries` and capture callback counters.\nExpected outcome: Queue and completion callbacks are each invoked once per processed entry.\nRun: `./build-tests/ai_file_sorter_tests \"CategorizationService invokes completion callback per entry\"`\n\n### Test infrastructure: `tests/unit/test_cli_reporter.cpp`\n\nThis 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.\n"
  },
  {
    "path": "TRADEMARKS.md",
    "content": "# Trademarks\n\nThis project is open source, but its name and branding are not licensed for general reuse.\n\nThe project owner claims trademark rights, to the extent permitted by law, in the following project marks (the \"Project Marks\"):\n\n- `AI File Sorter`\n- `ai-file-sorter`\n- 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`\n\nThe 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.\n\nYou may:\n\n- Use the Project Marks in plain text to refer to the official project, discuss compatibility, or describe unmodified official releases.\n- Keep existing trademark notices intact when redistributing unmodified copies.\n\nYou may not, without prior written permission from the project owner:\n\n- 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.\n- Use the Project Marks, logos, or other branding in a way that implies sponsorship, endorsement, affiliation, or official status.\n- Register, adopt, or use confusingly similar names, domains, package names, or social handles.\n\nIf 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.\n\nThird-party product names, logos, and trademarks referenced in this repository remain the property of their respective owners.\n\nAll 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.\n\nThis file provides notice of the project's trademark policy. It is not a substitute for trademark registration or jurisdiction-specific legal advice.\n"
  },
  {
    "path": "app/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.21)\n\nproject(AIFileSorter LANGUAGES CXX)\n\n# C++ standard\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\noption(AI_FILE_SORTER_BUILD_TESTS \"Build unit tests (requires Catch2 submodule)\" OFF)\noption(AI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND\n    \"Require vendored PDFium for PDF extraction instead of silently falling back to external CLI tools.\" ON)\nset(AI_FILE_SORTER_UPDATE_MODE \"PLATFORM_DEFAULT\" CACHE STRING\n    \"Updater behavior for this build: PLATFORM_DEFAULT, AUTO_INSTALL, NOTIFY_ONLY, or DISABLED\")\nset_property(CACHE AI_FILE_SORTER_UPDATE_MODE PROPERTY STRINGS\n    PLATFORM_DEFAULT AUTO_INSTALL NOTIFY_ONLY DISABLED)\n\nset(_aifs_effective_update_mode \"${AI_FILE_SORTER_UPDATE_MODE}\")\nif(_aifs_effective_update_mode STREQUAL \"PLATFORM_DEFAULT\")\n    if(WIN32)\n        set(_aifs_effective_update_mode \"AUTO_INSTALL\")\n    else()\n        set(_aifs_effective_update_mode \"NOTIFY_ONLY\")\n    endif()\nendif()\n\nset(_aifs_allowed_update_modes AUTO_INSTALL NOTIFY_ONLY DISABLED)\nlist(FIND _aifs_allowed_update_modes \"${_aifs_effective_update_mode}\" _aifs_update_mode_index)\nif(_aifs_update_mode_index EQUAL -1)\n    message(FATAL_ERROR\n        \"Unsupported AI_FILE_SORTER_UPDATE_MODE='${AI_FILE_SORTER_UPDATE_MODE}'. \"\n        \"Expected PLATFORM_DEFAULT, AUTO_INSTALL, NOTIFY_ONLY, or DISABLED.\")\nendif()\n\nif(_aifs_effective_update_mode STREQUAL \"AUTO_INSTALL\")\n    set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL)\nelseif(_aifs_effective_update_mode STREQUAL \"NOTIFY_ONLY\")\n    set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY)\nelse()\n    set(AI_FILE_SORTER_UPDATE_MODE_DEFINE AI_FILE_SORTER_UPDATE_MODE_DISABLED)\nendif()\n\nif(DEFINED VCPKG_INSTALLED_DIR AND NOT \"${VCPKG_INSTALLED_DIR}\" STREQUAL \"\")\n    set(AIFS_VCPKG_INSTALLED_ROOT \"${VCPKG_INSTALLED_DIR}\")\nelse()\n    set(AIFS_VCPKG_INSTALLED_ROOT \"${CMAKE_BINARY_DIR}/vcpkg_installed\")\nendif()\n\nmessage(STATUS \"AI File Sorter updater mode: ${_aifs_effective_update_mode}\")\n\ninclude(CheckSymbolExists)\ninclude(CheckCXXSourceCompiles)\n\nfunction(aifs_apply_update_mode target_name)\n    target_compile_definitions(${target_name} PRIVATE ${AI_FILE_SORTER_UPDATE_MODE_DEFINE})\nendfunction()\n\nfunction(aifs_apply_named_update_mode target_name update_mode)\n    if(update_mode STREQUAL \"AUTO_INSTALL\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL)\n    elseif(update_mode STREQUAL \"NOTIFY_ONLY\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY)\n    elseif(update_mode STREQUAL \"DISABLED\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_UPDATE_MODE_DISABLED)\n    else()\n        message(FATAL_ERROR\n            \"Unsupported explicit updater mode '${update_mode}' for target '${target_name}'.\")\n    endif()\nendfunction()\n\nfunction(aifs_apply_expected_update_mode target_name update_mode)\n    if(update_mode STREQUAL \"AUTO_INSTALL\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_AUTO_INSTALL)\n    elseif(update_mode STREQUAL \"NOTIFY_ONLY\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_NOTIFY_ONLY)\n    elseif(update_mode STREQUAL \"DISABLED\")\n        target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_EXPECTED_UPDATE_MODE_DISABLED)\n    else()\n        message(FATAL_ERROR\n            \"Unsupported expected updater mode '${update_mode}' for target '${target_name}'.\")\n    endif()\nendfunction()\n\n# Prefer MSVC on Windows if available\nif(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n    add_definitions(-D_CRT_SECURE_NO_WARNINGS)\n    # Keep MSVC worker processes busy within each project in addition to\n    # the top-level cmake --build --parallel job scheduling.\n    add_compile_options(\n        \"$<$<COMPILE_LANGUAGE:C>:/MP>\"\n        \"$<$<COMPILE_LANGUAGE:CXX>:/MP>\"\n    )\nendif()\n\n# Qt6\nfind_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)\nfind_package(Qt6LinguistTools CONFIG QUIET)\nif(NOT Qt6LinguistTools_FOUND)\n    set(_aifs_qttools_hints \"\")\n    if(DEFINED ENV{HOMEBREW_PREFIX} AND NOT \"$ENV{HOMEBREW_PREFIX}\" STREQUAL \"\")\n        list(APPEND _aifs_qttools_hints \"$ENV{HOMEBREW_PREFIX}/opt/qttools\")\n    endif()\n    list(APPEND _aifs_qttools_hints /opt/homebrew/opt/qttools /usr/local/opt/qttools)\n    if(DEFINED Qt6_DIR AND NOT \"${Qt6_DIR}\" STREQUAL \"\")\n        get_filename_component(_aifs_qt6_prefix \"${Qt6_DIR}/../../..\" ABSOLUTE)\n        list(APPEND _aifs_qttools_hints \"${_aifs_qt6_prefix}\")\n    endif()\n    list(REMOVE_DUPLICATES _aifs_qttools_hints)\n    foreach(_aifs_qttools_hint IN LISTS _aifs_qttools_hints)\n        if(EXISTS \"${_aifs_qttools_hint}/lib/cmake/Qt6LinguistTools/Qt6LinguistToolsConfig.cmake\")\n            list(APPEND CMAKE_PREFIX_PATH \"${_aifs_qttools_hint}\")\n        endif()\n    endforeach()\n    list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)\n    find_package(Qt6LinguistTools CONFIG REQUIRED)\nendif()\n\n# Third-party deps (resolved best via vcpkg on Windows)\nfind_package(CURL REQUIRED)\nfind_package(OpenSSL REQUIRED)\nfind_package(SQLite3 REQUIRED)\n# JsonCpp may not ship a CMake config on some distros (e.g. Ubuntu). Try\n# config mode first, then fall back to pkg-config.\nfind_package(JsonCpp CONFIG QUIET)\nif(NOT JsonCpp_FOUND)\n    find_package(PkgConfig REQUIRED)\n    pkg_check_modules(JSONCPP REQUIRED jsoncpp)\n    add_library(JsonCpp::JsonCpp INTERFACE IMPORTED)\n    target_include_directories(JsonCpp::JsonCpp INTERFACE ${JSONCPP_INCLUDE_DIRS})\n    target_link_directories(JsonCpp::JsonCpp INTERFACE ${JSONCPP_LIBRARY_DIRS})\n    target_link_libraries(JsonCpp::JsonCpp INTERFACE ${JSONCPP_LINK_LIBRARIES})\nelse()\n    if(NOT TARGET JsonCpp::JsonCpp)\n        add_library(JsonCpp::JsonCpp INTERFACE IMPORTED)\n    endif()\nendif()\nfind_package(fmt REQUIRED CONFIG)\nfind_package(spdlog REQUIRED CONFIG)\nfind_package(Intl REQUIRED) # libintl/gettext\n# MediaInfoLib from vcpkg depends on the separate ZenLib package and refers to\n# its imported target as plain \"zen\".\nfind_package(ZenLib CONFIG QUIET)\n\n# MediaInfoLib policy:\n# - Must come from package managers (apt/dnf/pacman/brew/vcpkg)\n# - Vendored submodules / checked-in binaries are rejected\noption(AI_FILE_SORTER_REQUIRE_MEDIAINFOLIB\n    \"Require MediaInfoLib at configure time for full audio/video metadata extraction\" ON)\noption(AI_FILE_SORTER_ALLOW_VENDORED_MEDIAINFOLIB\n    \"Allow vendored MediaInfo in the repository (not recommended)\" OFF)\n\nfile(REAL_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/..\" AI_FILE_SORTER_REPO_ROOT)\n\nset(_aifs_blocked_mediainfo_paths\n    \"${AI_FILE_SORTER_REPO_ROOT}/external/MediaInfoLib\"\n    \"${AI_FILE_SORTER_REPO_ROOT}/external/libmediainfo\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/lib/mediainfo\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include/MediaInfo\"\n)\nif(NOT AI_FILE_SORTER_ALLOW_VENDORED_MEDIAINFOLIB)\n    foreach(_blocked_path IN LISTS _aifs_blocked_mediainfo_paths)\n        if(EXISTS \"${_blocked_path}\")\n            message(FATAL_ERROR\n                \"Found vendored MediaInfo content at '${_blocked_path}'. \"\n                \"Use a package-managed libmediainfo (apt/dnf/pacman/brew/vcpkg) instead.\")\n        endif()\n    endforeach()\nendif()\n\nfunction(aifs_assert_path_not_in_repo path_value label)\n    if(NOT path_value)\n        return()\n    endif()\n\n    file(TO_CMAKE_PATH \"${AI_FILE_SORTER_REPO_ROOT}\" _repo_root_norm)\n    string(REGEX REPLACE \"([][+.*^$(){}|?\\\\\\\\])\" \"\\\\\\\\\\\\1\" _repo_root_regex \"${_repo_root_norm}\")\n\n    foreach(_entry IN LISTS path_value)\n        if(NOT _entry OR _entry MATCHES \"^\\\\$<\")\n            continue()\n        endif()\n\n        file(TO_CMAKE_PATH \"${_entry}\" _entry_norm)\n        # vcpkg manifest mode can stage package-managed headers/libs inside the\n        # build tree under a local vcpkg_installed directory. That is still a\n        # package-manager origin, not vendored MediaInfo content.\n        if(_entry_norm MATCHES \"(^|/)vcpkg_installed(/|$)\")\n            continue()\n        endif()\n        if(_entry_norm MATCHES \"^${_repo_root_regex}(/|$)\")\n            message(FATAL_ERROR\n                \"MediaInfo must come from a package manager. \"\n                \"Repository-local path detected for ${label}: '${_entry}'.\")\n        endif()\n    endforeach()\nendfunction()\n\nfunction(aifs_assert_mediainfo_target_external target_name)\n    if(NOT TARGET ${target_name})\n        return()\n    endif()\n\n    foreach(_prop IN ITEMS IMPORTED_LOCATION IMPORTED_IMPLIB INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_DIRECTORIES)\n        get_target_property(_prop_value ${target_name} ${_prop})\n        if(NOT _prop_value OR _prop_value STREQUAL \"_prop_value-NOTFOUND\")\n            continue()\n        endif()\n        aifs_assert_path_not_in_repo(\"${_prop_value}\" \"${target_name}:${_prop}\")\n    endforeach()\nendfunction()\n\nset(MEDIAINFO_DEPS_LIBS \"\")\nfind_package(MediaInfoLib CONFIG QUIET)\nif(TARGET MediaInfoLib::MediaInfoLib)\n    list(APPEND MEDIAINFO_DEPS_LIBS MediaInfoLib::MediaInfoLib)\nelseif(TARGET MediaInfoLib::MediaInfo)\n    list(APPEND MEDIAINFO_DEPS_LIBS MediaInfoLib::MediaInfo)\nelseif(TARGET MediaInfo::MediaInfo)\n    list(APPEND MEDIAINFO_DEPS_LIBS MediaInfo::MediaInfo)\nelseif(DEFINED MediaInfoLib_LIBRARY AND TARGET ${MediaInfoLib_LIBRARY})\n    # The vcpkg MediaInfoLib port exports a plain imported target named\n    # \"mediainfo\" and exposes that name through MediaInfoLib_LIBRARY.\n    list(APPEND MEDIAINFO_DEPS_LIBS ${MediaInfoLib_LIBRARY})\nelseif(TARGET mediainfo)\n    list(APPEND MEDIAINFO_DEPS_LIBS mediainfo)\nelse()\n    find_package(PkgConfig QUIET)\n    if(PkgConfig_FOUND)\n        pkg_check_modules(MEDIAINFO QUIET IMPORTED_TARGET libmediainfo)\n        if(TARGET PkgConfig::MEDIAINFO)\n            list(APPEND MEDIAINFO_DEPS_LIBS PkgConfig::MEDIAINFO)\n        endif()\n    endif()\n    if(NOT MEDIAINFO_DEPS_LIBS AND APPLE)\n        set(_aifs_mediainfo_prefixes \"\")\n        if(DEFINED ENV{HOMEBREW_PREFIX} AND NOT \"$ENV{HOMEBREW_PREFIX}\" STREQUAL \"\")\n            list(APPEND _aifs_mediainfo_prefixes \"$ENV{HOMEBREW_PREFIX}\")\n        endif()\n        list(APPEND _aifs_mediainfo_prefixes /opt/homebrew /usr/local)\n        list(REMOVE_DUPLICATES _aifs_mediainfo_prefixes)\n\n        set(_aifs_mediainfo_include_hints \"\")\n        set(_aifs_mediainfo_library_hints \"\")\n        foreach(_aifs_prefix IN LISTS _aifs_mediainfo_prefixes)\n            list(APPEND _aifs_mediainfo_include_hints\n                \"${_aifs_prefix}/opt/libmediainfo/include\"\n                \"${_aifs_prefix}/include\"\n            )\n            list(APPEND _aifs_mediainfo_library_hints\n                \"${_aifs_prefix}/opt/libmediainfo/lib\"\n                \"${_aifs_prefix}/lib\"\n            )\n        endforeach()\n\n        find_path(AIFS_MEDIAINFO_INCLUDE_DIR\n            NAMES MediaInfo/MediaInfo.h\n            HINTS ${_aifs_mediainfo_include_hints}\n        )\n        find_library(AIFS_MEDIAINFO_LIBRARY\n            NAMES mediainfo libmediainfo\n            HINTS ${_aifs_mediainfo_library_hints}\n        )\n        if(AIFS_MEDIAINFO_INCLUDE_DIR AND AIFS_MEDIAINFO_LIBRARY)\n            if(NOT TARGET AIFS::MediaInfoLib)\n                add_library(AIFS::MediaInfoLib UNKNOWN IMPORTED)\n                set_target_properties(AIFS::MediaInfoLib PROPERTIES\n                    IMPORTED_LOCATION \"${AIFS_MEDIAINFO_LIBRARY}\"\n                    INTERFACE_INCLUDE_DIRECTORIES \"${AIFS_MEDIAINFO_INCLUDE_DIR}\"\n                )\n            endif()\n            list(APPEND MEDIAINFO_DEPS_LIBS AIFS::MediaInfoLib)\n        endif()\n\n        unset(_aifs_mediainfo_include_hints)\n        unset(_aifs_mediainfo_library_hints)\n        unset(_aifs_mediainfo_prefixes)\n    endif()\nendif()\nif(MEDIAINFO_DEPS_LIBS)\n    foreach(_mediainfo_target IN LISTS MEDIAINFO_DEPS_LIBS)\n        aifs_assert_mediainfo_target_external(${_mediainfo_target})\n    endforeach()\n    add_compile_definitions(AI_FILE_SORTER_USE_MEDIAINFOLIB)\n    message(STATUS \"MediaInfoLib found via package-managed dependency: enabling full audio/video metadata extraction.\")\nelseif(AI_FILE_SORTER_REQUIRE_MEDIAINFOLIB)\n    message(FATAL_ERROR\n        \"MediaInfoLib is required but was not found. Install libmediainfo development files \"\n        \"(Linux: libmediainfo-dev, macOS: brew install mediainfo, Windows/vcpkg: libmediainfo). \"\n        \"Vendored MediaInfo submodules/binaries are not supported.\")\nelse()\n    message(STATUS\n        \"MediaInfoLib not found: using built-in metadata fallback parsers \"\n        \"(audio + MP4/MOV/M4V/3GP tags only).\")\nendif()\n\n# Vendored document analysis deps\nset(EXTERNAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/../external\")\nset(PUGIXML_DIR \"${EXTERNAL_DIR}/pugixml\")\nset(LIBZIP_DIR \"${EXTERNAL_DIR}/libzip\")\nset(PDFIUM_DIR \"${EXTERNAL_DIR}/pdfium\")\nset(DOC_DEPS_INCLUDE_DIRS \"\")\nset(DOC_DEPS_LIBS \"\")\n\n# Pugixml (compiled via PugixmlBundle.cpp)\nif(EXISTS \"${PUGIXML_DIR}/src/pugixml.hpp\")\n    list(APPEND DOC_DEPS_INCLUDE_DIRS \"${PUGIXML_DIR}/src\")\n    add_compile_definitions(PUGIXML_NO_EXCEPTIONS AI_FILE_SORTER_USE_PUGIXML)\nendif()\n\n# libzip (build from vendored source)\nif(EXISTS \"${LIBZIP_DIR}/CMakeLists.txt\")\n    set(BUILD_SHARED_LIBS OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_BZIP2 OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_LZMA OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_ZSTD OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_OPENSSL OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_GNUTLS OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_MBEDTLS OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_COMMONCRYPTO OFF CACHE BOOL \"\" FORCE)\n    set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL \"\" FORCE)\n    add_subdirectory(\"${LIBZIP_DIR}\" \"${CMAKE_CURRENT_BINARY_DIR}/libzip\")\n    if(TARGET libzip::zip)\n        add_compile_definitions(AI_FILE_SORTER_USE_LIBZIP)\n        list(APPEND DOC_DEPS_INCLUDE_DIRS \"${LIBZIP_DIR}/lib\" \"${CMAKE_CURRENT_BINARY_DIR}/libzip\")\n        list(APPEND DOC_DEPS_LIBS libzip::zip)\n    endif()\nendif()\n\nset(PDFIUM_PLATFORM_DIR \"\")\nset(PDFIUM_LIBRARY \"\")\nset(PDFIUM_RUNTIME \"\")\nset(_aifs_pdfium_missing_reason \"\")\n\nif(WIN32)\n    if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n        set(PDFIUM_PLATFORM_DIR \"${PDFIUM_DIR}/windows-x64\")\n        set(PDFIUM_LIBRARY \"${PDFIUM_PLATFORM_DIR}/lib/pdfium.dll.lib\")\n        set(PDFIUM_RUNTIME \"${PDFIUM_PLATFORM_DIR}/bin/pdfium.dll\")\n    else()\n        set(_aifs_pdfium_missing_reason\n            \"Embedded PDFium is only vendored for 64-bit Windows builds.\")\n    endif()\nelseif(APPLE)\n    set(_aifs_pdfium_apple_arch \"\")\n    if(CMAKE_OSX_ARCHITECTURES)\n        list(LENGTH CMAKE_OSX_ARCHITECTURES _aifs_pdfium_arch_count)\n        if(_aifs_pdfium_arch_count GREATER 1)\n            set(_aifs_pdfium_missing_reason\n                \"Embedded PDFium is vendored per-architecture. Configure a single macOS architecture instead of a universal build.\")\n        else()\n            list(GET CMAKE_OSX_ARCHITECTURES 0 _aifs_pdfium_apple_arch)\n        endif()\n    endif()\n    if(NOT _aifs_pdfium_apple_arch)\n        set(_aifs_pdfium_apple_arch \"${CMAKE_SYSTEM_PROCESSOR}\")\n    endif()\n    string(TOLOWER \"${_aifs_pdfium_apple_arch}\" _aifs_pdfium_apple_arch)\n    if(_aifs_pdfium_apple_arch MATCHES \"^(arm64|aarch64)$\")\n        set(PDFIUM_PLATFORM_DIR \"${PDFIUM_DIR}/macos-arm64\")\n        set(PDFIUM_LIBRARY \"${PDFIUM_PLATFORM_DIR}/lib/libpdfium.dylib\")\n        set(PDFIUM_RUNTIME \"${PDFIUM_LIBRARY}\")\n    elseif(_aifs_pdfium_apple_arch MATCHES \"^(x86_64|amd64)$\")\n        set(PDFIUM_PLATFORM_DIR \"${PDFIUM_DIR}/macos-x64\")\n        set(PDFIUM_LIBRARY \"${PDFIUM_PLATFORM_DIR}/lib/libpdfium.dylib\")\n        set(PDFIUM_RUNTIME \"${PDFIUM_LIBRARY}\")\n    else()\n        set(_aifs_pdfium_missing_reason\n            \"Embedded PDFium is not vendored for macOS architecture '${_aifs_pdfium_apple_arch}'.\")\n    endif()\nelseif(UNIX)\n    string(TOLOWER \"${CMAKE_SYSTEM_PROCESSOR}\" _aifs_pdfium_linux_arch)\n    if(_aifs_pdfium_linux_arch MATCHES \"^(x86_64|amd64)$\")\n        set(PDFIUM_PLATFORM_DIR \"${PDFIUM_DIR}/linux-x64\")\n        set(PDFIUM_LIBRARY \"${PDFIUM_PLATFORM_DIR}/lib/libpdfium.so\")\n        set(PDFIUM_RUNTIME \"${PDFIUM_LIBRARY}\")\n    else()\n        set(_aifs_pdfium_missing_reason\n            \"Embedded PDFium is not vendored for Linux architecture '${CMAKE_SYSTEM_PROCESSOR}'.\")\n    endif()\nendif()\n\nset(_aifs_pdfium_ready FALSE)\nif(PDFIUM_PLATFORM_DIR\n   AND EXISTS \"${PDFIUM_PLATFORM_DIR}/include/fpdfview.h\"\n   AND EXISTS \"${PDFIUM_LIBRARY}\"\n   AND PDFIUM_RUNTIME\n   AND EXISTS \"${PDFIUM_RUNTIME}\")\n    set(_aifs_pdfium_ready TRUE)\nendif()\n\nif(_aifs_pdfium_ready)\n    add_compile_definitions(AI_FILE_SORTER_USE_PDFIUM)\n    list(APPEND DOC_DEPS_INCLUDE_DIRS \"${PDFIUM_PLATFORM_DIR}/include\")\n    add_library(pdfium SHARED IMPORTED)\n    if(WIN32)\n        set_target_properties(pdfium PROPERTIES\n            IMPORTED_IMPLIB \"${PDFIUM_LIBRARY}\"\n            IMPORTED_LOCATION \"${PDFIUM_RUNTIME}\"\n        )\n    else()\n        set_target_properties(pdfium PROPERTIES\n            IMPORTED_LOCATION \"${PDFIUM_LIBRARY}\"\n        )\n    endif()\n    list(APPEND DOC_DEPS_LIBS pdfium)\nelseif(PDFIUM_PLATFORM_DIR OR _aifs_pdfium_missing_reason)\n    if(NOT _aifs_pdfium_missing_reason)\n        set(_aifs_pdfium_missing_reason\n            \"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.\")\n    endif()\n    if(AI_FILE_SORTER_REQUIRE_EMBEDDED_PDF_BACKEND)\n        message(FATAL_ERROR \"${_aifs_pdfium_missing_reason}\")\n    else()\n        message(WARNING \"${_aifs_pdfium_missing_reason} Falling back to 'pdftotext' when available.\")\n    endif()\nendif()\n\n# Sources\nset(APP_MAIN_SOURCE \"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp\")\nfile(GLOB APP_LIB_SOURCES CONFIGURE_DEPENDS\n    \"${CMAKE_CURRENT_SOURCE_DIR}/lib/*.cpp\"\n)\nfile(GLOB APP_HEADER_SOURCES CONFIGURE_DEPENDS\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp\"\n)\nset(APP_SOURCES ${APP_MAIN_SOURCE} ${APP_LIB_SOURCES})\nset(AIFS_TRANSLATION_TS_FILES\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_fr.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_de.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_it.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_es.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_nl.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_tr.ts\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/i18n/aifilesorter_ko.ts\"\n)\nset(AIFS_TRANSLATION_QM_DIR \"${CMAKE_CURRENT_BINARY_DIR}/i18n\")\n\n# Executable (GUI subsystem on Windows)\nif(WIN32)\n    add_executable(aifilesorter WIN32 ${APP_SOURCES})\nelse()\n    add_executable(aifilesorter ${APP_SOURCES})\nendif()\n\naifs_apply_update_mode(aifilesorter)\n\ntarget_include_directories(aifilesorter PRIVATE\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include/llama\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd\"\n    ${DOC_DEPS_INCLUDE_DIRS}\n)\n\nqt_add_lupdate(\n    NO_GLOBAL_TARGET\n    LUPDATE_TARGET update_translations\n    SOURCE_TARGETS aifilesorter\n    TS_FILES ${AIFS_TRANSLATION_TS_FILES}\n    SOURCES \"${CMAKE_CURRENT_SOURCE_DIR}/startapp_windows.cpp\" ${APP_HEADER_SOURCES}\n    OPTIONS -no-obsolete\n)\n\nqt_add_lrelease(\n    LRELEASE_TARGET release_app_translations\n    TS_FILES ${AIFS_TRANSLATION_TS_FILES}\n    QM_OUTPUT_DIRECTORY \"${AIFS_TRANSLATION_QM_DIR}\"\n    QM_FILES_OUTPUT_VARIABLE AIFS_TRANSLATION_QM_FILES\n)\n\nset_source_files_properties(${AIFS_TRANSLATION_QM_FILES} PROPERTIES GENERATED TRUE)\n\nfunction(aifs_add_translation_resources target_name)\n    qt_add_resources(${target_name} \"${target_name}_translations\"\n        PREFIX \"/i18n\"\n        BASE \"${AIFS_TRANSLATION_QM_DIR}\"\n        FILES ${AIFS_TRANSLATION_QM_FILES}\n    )\nendfunction()\n\naifs_add_translation_resources(aifilesorter)\n\n# Resources (equivalent to rcc generation in Makefile)\nset(APP_RESOURCE_FILES\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/.env\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/logo.png\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/qn_logo.png\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/app_icon_128.png\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_512x512.png\"\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/certs/cacert.pem\"\n)\n\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/.env\"\n    PROPERTIES QT_RESOURCE_ALIAS \".env\"\n)\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/logo.png\"\n    PROPERTIES QT_RESOURCE_ALIAS \"images/logo.png\"\n)\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/qn_logo.png\"\n    PROPERTIES QT_RESOURCE_ALIAS \"images/qn_logo.png\"\n)\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/app_icon_128.png\"\n    PROPERTIES QT_RESOURCE_ALIAS \"images/app_icon_128.png\"\n)\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_512x512.png\"\n    PROPERTIES QT_RESOURCE_ALIAS \"images/icon_512x512.png\"\n)\nset_source_files_properties(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/resources/certs/cacert.pem\"\n    PROPERTIES QT_RESOURCE_ALIAS \"certs/cacert.pem\"\n)\n\nqt_add_resources(aifilesorter \"app_resources\"\n    PREFIX \"/net/quicknode/AIFileSorter\"\n    FILES ${APP_RESOURCE_FILES}\n)\n\nif(WIN32)\n    if(DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKLibVersion})\n        set(WIN_SDK_UM_DIR \"$ENV{WindowsSdkDir}Lib/$ENV{WindowsSDKLibVersion}/um/x64\")\n        set(WIN_SDK_UCRT_DIR \"$ENV{WindowsSdkDir}Lib/$ENV{WindowsSDKLibVersion}/ucrt/x64\")\n        if(EXISTS \"${WIN_SDK_UM_DIR}\")\n            link_directories(\"${WIN_SDK_UM_DIR}\")\n        endif()\n        if(EXISTS \"${WIN_SDK_UCRT_DIR}\")\n            link_directories(\"${WIN_SDK_UCRT_DIR}\")\n        endif()\n    endif()\n\n    set(PRECOMPILED_CPU_LIB_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu/lib\")\n    set(PRECOMPILED_CPU_BIN_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu/bin\")\n    set(LLAMA_CPU_IMPORT \"${PRECOMPILED_CPU_LIB_DIR}/llama.lib\")\n    set(LLAMA_CPU_DLL \"${PRECOMPILED_CPU_BIN_DIR}/llama.dll\")\n    if(NOT EXISTS \"${LLAMA_CPU_IMPORT}\")\n        message(FATAL_ERROR \"Missing ${LLAMA_CPU_IMPORT}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot=<path> first.\")\n    endif()\n    if(NOT EXISTS \"${LLAMA_CPU_DLL}\")\n        message(FATAL_ERROR \"Missing ${LLAMA_CPU_DLL}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot=<path> to stage runtime DLLs.\")\n    endif()\n    add_library(llama SHARED IMPORTED)\n    set_target_properties(llama PROPERTIES\n        IMPORTED_IMPLIB \"${LLAMA_CPU_IMPORT}\"\n        IMPORTED_LOCATION \"${LLAMA_CPU_DLL}\"\n    )\n\n    foreach(libName IN ITEMS ggml ggml-base ggml-cpu)\n        set(import_path \"${PRECOMPILED_CPU_LIB_DIR}/${libName}.lib\")\n        set(dll_path \"${PRECOMPILED_CPU_BIN_DIR}/${libName}.dll\")\n        if(NOT EXISTS \"${import_path}\")\n            message(FATAL_ERROR \"Missing ${import_path}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot=<path> first.\")\n        endif()\n        if(NOT EXISTS \"${dll_path}\")\n            message(FATAL_ERROR \"Missing ${dll_path}. Run app/scripts/build_llama_windows.ps1 cuda=off vcpkgroot=<path> to stage runtime DLLs.\")\n        endif()\n        string(REPLACE \"-\" \"_\" imported_target \"${libName}\")\n        add_library(${imported_target} SHARED IMPORTED)\n        set_target_properties(${imported_target} PROPERTIES\n            IMPORTED_IMPLIB \"${import_path}\"\n            IMPORTED_LOCATION \"${dll_path}\"\n        )\n    endforeach()\n\n    set(MTMD_IMPORT \"${PRECOMPILED_CPU_LIB_DIR}/mtmd.lib\")\n    set(MTMD_DLL \"${PRECOMPILED_CPU_BIN_DIR}/mtmd.dll\")\n    if(EXISTS \"${MTMD_IMPORT}\" AND EXISTS \"${MTMD_DLL}\")\n        add_library(mtmd SHARED IMPORTED)\n        set_target_properties(mtmd PROPERTIES\n            IMPORTED_IMPLIB \"${MTMD_IMPORT}\"\n            IMPORTED_LOCATION \"${MTMD_DLL}\"\n        )\n        target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_HAS_MTMD)\n        set(_aifs_saved_required_libs \"${CMAKE_REQUIRED_LIBRARIES}\")\n        set(CMAKE_REQUIRED_LIBRARIES \"${MTMD_IMPORT}\")\n        check_cxx_source_compiles([[\n            extern \"C\" void mtmd_helper_set_progress_callback(void*, void*);\n            int main() {\n                mtmd_helper_set_progress_callback(0, 0);\n                return 0;\n            }\n        ]] HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK)\n        check_cxx_source_compiles([[\n            extern \"C\" void mtmd_helper_log_set(void*, void*);\n            int main() {\n                mtmd_helper_log_set(0, 0);\n                return 0;\n            }\n        ]] HAVE_MTMD_HELPER_LOG_SET)\n        set(CMAKE_REQUIRED_LIBRARIES \"${_aifs_saved_required_libs}\")\n        unset(_aifs_saved_required_libs)\n        if(HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK)\n            target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK)\n        endif()\n        if(HAVE_MTMD_HELPER_LOG_SET)\n            target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_LOG_CALLBACK)\n        endif()\n    else()\n        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.\")\n    endif()\nelse()\n    # Build llama.cpp from the included submodule for non-Windows platforms\n    set(LLAMA_BUILD_COMMON ON CACHE BOOL \"llama: build common utils library\" FORCE)\n    set(BUILD_SHARED_LIBS OFF CACHE BOOL \"Build shared libs\" FORCE)\n    add_subdirectory(\"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp\" \"${CMAKE_CURRENT_BINARY_DIR}/llama-build\")\n    get_directory_property(_llama_install_version DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/llama-build\" DEFINITION LLAMA_INSTALL_VERSION)\n    if (NOT _llama_install_version OR _llama_install_version STREQUAL \"LLAMA_INSTALL_VERSION-NOTFOUND\")\n        set(_llama_install_version \"0.0.0\")\n    endif()\n    set(LLAMA_INSTALL_VERSION \"${_llama_install_version}\")\n    add_subdirectory(\"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd\" \"${CMAKE_CURRENT_BINARY_DIR}/mtmd-build\")\n    target_link_libraries(aifilesorter PRIVATE llama)\n    target_link_libraries(aifilesorter PRIVATE mtmd)\n    target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_HAS_MTMD)\n    set(CMAKE_REQUIRED_INCLUDES\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/tools/mtmd\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/include\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include/external/llama.cpp/ggml/include\"\n    )\n    check_symbol_exists(mtmd_helper_set_progress_callback \"mtmd-helper.h\" HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK)\n    check_symbol_exists(mtmd_helper_log_set \"mtmd-helper.h\" HAVE_MTMD_HELPER_LOG_SET)\n    set(CMAKE_REQUIRED_INCLUDES)\n    if(HAVE_MTMD_HELPER_SET_PROGRESS_CALLBACK)\n        target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK)\n    endif()\n    if(HAVE_MTMD_HELPER_LOG_SET)\n        target_compile_definitions(aifilesorter PRIVATE AI_FILE_SORTER_MTMD_LOG_CALLBACK)\n    endif()\n    if(MSVC)\n        target_compile_options(llama PRIVATE /Zc:char8_t-)\n    endif()\nendif()\n\n# Link libraries\ntarget_link_libraries(aifilesorter PRIVATE\n    Qt6::Widgets Qt6::Gui Qt6::Core\n    CURL::libcurl\n    OpenSSL::SSL OpenSSL::Crypto\n    SQLite::SQLite3\n    JsonCpp::JsonCpp\n    fmt::fmt\n    spdlog::spdlog\n    Intl::Intl\n    llama           # imported on Windows or built from submodule on other platforms\n    ${MEDIAINFO_DEPS_LIBS}\n    ${DOC_DEPS_LIBS}\n)\n\nif(WIN32)\n    target_link_libraries(aifilesorter PRIVATE ggml ggml_base ggml_cpu)\n    if(TARGET mtmd)\n        target_link_libraries(aifilesorter PRIVATE mtmd)\n    endif()\nendif()\n\nif(_aifs_pdfium_ready)\n    if(PDFIUM_RUNTIME AND EXISTS \"${PDFIUM_RUNTIME}\")\n        add_custom_command(TARGET aifilesorter POST_BUILD\n            COMMAND ${CMAKE_COMMAND} -E copy_if_different\n                \"${PDFIUM_RUNTIME}\"\n                \"$<TARGET_FILE_DIR:aifilesorter>\"\n        )\n    endif()\n    if(NOT WIN32)\n        if(APPLE)\n            set(_pdfium_rpath \"@loader_path\")\n        else()\n            set(_pdfium_rpath \"$ORIGIN\")\n        endif()\n        set_target_properties(aifilesorter PROPERTIES\n            BUILD_RPATH \"${_pdfium_rpath}\"\n            INSTALL_RPATH \"${_pdfium_rpath}\"\n        )\n        unset(_pdfium_rpath)\n    endif()\nendif()\n\nif(WIN32)\n    set(STARTER_TARGET StartAiFileSorter)\n    add_executable(${STARTER_TARGET} WIN32\n        \"${CMAKE_CURRENT_SOURCE_DIR}/startapp_windows.cpp\"\n    )\n    aifs_apply_update_mode(${STARTER_TARGET})\n    target_include_directories(${STARTER_TARGET} PRIVATE\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n    )\n    target_link_libraries(${STARTER_TARGET} PRIVATE\n        Qt6::Widgets Qt6::Gui Qt6::Core\n    )\n    target_compile_definitions(${STARTER_TARGET} PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)\nendif()\n\n# On Windows, ensure Unicode and lean Windows headers in deps that need it\nif(WIN32)\n    target_compile_definitions(aifilesorter PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)\n    set(WIN_SYSTEM_LIBS wininet d3d11 dxgi dxguid d3d12 mpr userenv)\n\n    if(CMAKE_SIZEOF_VOID_P EQUAL 8)\n        set(_win_sdk_arch \"x64\")\n    else()\n        set(_win_sdk_arch \"x86\")\n    endif()\n\n    set(_win_sdk_lib_paths \"\")\n    if(DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKLibVersion})\n        file(TO_CMAKE_PATH \"$ENV{WindowsSdkDir}\" _sdk_dir)\n        file(TO_CMAKE_PATH \"$ENV{WindowsSDKLibVersion}\" _sdk_version_raw)\n        string(REGEX REPLACE \"/$\" \"\" _sdk_version \"${_sdk_version_raw}\")\n        set(_sdk_root \"${_sdk_dir}Lib/${_sdk_version}\")\n        foreach(_subdir IN ITEMS um ucrt)\n            set(_candidate \"${_sdk_root}/${_subdir}/${_win_sdk_arch}\")\n            if(EXISTS \"${_candidate}\")\n                list(APPEND _win_sdk_lib_paths \"${_candidate}\")\n            endif()\n        endforeach()\n    endif()\n\n    if(NOT _win_sdk_lib_paths AND DEFINED CMAKE_RC_COMPILER AND CMAKE_RC_COMPILER)\n        get_filename_component(_rc_dir \"${CMAKE_RC_COMPILER}\" DIRECTORY)\n        get_filename_component(_bin_version_dir \"${_rc_dir}\" DIRECTORY)\n        get_filename_component(_bin_dir \"${_bin_version_dir}\" DIRECTORY)\n        get_filename_component(_kits_root \"${_bin_dir}\" DIRECTORY)\n        get_filename_component(_sdk_version \"${_bin_version_dir}\" NAME)\n        if(_kits_root AND EXISTS \"${_kits_root}/Lib/${_sdk_version}\")\n            set(_sdk_root \"${_kits_root}/Lib/${_sdk_version}\")\n            foreach(_subdir IN ITEMS um ucrt)\n                set(_candidate \"${_sdk_root}/${_subdir}/${_win_sdk_arch}\")\n                if(EXISTS \"${_candidate}\")\n                    list(APPEND _win_sdk_lib_paths \"${_candidate}\")\n                endif()\n            endforeach()\n        endif()\n    endif()\n\n    foreach(libName IN LISTS WIN_SYSTEM_LIBS)\n        string(TOUPPER \"${libName}\" upperLib)\n        set(varName \"${upperLib}_LIBRARY\")\n        unset(${varName})\n        if(_win_sdk_lib_paths)\n            find_library(${varName} NAMES ${libName}\n                PATHS ${_win_sdk_lib_paths}\n                NO_DEFAULT_PATH\n            )\n        endif()\n        if(NOT ${varName})\n            find_library(${varName} NAMES ${libName})\n        endif()\n        if(NOT ${varName})\n            message(FATAL_ERROR \"Required system library '${libName}' not found. Ensure the Windows SDK is installed.\")\n        endif()\n        target_link_libraries(aifilesorter PRIVATE \"${${varName}}\")\n    endforeach()\nendif()\n\nif(WIN32)\n    find_program(POWERSHELL_EXECUTABLE NAMES pwsh pwsh.exe powershell powershell.exe)\n    if(NOT POWERSHELL_EXECUTABLE)\n        message(FATAL_ERROR \"PowerShell is required to generate Windows resources\")\n    endif()\n\n    set(APP_ICON_BASE \"${CMAKE_CURRENT_SOURCE_DIR}/resources/images/icon_256x256.png\")\n    set(APP_ICON_ICO \"${CMAKE_CURRENT_BINARY_DIR}/generated/app_icon.ico\")\n    add_custom_command(OUTPUT \"${APP_ICON_ICO}\"\n        COMMAND \"${POWERSHELL_EXECUTABLE}\" -NoProfile -ExecutionPolicy Bypass -File \"${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icon.ps1\" -BasePng \"${APP_ICON_BASE}\" -Ico \"${APP_ICON_ICO}\"\n        DEPENDS \"${APP_ICON_BASE}\" \"${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icon.ps1\"\n        COMMENT \"Generating Windows icon\"\n        VERBATIM\n    )\n    set(APP_ICON_RC \"${CMAKE_CURRENT_BINARY_DIR}/generated/app_icon.rc\")\n    file(TO_NATIVE_PATH \"${APP_ICON_ICO}\" APP_ICON_ICO_NATIVE_TEMP)\n    string(REPLACE \"\\\\\" \"\\\\\\\\\" APP_ICON_ICO_NATIVE \"${APP_ICON_ICO_NATIVE_TEMP}\")\n    set(APP_ICON_PATH \"${APP_ICON_ICO_NATIVE}\")\n    configure_file(\n        \"${CMAKE_CURRENT_SOURCE_DIR}/resources/windows/app_icon.rc.in\"\n        \"${APP_ICON_RC}\"\n        @ONLY\n    )\n    set_source_files_properties(\"${APP_ICON_ICO}\" PROPERTIES GENERATED TRUE)\n    add_custom_target(app_icon_resource ALL DEPENDS \"${APP_ICON_ICO}\")\n    add_dependencies(aifilesorter app_icon_resource)\n    add_dependencies(aifilesorter app_icon_resource)\n    if(WIN32)\n        add_dependencies(${STARTER_TARGET} app_icon_resource)\n    endif()\n    target_sources(aifilesorter PRIVATE \"${APP_ICON_RC}\")\n    target_sources(aifilesorter PRIVATE \"${APP_ICON_RC}\")\n    if(WIN32)\n        target_sources(${STARTER_TARGET} PRIVATE \"${APP_ICON_RC}\")\n    endif()\n\n    # Version info resource generated from app_version.hpp\n    set(APP_VERSION_HEADER \"${CMAKE_CURRENT_SOURCE_DIR}/include/app_version.hpp\")\n    file(READ \"${APP_VERSION_HEADER}\" APP_VERSION_CONTENTS)\n    string(REGEX MATCH \"Version\\\\{([0-9]+),[ \\t]*([0-9]+),[ \\t]*([0-9]+)\" _ \"${APP_VERSION_CONTENTS}\")\n    if(CMAKE_MATCH_1)\n        set(APP_VER_MAJOR \"${CMAKE_MATCH_1}\")\n        set(APP_VER_MINOR \"${CMAKE_MATCH_2}\")\n        set(APP_VER_PATCH \"${CMAKE_MATCH_3}\")\n    else()\n        set(APP_VER_MAJOR \"0\")\n        set(APP_VER_MINOR \"0\")\n        set(APP_VER_PATCH \"0\")\n    endif()\n\n    configure_file(\n        \"${CMAKE_CURRENT_SOURCE_DIR}/resources/windows/version.rc.in\"\n        \"${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc\"\n        @ONLY\n    )\n    target_sources(aifilesorter PRIVATE \"${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc\")\n    target_sources(${STARTER_TARGET} PRIVATE \"${CMAKE_CURRENT_BINARY_DIR}/generated/version.rc\")\n\n    set(PRECOMPILED_CPU_ROOT \"${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cpu\")\n    set(PRECOMPILED_CUDA_ROOT \"${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/cuda\")\n    set(PRECOMPILED_VULKAN_ROOT \"${CMAKE_CURRENT_SOURCE_DIR}/lib/precompiled/vulkan\")\n\n    add_custom_command(TARGET aifilesorter POST_BUILD\n        # COMMAND ${CMAKE_COMMAND} -E remove -f \"$<TARGET_FILE_DIR:aifilesorter>/openblas.dll\"\n        COMMAND ${CMAKE_COMMAND} -E make_directory \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wocuda\"\n        COMMAND ${CMAKE_COMMAND} -E make_directory \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wcuda\"\n        COMMAND ${CMAKE_COMMAND} -E make_directory \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wvulkan\"\n        COMMAND ${CMAKE_COMMAND} -E copy_directory\n            \"${PRECOMPILED_CPU_ROOT}\"\n            \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wocuda\"\n        COMMAND ${CMAKE_COMMAND} -E copy_directory\n            \"${PRECOMPILED_CUDA_ROOT}\"\n            \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wcuda\"\n        COMMAND ${CMAKE_COMMAND} -E copy_directory\n            \"${PRECOMPILED_VULKAN_ROOT}\"\n            \"$<TARGET_FILE_DIR:aifilesorter>/lib/ggml/wvulkan\"\n    )\n\n    # set(_precompiled_libopenblas \"${PRECOMPILED_CPU_ROOT}/bin/libopenblas.dll\")\n    # if(EXISTS \"${_precompiled_libopenblas}\")\n    #     add_custom_command(TARGET aifilesorter POST_BUILD\n    #         COMMAND ${CMAKE_COMMAND} -E copy_if_different\n    #             \"${_precompiled_libopenblas}\"\n    #             \"$<TARGET_FILE_DIR:aifilesorter>/libopenblas.dll\"\n    #     )\n    # else()\n    #     message(WARNING \"Expected ${_precompiled_libopenblas} to exist. Run app/scripts/build_llama_windows.ps1 to stage GGML artifacts.\")\n    # endif()\nendif()\n\nif(AI_FILE_SORTER_BUILD_TESTS)\n    include(CTest)\n    set(_catch2_source_dir \"${CMAKE_SOURCE_DIR}/../external/Catch2\")\n    if(EXISTS \"${_catch2_source_dir}/CMakeLists.txt\")\n        add_subdirectory(${_catch2_source_dir} ${CMAKE_BINARY_DIR}/catch2-build)\n    else()\n        message(STATUS \"Catch2 submodule not found, fetching via FetchContent\")\n        include(FetchContent)\n        FetchContent_Declare(\n            Catch2\n            GIT_REPOSITORY https://github.com/catchorg/Catch2.git\n            GIT_TAG v3.5.2\n        )\n        FetchContent_MakeAvailable(Catch2)\n    endif()\n\n    function(aifs_stage_test_runtime target_name)\n        if(WIN32)\n            set(_aifs_test_runtime_dlls \"\")\n            add_custom_command(TARGET ${target_name} POST_BUILD\n                COMMAND ${CMAKE_COMMAND} -E copy_if_different\n                    $<TARGET_RUNTIME_DLLS:${target_name}>\n                    $<TARGET_FILE_DIR:${target_name}>\n                COMMAND_EXPAND_LISTS\n            )\n\n            if(VCPKG_TARGET_TRIPLET)\n                set(_aifs_vcpkg_runtime_dir \"${AIFS_VCPKG_INSTALLED_ROOT}/${VCPKG_TARGET_TRIPLET}/bin\")\n                if(EXISTS \"${_aifs_vcpkg_runtime_dir}\")\n                    file(GLOB _aifs_vcpkg_runtime_dlls \"${_aifs_vcpkg_runtime_dir}/*.dll\")\n                    list(APPEND _aifs_test_runtime_dlls ${_aifs_vcpkg_runtime_dlls})\n                endif()\n            endif()\n\n            if(EXISTS \"${PRECOMPILED_CPU_ROOT}/bin\")\n                file(GLOB _aifs_precompiled_cpu_runtime_dlls\n                    \"${PRECOMPILED_CPU_ROOT}/bin/*.dll\")\n                list(APPEND _aifs_test_runtime_dlls ${_aifs_precompiled_cpu_runtime_dlls})\n            endif()\n\n            set(_aifs_mingw_runtime_search_paths \"\")\n            if(DEFINED ENV{OPENBLAS_ROOT} AND NOT \"$ENV{OPENBLAS_ROOT}\" STREQUAL \"\")\n                list(APPEND _aifs_mingw_runtime_search_paths \"$ENV{OPENBLAS_ROOT}/bin\")\n            endif()\n            list(APPEND _aifs_mingw_runtime_search_paths \"C:/msys64/mingw64/bin\")\n\n            foreach(_aifs_mingw_runtime_name IN ITEMS\n                libgomp-1.dll\n                libgcc_s_seh-1.dll\n                libgfortran-5.dll\n                libwinpthread-1.dll\n                libquadmath-0.dll)\n                foreach(_aifs_runtime_path IN LISTS _aifs_mingw_runtime_search_paths)\n                    if(EXISTS \"${_aifs_runtime_path}/${_aifs_mingw_runtime_name}\")\n                        list(APPEND _aifs_test_runtime_dlls\n                            \"${_aifs_runtime_path}/${_aifs_mingw_runtime_name}\")\n                        break()\n                    endif()\n                endforeach()\n            endforeach()\n\n            list(REMOVE_DUPLICATES _aifs_test_runtime_dlls)\n            if(_aifs_test_runtime_dlls)\n                add_custom_command(TARGET ${target_name} POST_BUILD\n                    COMMAND ${CMAKE_COMMAND} -E copy_if_different\n                        ${_aifs_test_runtime_dlls}\n                        $<TARGET_FILE_DIR:${target_name}>\n                    COMMAND_EXPAND_LISTS\n                )\n            endif()\n\n            if(VCPKG_TARGET_TRIPLET)\n                set(_aifs_qt_plugin_root \"${AIFS_VCPKG_INSTALLED_ROOT}/${VCPKG_TARGET_TRIPLET}/Qt6/plugins\")\n                foreach(_aifs_qt_plugin_subdir IN ITEMS platforms styles imageformats)\n                    set(_aifs_qt_plugin_src_dir \"${_aifs_qt_plugin_root}/${_aifs_qt_plugin_subdir}\")\n                    if(EXISTS \"${_aifs_qt_plugin_src_dir}\")\n                        file(GLOB _aifs_qt_plugin_dlls \"${_aifs_qt_plugin_src_dir}/*.dll\")\n                        if(_aifs_qt_plugin_dlls)\n                            add_custom_command(TARGET ${target_name} POST_BUILD\n                                COMMAND ${CMAKE_COMMAND} -E make_directory\n                                    \"$<TARGET_FILE_DIR:${target_name}>/${_aifs_qt_plugin_subdir}\"\n                                COMMAND ${CMAKE_COMMAND} -E copy_if_different\n                                    ${_aifs_qt_plugin_dlls}\n                                    \"$<TARGET_FILE_DIR:${target_name}>/${_aifs_qt_plugin_subdir}\"\n                                COMMAND_EXPAND_LISTS\n                            )\n                        endif()\n                    endif()\n                endforeach()\n            endif()\n        endif()\n\n        if(_aifs_pdfium_ready AND PDFIUM_RUNTIME AND EXISTS \"${PDFIUM_RUNTIME}\")\n            add_custom_command(TARGET ${target_name} POST_BUILD\n                COMMAND ${CMAKE_COMMAND} -E copy_if_different\n                    \"${PDFIUM_RUNTIME}\"\n                    \"$<TARGET_FILE_DIR:${target_name}>\"\n            )\n        endif()\n        if(_aifs_pdfium_ready AND NOT WIN32)\n            if(APPLE)\n                set(_pdfium_rpath \"@loader_path\")\n            else()\n                set(_pdfium_rpath \"$ORIGIN\")\n            endif()\n            set_target_properties(${target_name} PROPERTIES\n                BUILD_RPATH \"${_pdfium_rpath}\"\n                INSTALL_RPATH \"${_pdfium_rpath}\"\n            )\n            unset(_pdfium_rpath)\n        endif()\n    endfunction()\n\n    add_executable(ai_file_sorter_tests\n        ${APP_LIB_SOURCES}\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_utils.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_file_scanner.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_local_llm_backend.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_ggml_runtime_paths.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llm_downloader.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_update_feed.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater_build_modes.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llm_selection_dialog_visual.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_translation.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_image_options.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_main_app_visual_fallback.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_settings_image_options.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_ui_translator.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_categorization_dialog.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_checkbox_matrix.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_review_dialog_rename_gate.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_cli_reporter.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_support_prompt.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_whitelist_and_prompt.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_database_manager_rename_only.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_cache_interactions.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_image_rename_metadata_service.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_llava_image_analyzer.cpp\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_media_rename_metadata_service.cpp\"\n    )\n\n    target_include_directories(ai_file_sorter_tests PRIVATE\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/include/llama\"\n        \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit\"\n        ${DOC_DEPS_INCLUDE_DIRS}\n    )\n\n    target_link_libraries(ai_file_sorter_tests PRIVATE\n        Catch2::Catch2WithMain\n        Qt6::Core\n        Qt6::Widgets\n        CURL::libcurl\n        OpenSSL::SSL OpenSSL::Crypto\n        SQLite::SQLite3\n        JsonCpp::JsonCpp\n        spdlog::spdlog\n        fmt::fmt\n        Intl::Intl\n        llama\n        ${MEDIAINFO_DEPS_LIBS}\n        ${DOC_DEPS_LIBS}\n    )\n\n    aifs_add_translation_resources(ai_file_sorter_tests)\n\n    target_compile_definitions(ai_file_sorter_tests PRIVATE AI_FILE_SORTER_TEST_BUILD=1 WIN32_LEAN_AND_MEAN NOMINMAX)\n    aifs_apply_update_mode(ai_file_sorter_tests)\n    aifs_apply_expected_update_mode(ai_file_sorter_tests \"${_aifs_effective_update_mode}\")\n\n    if(WIN32)\n        target_link_libraries(ai_file_sorter_tests PRIVATE ggml ggml_base ggml_cpu)\n        foreach(libName IN LISTS WIN_SYSTEM_LIBS)\n            string(TOUPPER \"${libName}\" upperLib)\n            set(varName \"${upperLib}_LIBRARY\")\n            if(DEFINED ${varName} AND ${varName})\n                target_link_libraries(ai_file_sorter_tests PRIVATE \"${${varName}}\")\n            else()\n                target_link_libraries(ai_file_sorter_tests PRIVATE ${libName})\n            endif()\n        endforeach()\n    endif()\n\n    aifs_stage_test_runtime(ai_file_sorter_tests)\n\n    if(WIN32)\n        set(AIFS_UPDATER_MODE_TEST_APP_SOURCES\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/IniConfig.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/Logger.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/Settings.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateArchiveExtractor.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateFeed.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/UpdateInstaller.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/Updater.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/Utils.cpp\"\n            \"${CMAKE_CURRENT_SOURCE_DIR}/lib/Version.cpp\"\n        )\n\n        function(aifs_add_updater_mode_test target_name update_mode)\n            add_executable(${target_name}\n                ${AIFS_UPDATER_MODE_TEST_APP_SOURCES}\n                \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit/test_updater_build_modes.cpp\"\n            )\n\n            target_include_directories(${target_name} PRIVATE\n                \"${CMAKE_CURRENT_SOURCE_DIR}/include\"\n                \"${CMAKE_CURRENT_SOURCE_DIR}/../tests/unit\"\n                ${DOC_DEPS_INCLUDE_DIRS}\n            )\n\n            target_link_libraries(${target_name} PRIVATE\n                Catch2::Catch2WithMain\n                Qt6::Core\n                Qt6::Widgets\n                CURL::libcurl\n                OpenSSL::SSL OpenSSL::Crypto\n                SQLite::SQLite3\n                JsonCpp::JsonCpp\n                spdlog::spdlog\n                fmt::fmt\n                Intl::Intl\n                ${DOC_DEPS_LIBS}\n            )\n\n            target_compile_definitions(${target_name} PRIVATE AI_FILE_SORTER_TEST_BUILD=1 WIN32_LEAN_AND_MEAN NOMINMAX)\n            foreach(libName IN LISTS WIN_SYSTEM_LIBS)\n                string(TOUPPER \"${libName}\" upperLib)\n                set(varName \"${upperLib}_LIBRARY\")\n                if(DEFINED ${varName} AND ${varName})\n                    target_link_libraries(${target_name} PRIVATE \"${${varName}}\")\n                else()\n                    target_link_libraries(${target_name} PRIVATE ${libName})\n                endif()\n            endforeach()\n\n            aifs_apply_named_update_mode(${target_name} \"${update_mode}\")\n            aifs_apply_expected_update_mode(${target_name} \"${update_mode}\")\n            aifs_stage_test_runtime(${target_name})\n        endfunction()\n\n        aifs_add_updater_mode_test(ai_file_sorter_updater_notify_only_tests \"NOTIFY_ONLY\")\n        aifs_add_updater_mode_test(ai_file_sorter_updater_disabled_tests \"DISABLED\")\n    endif()\n\n    if(BUILD_TESTING)\n        add_test(NAME ai_file_sorter_tests COMMAND ai_file_sorter_tests)\n        if(WIN32)\n            add_test(NAME ai_file_sorter_updater_notify_only_tests COMMAND ai_file_sorter_updater_notify_only_tests)\n            add_test(NAME ai_file_sorter_updater_disabled_tests COMMAND ai_file_sorter_updater_disabled_tests)\n        endif()\n    endif()\n\n    if(NOT WIN32)\n        add_test(\n            NAME integration_run_all\n            COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_SOURCE_DIR}/../tests/run_all_tests.sh\n            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..\n        )\n        set_tests_properties(integration_run_all PROPERTIES\n            PASS_REGULAR_EXPRESSION \"All tests completed successfully.\"\n        )\n    endif()\nendif()\n"
  },
  {
    "path": "app/Makefile",
    "content": "# Detect platform\nUNAME := $(shell uname | cut -d'-' -f1)\nUNAME_M := $(shell uname -m)\n\nBIN_DIR := ./bin\nOBJ_ROOT := ./obj\nOBJ_DIR := $(OBJ_ROOT)\nSRC_DIR := ./lib\nAPP_NAME ?= AI File Sorter\n\n# Goals that should not require toolchain/dependency discovery.\nNON_BUILD_GOALS := clean\nNEEDS_BUILD_DEPS := 1\nifneq ($(strip $(MAKECMDGOALS)),)\nifeq ($(strip $(filter-out $(NON_BUILD_GOALS),$(MAKECMDGOALS))),)\nNEEDS_BUILD_DEPS := 0\nendif\nendif\n\n# Optional: build llama.cpp with multi-variant CPU backends on macOS.\n# Usage: make LLAMA_MULTI_VARIANT=1\nLLAMA_MULTI_VARIANT ?= 0\nGGML_PRECOMPILED_SUBDIR ?= precompiled\n\nifeq ($(UNAME), Linux)\n    PLATFORM := Linux\n    CXXFLAGS += -DLINUX\n    CXXFLAGS += -DAI_FILE_SORTER_HAS_MTMD\n    TARGET := $(BIN_DIR)/aifilesorter-bin\n    INSTALL_DIR := /usr/local/bin\n    INSTALL_LIB_DIR := /usr/local/lib/aifilesorter\n\tLD_CONF_FILE := /etc/ld.so.conf.d/aifilesorter.conf\n\n    # --- Qt6 setup ---\n    PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null)\n    QT_PACKAGES := Qt6Widgets Qt6Gui Qt6Core\n    QT_CXXFLAGS :=\n    QT_LDFLAGS :=\nifneq ($(strip $(PKG_CONFIG)),)\n    QT_CXXFLAGS := $(shell $(PKG_CONFIG) --cflags $(QT_PACKAGES) 2>/dev/null)\n    QT_LDFLAGS := $(shell $(PKG_CONFIG) --libs $(QT_PACKAGES) 2>/dev/null)\nendif\nifeq ($(strip $(QT_CXXFLAGS)),)\n    QT_INCLUDE_BASE ?= /usr/include/x86_64-linux-gnu/qt6\n    QT_LIB_BASE     ?= /usr/lib/x86_64-linux-gnu\n    CXXFLAGS += -I$(QT_INCLUDE_BASE) -I$(QT_INCLUDE_BASE)/QtCore -I$(QT_INCLUDE_BASE)/QtGui -I$(QT_INCLUDE_BASE)/QtWidgets\n    LDFLAGS  += -L$(QT_LIB_BASE) -lQt6Widgets -lQt6Gui -lQt6Core\nelse\n    CXXFLAGS += $(QT_CXXFLAGS)\n    LDFLAGS  += $(QT_LDFLAGS)\nendif\n\n    # --- Other dependencies ---\n\tLDFLAGS += -lcurl -ljsoncpp -lsqlite3 -lcrypto -lfmt -lspdlog -lssl -lllama -lggml -lggml-base -lmtmd -lX11 -pthread\n\tLDFLAGS += -Wl,-rpath,'$$ORIGIN/../lib/precompiled/cpu/bin' -Wl,-rpath,'$$ORIGIN/../lib/precompiled'\n\tLDFLAGS += -Wl,-rpath-link=./lib/precompiled/cpu/bin -Wl,-rpath-link=./lib/precompiled\n\nelse ifeq ($(UNAME), Darwin)\n    MACOS_ARCH ?= $(UNAME_M)\n    DEFAULT_BREW_PREFIX := $(shell if [ \"$(MACOS_ARCH)\" = \"arm64\" ]; then echo /opt/homebrew; else echo /usr/local; fi)\nifeq ($(origin BREW_PREFIX),undefined)\n    ifeq ($(MACOS_ARCH),x86_64)\n        BREW_PREFIX := /usr/local\n    else\n        BREW_PREFIX := $(shell if command -v brew >/dev/null 2>&1; then brew --prefix; else echo $(DEFAULT_BREW_PREFIX); fi)\n    endif\nendif\n    QT_PREFIX := $(BREW_PREFIX)/opt/qt\n    QTBASE_PREFIX := $(BREW_PREFIX)/opt/qtbase\n    CURL_PREFIX := $(BREW_PREFIX)/opt/curl\n    LIBFFI_PREFIX := $(BREW_PREFIX)/opt/libffi\n    EXPAT_PREFIX := $(BREW_PREFIX)/opt/expat\n    SDKROOT := $(shell xcrun --sdk macosx --show-sdk-path 2>/dev/null)\n    MACOSX_DEPLOYMENT_TARGET ?= 11.0\n    HOMEBREW_OS_PKG_CONFIG_DIRS := $(shell if [ -d \"$(BREW_PREFIX)/Library/Homebrew/os/mac/pkgconfig\" ]; then find \"$(BREW_PREFIX)/Library/Homebrew/os/mac/pkgconfig\" -mindepth 1 -maxdepth 1 -type d | tr '\\n' ':' | sed 's/:$$//'; fi)\n    # Homebrew exposes system pkg-config metadata like libcurl.pc here; libmediainfo depends on it.\n    MACOS_PKG_CONFIG_DIRS := $(BREW_PREFIX)/lib/pkgconfig:$(BREW_PREFIX)/share/pkgconfig:$(LIBFFI_PREFIX)/lib/pkgconfig:$(EXPAT_PREFIX)/lib/pkgconfig:$(QT_PREFIX)/lib/pkgconfig$(if $(strip $(HOMEBREW_OS_PKG_CONFIG_DIRS)),:$(HOMEBREW_OS_PKG_CONFIG_DIRS))\n\n    export MACOSX_DEPLOYMENT_TARGET\n    PATH := $(QTBASE_PREFIX)/share/qt/libexec:$(QT_PREFIX)/bin:$(CURL_PREFIX)/bin:$(PATH)\n    export PATH\n\nifeq ($(MACOS_ARCH),x86_64)\n    export PKG_CONFIG_PATH := $(MACOS_PKG_CONFIG_DIRS)\n    export PKG_CONFIG_LIBDIR := $(MACOS_PKG_CONFIG_DIRS)\n    CPPFLAGS := $(filter-out -I/opt/homebrew/%,$(CPPFLAGS))\n    LDFLAGS := $(filter-out -L/opt/homebrew/% -F/opt/homebrew/%,$(LDFLAGS))\nelse\n    export PKG_CONFIG_PATH := $(MACOS_PKG_CONFIG_DIRS):$(PKG_CONFIG_PATH)\n    export PKG_CONFIG_LIBDIR := $(MACOS_PKG_CONFIG_DIRS)\nendif\n\n    export LDFLAGS += -L$(LIBFFI_PREFIX)/lib\n    export CPPFLAGS += -I$(LIBFFI_PREFIX)/include\n    PLATFORM := MacOS\n    CXXFLAGS += -DMACOS -DENABLE_METAL -DGGML_USE_METAL -DAI_FILE_SORTER_HAS_MTMD -Wno-deprecated -Iinclude/llama -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)\n    ifneq ($(strip $(MACOS_ARCH)),)\n    CXXFLAGS := $(filter-out -arch arm64 -arch x86_64,$(CXXFLAGS))\n    LDFLAGS := $(filter-out -arch arm64 -arch x86_64,$(LDFLAGS))\n    CXXFLAGS += -arch $(MACOS_ARCH)\n    LDFLAGS += -arch $(MACOS_ARCH)\n    endif\n    ifneq ($(strip $(SDKROOT)),)\n    export SDKROOT\n    CXXFLAGS += -isysroot $(SDKROOT) -stdlib=libc++ -I$(SDKROOT)/usr/include/c++/v1\n    LDFLAGS += -isysroot $(SDKROOT)\n    endif\n    LDFLAGS += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)\n    TARGET := $(BIN_DIR)/aifilesorter\n    INSTALL_DIR := /usr/local/bin\n\tINSTALL_LIB_DIR := /usr/local/lib/aifilesorter\n\n    SPDLOG_PATH := $(BREW_PREFIX)/include\n    CXXFLAGS += -I$(SPDLOG_PATH)\n\nifeq ($(origin PKG_CONFIG),undefined)\n    ifeq ($(MACOS_ARCH),x86_64)\n        ifneq ($(wildcard /usr/local/bin/pkg-config),)\n            PKG_CONFIG := /usr/local/bin/pkg-config\n        else\n            PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null)\n        endif\n    else\n        PKG_CONFIG := $(shell command -v pkg-config 2>/dev/null)\n    endif\nendif\nifeq ($(strip $(PKG_CONFIG)),)\nifeq ($(NEEDS_BUILD_DEPS),1)\n$(error pkg-config is required to locate Qt6 frameworks on macOS. Please install it (e.g. brew install pkg-config))\nendif\nendif\n\n    QT_PACKAGES := Qt6Widgets Qt6Gui Qt6Core\n    QT_CXXFLAGS := $(shell PKG_CONFIG_PATH=\"$(PKG_CONFIG_PATH)\" $(PKG_CONFIG) --cflags $(QT_PACKAGES))\n    QT_LDFLAGS := $(shell PKG_CONFIG_PATH=\"$(PKG_CONFIG_PATH)\" $(PKG_CONFIG) --libs $(QT_PACKAGES))\nifeq ($(strip $(QT_CXXFLAGS)),)\nifeq ($(NEEDS_BUILD_DEPS),1)\n$(error Could not retrieve Qt6 flags via pkg-config. Ensure Qt6 is installed (brew install qt) and PKG_CONFIG_PATH includes its pkgconfig directory.)\nendif\nendif\nifeq ($(MACOS_ARCH),x86_64)\nifneq ($(findstring /opt/homebrew,$(QT_CXXFLAGS) $(QT_LDFLAGS)),)\nifeq ($(NEEDS_BUILD_DEPS),1)\n$(error x86_64 build resolved Qt flags from /opt/homebrew. Install x86_64 Qt under /usr/local (Intel Homebrew) or set BREW_PREFIX/PKG_CONFIG accordingly.)\nendif\nendif\nendif\n    CXXFLAGS += $(QT_CXXFLAGS)\n    LDFLAGS += $(QT_LDFLAGS)\n\n    LDFLAGS += -lcurl -ljsoncpp -lsqlite3 -lcrypto -lfmt -lspdlog -lssl -lllama -lggml -lggml-base -lmtmd -lintl -pthread\n\tLDFLAGS += -framework Metal -framework Foundation\n    LDFLAGS += -Wl,-rpath,@loader_path/lib -Wl,-rpath,@loader_path/../lib/$(GGML_PRECOMPILED_SUBDIR)\n    BIN_SUBDIR := $(patsubst ./bin/%,%,$(BIN_DIR))\n    ifneq ($(BIN_SUBDIR),$(BIN_DIR))\n    ifneq ($(strip $(BIN_SUBDIR)),)\n    LDFLAGS += -Wl,-rpath,@loader_path/../../lib -Wl,-rpath,@loader_path/../../lib/$(GGML_PRECOMPILED_SUBDIR)\n    endif\n    endif\n\n\nendif\n\nifeq ($(UNAME), Darwin)\nifneq ($(strip $(MACOS_ARCH)),)\nBIN_SUBDIR := $(patsubst ./bin/%,%,$(BIN_DIR))\nOBJ_VARIANT := $(GGML_PRECOMPILED_SUBDIR)\nifneq ($(BIN_SUBDIR),$(BIN_DIR))\nifneq ($(strip $(BIN_SUBDIR)),)\nOBJ_VARIANT := $(BIN_SUBDIR)\nendif\nendif\nOBJ_DIR := $(OBJ_ROOT)/$(MACOS_ARCH)/$(OBJ_VARIANT)\nendif\nendif\n\n# MediaInfo policy:\n# - Must come from package managers (apt/dnf/pacman/brew/vcpkg)\n# - Vendored submodules / checked-in binaries are rejected\nMEDIAINFO_REQUIRE ?= 1\nMEDIAINFO_ALLOW_VENDORED ?= 0\nMEDIAINFO_PKG ?= libmediainfo\nMEDIAINFO_CFLAGS :=\nMEDIAINFO_LDFLAGS :=\n\nifeq ($(NEEDS_BUILD_DEPS),1)\nMEDIAINFO_BLOCKED_PATHS := ../external/MediaInfoLib ../external/libmediainfo ./lib/mediainfo ./include/MediaInfo\nifneq ($(MEDIAINFO_ALLOW_VENDORED),1)\nifneq ($(strip $(foreach p,$(MEDIAINFO_BLOCKED_PATHS),$(wildcard $(p)))),)\n$(error Vendored MediaInfo content detected ($(MEDIAINFO_BLOCKED_PATHS)). Use package-managed libmediainfo only.)\nendif\nendif\n\nifeq ($(strip $(PKG_CONFIG)),)\nifeq ($(MEDIAINFO_REQUIRE),1)\n$(error pkg-config is required to resolve package-managed libmediainfo. Install pkg-config and libmediainfo (apt/dnf/pacman/brew/vcpkg).)\nendif\nelse\nMEDIAINFO_CFLAGS := $(shell PKG_CONFIG_PATH=\"$(PKG_CONFIG_PATH)\" $(PKG_CONFIG) --cflags $(MEDIAINFO_PKG) 2>/dev/null)\nMEDIAINFO_LDFLAGS := $(shell PKG_CONFIG_PATH=\"$(PKG_CONFIG_PATH)\" $(PKG_CONFIG) --libs $(MEDIAINFO_PKG) 2>/dev/null)\nendif\n\nifeq ($(MEDIAINFO_REQUIRE),1)\nifeq ($(strip $(MEDIAINFO_LDFLAGS)),)\n$(error libmediainfo not found via pkg-config. Install it through apt/dnf/pacman/brew/vcpkg. Vendored copies are not supported.)\nendif\nendif\nendif\n\nifneq ($(strip $(MEDIAINFO_LDFLAGS)),)\nCXXFLAGS += -DAI_FILE_SORTER_USE_MEDIAINFOLIB $(MEDIAINFO_CFLAGS)\nLDFLAGS += $(MEDIAINFO_LDFLAGS)\nendif\n\nWRAPPED_BINARY := $(notdir $(TARGET))\n\n# Compiler and flags\nifeq ($(UNAME), Darwin)\nCXX := clang++\nelse\nCXX := g++\nendif\nCXXFLAGS += -std=c++20 -Wall -O2 -fPIC '-DAI_FILE_SORTER_APP_NAME=\"$(APP_NAME)\"' '-DAI_FILE_SORTER_GGML_SUBDIR=\"$(GGML_PRECOMPILED_SUBDIR)\"'\nCXX_VERSION_INFO := $(shell $(CXX) --version 2>/dev/null)\n# Suppress GCC-only diagnostics; clang (macOS) does not support some of them\nifneq (,$(findstring clang,$(CXX_VERSION_INFO)))\nCXXFLAGS += -Wno-array-bounds\nelse\nCXXFLAGS += -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread\nendif\nINCLUDE_DIRS = -I./include -I./include/external/llama.cpp/include -I./include/external/llama.cpp/ggml/include -I./include/external/llama.cpp/tools/mtmd\nLIB_DIRS =\nifeq ($(UNAME), Linux)\nLIB_DIRS += -L./lib/precompiled/cpu/bin -L./lib/precompiled\nelse\nLIB_DIRS += -L./lib/$(GGML_PRECOMPILED_SUBDIR)\nendif\nifeq ($(UNAME), Darwin)\nLIB_DIRS += -L$(BREW_PREFIX)/lib\nendif\n\n# --- Vendored document analysis dependencies ---\nDOC_DEPS_DIR := ../external\nLIBZIP_DIR := $(DOC_DEPS_DIR)/libzip\nPUGIXML_DIR := $(DOC_DEPS_DIR)/pugixml\nPDFIUM_DIR := $(DOC_DEPS_DIR)/pdfium\n\nLIBZIP_CMAKE := $(LIBZIP_DIR)/CMakeLists.txt\nLIBZIP_BUILD_DIR := $(LIBZIP_DIR)/build\nLIBZIP_LIB := $(LIBZIP_BUILD_DIR)/lib/libzip.a\nLIBZIP_CONF := $(LIBZIP_BUILD_DIR)/zipconf.h\nLIBZIP_CMAKE_ARGS :=\nifeq ($(UNAME), Darwin)\nifneq ($(strip $(MACOS_ARCH)),)\nLIBZIP_BUILD_DIR := $(LIBZIP_DIR)/build-$(MACOS_ARCH)\nLIBZIP_LIB := $(LIBZIP_BUILD_DIR)/lib/libzip.a\nLIBZIP_CMAKE_ARGS += -DCMAKE_OSX_ARCHITECTURES=$(MACOS_ARCH)\nendif\nendif\n\nPUGIXML_HDR := $(PUGIXML_DIR)/src/pugixml.hpp\n\nPDFIUM_PLATFORM_DIR :=\nPDFIUM_INC :=\nPDFIUM_LIB :=\nPDFIUM_STAGED_LIB :=\nPDFIUM_STAGED_STAMP :=\nifeq ($(UNAME), Linux)\nPDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/linux-x64\nPDFIUM_INC := $(PDFIUM_PLATFORM_DIR)/include\nPDFIUM_LIB := $(PDFIUM_PLATFORM_DIR)/lib/libpdfium.so\nPDFIUM_STAGED_LIB := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libpdfium.so\nPDFIUM_STAGED_STAMP := $(PDFIUM_STAGED_LIB).ready\nendif\nifeq ($(UNAME), Darwin)\nPDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/macos-arm64\nifeq ($(MACOS_ARCH),x86_64)\nPDFIUM_PLATFORM_DIR := $(PDFIUM_DIR)/macos-x64\nendif\nPDFIUM_INC := $(PDFIUM_PLATFORM_DIR)/include\nPDFIUM_LIB := $(PDFIUM_PLATFORM_DIR)/lib/libpdfium.dylib\nPDFIUM_STAGED_LIB := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libpdfium.dylib\nPDFIUM_STAGED_STAMP := $(PDFIUM_STAGED_LIB).ready\nendif\n\nDOC_LIBS :=\nDOC_DEPS_HEADERS :=\nDOC_RUNTIME_DEPS :=\nifneq ($(wildcard $(PUGIXML_HDR)),)\nCXXFLAGS += -DPUGIXML_NO_EXCEPTIONS\nCXXFLAGS += -DAI_FILE_SORTER_USE_PUGIXML\nINCLUDE_DIRS += -I$(PUGIXML_DIR)/src\nendif\nifneq ($(wildcard $(LIBZIP_CMAKE)),)\nCXXFLAGS += -DAI_FILE_SORTER_USE_LIBZIP\nINCLUDE_DIRS += -I$(LIBZIP_DIR)/lib -I$(LIBZIP_BUILD_DIR)\nLDFLAGS += -lz\nDOC_LIBS += $(LIBZIP_LIB)\nDOC_DEPS_HEADERS += $(LIBZIP_CONF)\nendif\nifneq ($(wildcard $(PDFIUM_LIB)),)\nCXXFLAGS += -DAI_FILE_SORTER_USE_PDFIUM\nINCLUDE_DIRS += -I$(PDFIUM_INC)\nDOC_LIBS += $(PDFIUM_STAGED_LIB)\nDOC_RUNTIME_DEPS += $(PDFIUM_STAGED_STAMP)\nendif\n\n# Enable mtmd progress callback only when the linked libmtmd provides it.\nMTMD_PROGRESS_CALLBACK ?= auto\nMTMD_LIB_CANDIDATES :=\nifeq ($(UNAME), Linux)\nMTMD_LIB_CANDIDATES := ./lib/precompiled/cpu/bin/libmtmd.so ./lib/precompiled/libmtmd.so\nendif\nifeq ($(UNAME), Darwin)\nMTMD_LIB_CANDIDATES := ./lib/$(GGML_PRECOMPILED_SUBDIR)/libmtmd.dylib $(BREW_PREFIX)/lib/libmtmd.dylib\nendif\nifeq ($(MTMD_PROGRESS_CALLBACK),auto)\nMTMD_PROGRESS_CALLBACK := $(shell \\\n\tif command -v nm >/dev/null 2>&1; then \\\n\t\tfor lib in $(MTMD_LIB_CANDIDATES); do \\\n\t\t\tif [ -e \"$$lib\" ] && nm -D --defined-only \"$$lib\" 2>/dev/null | grep -q \"mtmd_helper_set_progress_callback\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\t\tif [ -e \"$$lib\" ] && nm -g \"$$lib\" 2>/dev/null | grep -q \"[Tt] _mtmd_helper_set_progress_callback\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\telif command -v objdump >/dev/null 2>&1; then \\\n\t\tfor lib in $(MTMD_LIB_CANDIDATES); do \\\n\t\t\tif [ -e \"$$lib\" ] && objdump -T \"$$lib\" 2>/dev/null | grep -q \"mtmd_helper_set_progress_callback\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\tfi; \\\n\techo 0)\nendif\nifeq ($(MTMD_PROGRESS_CALLBACK),1)\nCXXFLAGS += -DAI_FILE_SORTER_MTMD_PROGRESS_CALLBACK\nelse\nCXXFLAGS += -UAI_FILE_SORTER_MTMD_PROGRESS_CALLBACK\nendif\n\n# Enable mtmd log callback only when the linked libmtmd provides it.\nMTMD_LOG_CALLBACK ?= auto\nifeq ($(MTMD_LOG_CALLBACK),auto)\nMTMD_LOG_CALLBACK := $(shell \\\n\tif command -v nm >/dev/null 2>&1; then \\\n\t\tfor lib in $(MTMD_LIB_CANDIDATES); do \\\n\t\t\tif [ -e \"$$lib\" ] && nm -D --defined-only \"$$lib\" 2>/dev/null | grep -q \"mtmd_helper_log_set\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\t\tif [ -e \"$$lib\" ] && nm -g \"$$lib\" 2>/dev/null | grep -q \"[Tt] _mtmd_helper_log_set\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\telif command -v objdump >/dev/null 2>&1; then \\\n\t\tfor lib in $(MTMD_LIB_CANDIDATES); do \\\n\t\t\tif [ -e \"$$lib\" ] && objdump -T \"$$lib\" 2>/dev/null | grep -q \"mtmd_helper_log_set\"; then \\\n\t\t\t\techo 1; exit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\tfi; \\\n\techo 0)\nendif\nifeq ($(MTMD_LOG_CALLBACK),1)\nCXXFLAGS += -DAI_FILE_SORTER_MTMD_LOG_CALLBACK\nelse\nCXXFLAGS += -UAI_FILE_SORTER_MTMD_LOG_CALLBACK\nendif\n\nQRC_FILE := resources/app.qrc\nQRC_CPP := $(OBJ_DIR)/qrc_app.cpp\nQRC_OBJ := $(OBJ_DIR)/qrc_app.o\nQRC_DIR := $(dir $(QRC_FILE))\nQRC_RESOURCES := $(shell sed -n -E 's|.*<file>([^<]*)</file>.*|\\1|p' $(QRC_FILE))\nQRC_RESOURCES := $(addprefix $(QRC_DIR),$(QRC_RESOURCES))\nMAKEFILE_SELF := $(lastword $(MAKEFILE_LIST))\nTS_DIR := resources/i18n\nTS_FILES := \\\n\t$(TS_DIR)/aifilesorter_fr.ts \\\n\t$(TS_DIR)/aifilesorter_de.ts \\\n\t$(TS_DIR)/aifilesorter_it.ts \\\n\t$(TS_DIR)/aifilesorter_es.ts \\\n\t$(TS_DIR)/aifilesorter_nl.ts \\\n\t$(TS_DIR)/aifilesorter_tr.ts \\\n\t$(TS_DIR)/aifilesorter_ko.ts\nQM_DIR := $(OBJ_DIR)/i18n\nQM_FILES := $(patsubst $(TS_DIR)/%.ts,$(QM_DIR)/%.qm,$(TS_FILES))\nTRANSLATIONS_QRC := $(OBJ_DIR)/translations.qrc\nTRANSLATIONS_QRC_CPP := $(OBJ_DIR)/qrc_translations.cpp\nTRANSLATIONS_QRC_OBJ := $(OBJ_DIR)/qrc_translations.o\nQMAKE6 := $(shell \\\n\tif command -v qmake6 >/dev/null 2>&1; then \\\n\t\tcommand -v qmake6; \\\n\telif [ -x /usr/lib/qt6/bin/qmake6 ]; then \\\n\t\tprintf '%s\\n' /usr/lib/qt6/bin/qmake6; \\\n\tfi)\nQTPATHS6 := $(shell \\\n\tif command -v qtpaths6 >/dev/null 2>&1; then \\\n\t\tcommand -v qtpaths6; \\\n\telif [ -x /usr/lib/qt6/bin/qtpaths6 ]; then \\\n\t\tprintf '%s\\n' /usr/lib/qt6/bin/qtpaths6; \\\n\tfi)\n\nifndef RCC\nRCC := $(shell command -v qt6-rcc 2>/dev/null)\nifeq ($(strip $(RCC)),)\nRCC := $(wildcard /usr/lib/qt6/libexec/rcc)\nendif\nifeq ($(strip $(RCC)),)\nRCC := $(shell command -v rcc 2>/dev/null)\nendif\nifeq ($(strip $(RCC)),)\nRCC := $(wildcard /opt/homebrew/opt/qt/bin/qt6-rcc)\nendif\nifeq ($(strip $(RCC)),)\nRCC := $(wildcard /usr/lib/qt6/libexec/rcc)\nendif\nifeq ($(strip $(RCC)),)\nRCC := $(wildcard /opt/homebrew/opt/qtbase/share/qt/libexec/rcc)\nendif\nifeq ($(strip $(RCC)),)\nRCC := $(wildcard /usr/local/opt/qtbase/share/qt/libexec/rcc)\nendif\nendif\nifeq ($(strip $(RCC)),)\nifeq ($(NEEDS_BUILD_DEPS),1)\n$(error Could not find Qt resource compiler (qt6-rcc or rcc))\nendif\nendif\n\nifndef LRELEASE\nLRELEASE := $(shell \\\n\tfor candidate in lrelease6 lrelease-qt6; do \\\n\t\tif command -v \"$$candidate\" >/dev/null 2>&1; then \\\n\t\t\tcommand -v \"$$candidate\"; \\\n\t\t\texit 0; \\\n\t\tfi; \\\n\tdone; \\\n\tif [ -n \"$(QTPATHS6)\" ]; then \\\n\t\tfor qt_host_dir in \"$$($(QTPATHS6) --query QT_HOST_LIBEXECS 2>/dev/null)\" \"$$($(QTPATHS6) --query QT_HOST_BINS 2>/dev/null)\"; do \\\n\t\t\tif [ -n \"$$qt_host_dir\" ] && [ -x \"$$qt_host_dir/lrelease\" ]; then \\\n\t\t\t\tprintf '%s\\n' \"$$qt_host_dir/lrelease\"; \\\n\t\t\t\texit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\tfi; \\\n\tif [ -n \"$(QMAKE6)\" ]; then \\\n\t\tfor qt_host_dir in \"$$($(QMAKE6) -query QT_HOST_LIBEXECS 2>/dev/null)\" \"$$($(QMAKE6) -query QT_HOST_BINS 2>/dev/null)\" \"$$($(QMAKE6) -query QT_INSTALL_BINS 2>/dev/null)\"; do \\\n\t\t\tif [ -n \"$$qt_host_dir\" ] && [ -x \"$$qt_host_dir/lrelease\" ]; then \\\n\t\t\t\tprintf '%s\\n' \"$$qt_host_dir/lrelease\"; \\\n\t\t\t\texit 0; \\\n\t\t\tfi; \\\n\t\tdone; \\\n\tfi; \\\n\tfor candidate in \\\n\t\t/usr/lib/qt6/libexec/lrelease \\\n\t\t/usr/lib/qt6/bin/lrelease \\\n\t\t/opt/homebrew/bin/lrelease \\\n\t\t/opt/homebrew/opt/qt/share/qt/libexec/lrelease \\\n\t\t/opt/homebrew/opt/qtbase/share/qt/libexec/lrelease \\\n\t\t/usr/local/opt/qtbase/share/qt/libexec/lrelease; do \\\n\t\tif [ -x \"$$candidate\" ]; then \\\n\t\t\tprintf '%s\\n' \"$$candidate\"; \\\n\t\t\texit 0; \\\n\t\tfi; \\\n\tdone; \\\n\tif command -v lrelease >/dev/null 2>&1; then \\\n\t\tcandidate=\"$$(command -v lrelease)\"; \\\n\t\tif \"$$candidate\" -version 2>&1 | grep -Eq 'Qt[^0-9]*6|version 6'; then \\\n\t\t\tprintf '%s\\n' \"$$candidate\"; \\\n\t\tfi; \\\n\tfi)\nendif\nifeq ($(strip $(LRELEASE)),)\nifeq ($(NEEDS_BUILD_DEPS),1)\n$(error Could not find a Qt 6 translation compiler (install qt6-l10n-tools / qt6-tools-dev-tools, or set LRELEASE=/path/to/qt6/lrelease))\nendif\nendif\n\n# Source files\nSRCS = main.cpp $(wildcard $(SRC_DIR)/*.cpp)\nOBJS = $(patsubst %.cpp, $(OBJ_DIR)/%.o, $(notdir $(SRCS)))\nDEPS = $(OBJS:.o=.d) $(QRC_OBJ:.o=.d) $(TRANSLATIONS_QRC_OBJ:.o=.d)\nBUILD_CONFIG_STAMP := $(OBJ_DIR)/.build-config\n\nPRECOMPILED_LLAMA :=\nifeq ($(UNAME), Darwin)\nifneq ($(LLAMA_MULTI_VARIANT),0)\nPRECOMPILED_LLAMA := precompiled_llama\nendif\nendif\n\n.PHONY: all clean install uninstall doc_runtime_libs precompiled_llama MACOS_LLAMA_M1 MACOS_LLAMA_M2 MACOS_LLAMA_INTEL\n\n# Main rules\nall: $(PRECOMPILED_LLAMA) doc_runtime_libs $(TARGET)\n\t@printf \"\\nFinished building AI File Sorter for %s\\n\" \"$(PLATFORM)\"\n\n$(TARGET): $(OBJS) $(QRC_OBJ) $(TRANSLATIONS_QRC_OBJ) $(DOC_LIBS) | doc_runtime_libs $(DOC_RUNTIME_DEPS)\n\tmkdir -p $(BIN_DIR)\n\t$(CXX) $(CXXFLAGS) -o $@ $^ $(LIB_DIRS) $(LDFLAGS)\nifeq ($(PLATFORM), Linux)\n\t@$(MAKE) create_run_wrapper\nendif\n\n$(BUILD_CONFIG_STAMP): Makefile\n\tmkdir -p $(OBJ_DIR)\n\t@tmp=\"$(BUILD_CONFIG_STAMP).tmp.$$\"; \\\n\tprintf '%s\\n' \\\n\t\t'CXX=$(CXX)' \\\n\t\t'CXXFLAGS=$(CXXFLAGS)' \\\n\t\t'INCLUDE_DIRS=$(INCLUDE_DIRS)' \\\n\t\t'APP_NAME=$(APP_NAME)' \\\n\t\t'GGML_PRECOMPILED_SUBDIR=$(GGML_PRECOMPILED_SUBDIR)' \\\n\t\t'MACOS_ARCH=$(MACOS_ARCH)' \\\n\t\t'BIN_DIR=$(BIN_DIR)' \\\n\t\t> \"$$tmp\"; \\\n\tif [ ! -f \"$@\" ] || ! cmp -s \"$$tmp\" \"$@\"; then \\\n\t\tmv \"$$tmp\" \"$@\"; \\\n\telse \\\n\t\trm -f \"$$tmp\"; \\\n\tfi\n\n$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP)\n\tmkdir -p $(OBJ_DIR)\n\t$(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@\n\n$(LIBZIP_CONF): $(LIBZIP_LIB)\n\n$(LIBZIP_LIB):\n\t@echo \"Building libzip (vendored)...\"\n\tmkdir -p $(LIBZIP_BUILD_DIR)\n\tLDFLAGS= cmake -S $(LIBZIP_DIR) -B $(LIBZIP_BUILD_DIR) \\\n\t\t$(LIBZIP_CMAKE_ARGS) \\\n\t\t-DCMAKE_EXE_LINKER_FLAGS= \\\n\t\t-DCMAKE_SHARED_LINKER_FLAGS= \\\n\t\t-DCMAKE_MODULE_LINKER_FLAGS= \\\n\t\t-DBUILD_SHARED_LIBS=OFF \\\n\t\t-DENABLE_BZIP2=OFF \\\n\t\t-DENABLE_LZMA=OFF \\\n\t\t-DENABLE_ZSTD=OFF \\\n\t\t-DENABLE_OPENSSL=OFF \\\n\t\t-DENABLE_GNUTLS=OFF \\\n\t\t-DENABLE_MBEDTLS=OFF \\\n\t\t-DENABLE_COMMONCRYPTO=OFF \\\n\t\t-DENABLE_WINDOWS_CRYPTO=OFF\n\tLDFLAGS= cmake --build $(LIBZIP_BUILD_DIR)\n\ndoc_runtime_libs:\n\nifneq ($(wildcard $(PDFIUM_LIB)),)\n$(PDFIUM_STAGED_LIB): $(PDFIUM_LIB)\n\t@echo \"Staging PDFium runtime library...\"\n\tmkdir -p $(dir $(PDFIUM_STAGED_LIB))\n\tcp $(PDFIUM_LIB) $(PDFIUM_STAGED_LIB)\nifeq ($(UNAME), Darwin)\n\tchmod u+w $(PDFIUM_STAGED_LIB) 2>/dev/null || true\n\tinstall_name_tool -id @rpath/libpdfium.dylib $(PDFIUM_STAGED_LIB)\nendif\n\n$(PDFIUM_STAGED_STAMP): $(PDFIUM_STAGED_LIB)\n\ttouch $@\n\ndoc_runtime_libs: $(PDFIUM_STAGED_STAMP)\nendif\n\nprecompiled_llama:\nifeq ($(UNAME), Darwin)\n\t@echo \"Checking llama.cpp precompiled libraries (multi-variant=$(LLAMA_MULTI_VARIANT))...\"\n\t@if [ -f \"./lib/$(GGML_PRECOMPILED_SUBDIR)/libllama.dylib\" ]; then \\\n\t\techo \"Using existing precompiled libs in ./lib/$(GGML_PRECOMPILED_SUBDIR)\"; \\\n\telse \\\n\t\techo \"Building llama.cpp precompiled libraries (multi-variant=$(LLAMA_MULTI_VARIANT))...\"; \\\n\t\tLLAMA_MACOS_MULTI_VARIANT=$(LLAMA_MULTI_VARIANT) LLAMA_PRECOMPILED_DIR=./lib/$(GGML_PRECOMPILED_SUBDIR) ./scripts/build_llama_macos.sh; \\\n\tfi\nelse\n\t@echo \"precompiled_llama is only supported on macOS.\"\nendif\n\nMACOS_LLAMA_M1:\nifeq ($(UNAME), Darwin)\n\t@echo \"Checking llama.cpp for M1-safe multi-variant CPU backends...\"\n\t@if [ -f \"./lib/precompiled-m1/libllama.dylib\" ]; then \\\n\t\techo \"Using existing precompiled libs in ./lib/precompiled-m1\"; \\\n\telse \\\n\t\techo \"Building llama.cpp for M1-safe multi-variant CPU backends...\"; \\\n\t\tLLAMA_MACOS_MULTI_VARIANT=1 LLAMA_PRECOMPILED_DIR=./lib/precompiled-m1 ./scripts/build_llama_macos.sh; \\\n\tfi\n\t$(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-m1 APP_NAME=\"AI File Sorter for Mac M1\" BIN_DIR=./bin/m1 all\nelse\n\t@echo \"MACOS_LLAMA_M1 is only supported on macOS.\"\nendif\n\nMACOS_LLAMA_M2:\nifeq ($(UNAME), Darwin)\n\t@echo \"Checking llama.cpp for native (fast) Apple Silicon backends...\"\n\t@if [ -f \"./lib/precompiled-m2/libllama.dylib\" ]; then \\\n\t\techo \"Using existing precompiled libs in ./lib/precompiled-m2\"; \\\n\telse \\\n\t\techo \"Building llama.cpp for native (fast) Apple Silicon backends...\"; \\\n\t\tLLAMA_MACOS_MULTI_VARIANT=0 LLAMA_PRECOMPILED_DIR=./lib/precompiled-m2 ./scripts/build_llama_macos.sh; \\\n\tfi\n\t$(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-m2 APP_NAME=\"AI File Sorter for Mac M2-M5\" BIN_DIR=./bin/m2 all\nelse\n\t@echo \"MACOS_LLAMA_M2 is only supported on macOS.\"\nendif\n\nMACOS_LLAMA_INTEL:\nifeq ($(UNAME), Darwin)\n\t@echo \"Checking llama.cpp for Intel (x86_64) macOS backends...\"\n\t@if [ -f \"./lib/precompiled-intel/libllama.dylib\" ]; then \\\n\t\techo \"Using existing precompiled libs in ./lib/precompiled-intel\"; \\\n\telse \\\n\t\techo \"Building llama.cpp for Intel (x86_64) macOS backends...\"; \\\n\t\tLLAMA_MACOS_ARCH=x86_64 LLAMA_MACOS_ENABLE_METAL=1 LLAMA_MACOS_MULTI_VARIANT=0 LLAMA_PRECOMPILED_DIR=./lib/precompiled-intel ./scripts/build_llama_macos.sh; \\\n\tfi\n\t$(MAKE) LLAMA_MULTI_VARIANT=0 GGML_PRECOMPILED_SUBDIR=precompiled-intel APP_NAME=\"AI File Sorter for Mac Intel\" BIN_DIR=./bin/intel MACOS_ARCH=x86_64 all\nelse\n\t@echo \"MACOS_LLAMA_INTEL is only supported on macOS.\"\nendif\n\n$(OBJ_DIR)/main.o: main.cpp $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP)\n\tmkdir -p $(OBJ_DIR)\n\t$(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@\n\n$(QRC_CPP): $(QRC_FILE) $(QRC_RESOURCES) $(MAKEFILE_SELF)\n\tmkdir -p $(OBJ_DIR)\n\t$(RCC) -name app -o $@ $<\n\n$(QRC_OBJ): $(QRC_CPP) $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@\n\n$(QM_DIR)/%.qm: $(TS_DIR)/%.ts\n\tmkdir -p $(dir $@)\n\t$(LRELEASE) $< -qm $@\n\n$(TRANSLATIONS_QRC): $(QM_FILES)\n\tmkdir -p $(OBJ_DIR)\n\t@tmp=\"$@.tmp\"; \\\n\tprintf '%s\\n' '<!DOCTYPE RCC><RCC version=\"1.0\">' '  <qresource prefix=\"/i18n\">' > \"$$tmp\"; \\\n\tfor qm in $(QM_FILES); do \\\n\t\tprintf '    <file alias=\"%s\">i18n/%s</file>\\n' \"$$(basename \"$$qm\")\" \"$$(basename \"$$qm\")\" >> \"$$tmp\"; \\\n\tdone; \\\n\tprintf '%s\\n' '  </qresource>' '</RCC>' >> \"$$tmp\"; \\\n\tmv \"$$tmp\" \"$@\"\n\n$(TRANSLATIONS_QRC_CPP): $(TRANSLATIONS_QRC) $(QM_FILES) $(MAKEFILE_SELF)\n\tmkdir -p $(OBJ_DIR)\n\t$(RCC) -name translations -o $@ $<\n\n$(TRANSLATIONS_QRC_OBJ): $(TRANSLATIONS_QRC_CPP) $(DOC_DEPS_HEADERS) $(BUILD_CONFIG_STAMP)\n\t$(CXX) $(CXXFLAGS) $(INCLUDE_DIRS) -MMD -MP -MF $(@:.o=.d) -c $< -o $@\n\nclean:\n\trm -rf $(OBJ_ROOT) $(BIN_DIR)\n\ncreate_run_wrapper:\n\t@mkdir -p $(BIN_DIR)\n\t@python3 scripts/gen_run_wrapper.py \\\n\t\t--mode dev \\\n\t\t--binary '$(WRAPPED_BINARY)' \\\n\t\t--output '$(BIN_DIR)/run_aifilesorter.sh'\n\t@chmod 755 $(BIN_DIR)/run_aifilesorter.sh\n\ninstall: $(TARGET)\nifeq ($(PLATFORM), Linux)\n\t@echo \"Installing runtime payload into $(INSTALL_LIB_DIR)...\"\n\tmkdir -p $(INSTALL_LIB_DIR)/bin\n\tmkdir -p $(INSTALL_LIB_DIR)/lib\n\tcp $(TARGET) $(INSTALL_LIB_DIR)/bin/$(WRAPPED_BINARY)\n\trm -rf $(INSTALL_LIB_DIR)/lib/$(GGML_PRECOMPILED_SUBDIR)\n\tcp -a lib/$(GGML_PRECOMPILED_SUBDIR) $(INSTALL_LIB_DIR)/lib/\n\tif [ -f ../external/pdfium/linux-x64/lib/libpdfium.so ]; then \\\n\t\tcp ../external/pdfium/linux-x64/lib/libpdfium.so $(INSTALL_LIB_DIR)/lib/$(GGML_PRECOMPILED_SUBDIR)/; \\\n\tfi\n\tif [ -f resources/certs/cacert.pem ]; then \\\n\t\tmkdir -p $(INSTALL_LIB_DIR)/certs; \\\n\t\tcp resources/certs/cacert.pem $(INSTALL_LIB_DIR)/certs/cacert.pem; \\\n\tfi\n\t@echo \"Installing launcher script to $(INSTALL_DIR)...\"\n\tmkdir -p $(INSTALL_DIR)\n\t@python3 scripts/gen_run_wrapper.py \\\n\t\t--mode install \\\n\t\t--install-app-dir '$(INSTALL_LIB_DIR)' \\\n\t\t--binary '$(WRAPPED_BINARY)' \\\n\t\t--output '$(INSTALL_DIR)/run_aifilesorter.sh'\n\tchmod 755 $(INSTALL_DIR)/run_aifilesorter.sh\n\tln -sf $(INSTALL_DIR)/run_aifilesorter.sh $(INSTALL_DIR)/aifilesorter\n\t@echo \"Installation complete.\"\n\nelse ifeq ($(PLATFORM), MacOS)\n\t@echo \"Installing binary to $(INSTALL_DIR)...\"\n\tmkdir -p $(INSTALL_DIR)\n\tcp $(TARGET) $(INSTALL_DIR)/aifilesorter\n\n\t@echo \"Installing libraries to $(INSTALL_LIB_DIR)...\"\n\tmkdir -p $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-base.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-blas.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-cpu.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml-metal.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libggml.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libmtmd.dylib $(INSTALL_LIB_DIR)\n\tcp lib/$(GGML_PRECOMPILED_SUBDIR)/libllama.dylib $(INSTALL_LIB_DIR)\n\tif [ -n \"$(PDFIUM_LIB)\" ] && [ -f \"$(PDFIUM_LIB)\" ]; then \\\n\t\tcp \"$(PDFIUM_LIB)\" $(INSTALL_LIB_DIR); \\\n\tfi\n\n\tinstall_name_tool -add_rpath $(INSTALL_LIB_DIR) $(INSTALL_DIR)/aifilesorter\n\n\t@echo \"macOS installation complete.\"\nendif\n\nuninstall:\nifeq ($(PLATFORM), Linux)\n\t@echo \"Uninstalling aifilesorter binary and libraries...\"\n\n\t@echo \"Removing binary from /usr/local/bin...\"\n\trm -f /usr/local/bin/aifilesorter\n\n\t@echo \"Removing libraries from /usr/local/lib/aifilesorter...\"\n\trm -rf /usr/local/lib/aifilesorter\n\n\t@echo \"Removing ld config file...\"\n\trm -f /etc/ld.so.conf.d/aifilesorter.conf\n\n\t@echo \"Running ldconfig...\"\n\tldconfig\n\n\t@echo \"Core uninstallation complete.\"\n\n\t@bash -c 'read -p \"Do you also want to delete the downloaded local LLM models in ~/.local/share/aifilesorter/llms/? [y/N] \" ans; \\\n\t\tif [ \"$$ans\" = \"y\" ] || [ \"$$ans\" = \"Y\" ]; then \\\n\t\t\techo \"Deleting ~/.local/share/aifilesorter/llms/...\"; \\\n\t\t\trm -rf \"$$HOME/.local/share/aifilesorter/llms\"; \\\n\t\telse \\\n\t\t\techo \"Keeping downloaded models.\"; \\\n\t\tfi'\n\n\nelse ifeq ($(PLATFORM), MacOS)\n\t@echo \"Uninstalling aifilesorter binary and libraries on macOS...\"\n\n\t@echo \"Removing binary from $(INSTALL_DIR)...\"\n\trm -f $(INSTALL_DIR)/aifilesorter\n\n\t@echo \"Removing installed libraries...\"\n\trm -rf $(INSTALL_LIB_DIR)\n\n\t@echo \"Core uninstallation complete.\"\n\n\t@read -p \"Do you also want to delete the downloaded local LLM models in ~/Library/Application\\ Support/aifilesorter/llms/? [y/N] \" ans; \\\n\tif [ \"$$ans\" = \"y\" ] || [ \"$$ans\" = \"Y\" ]; then \\\n\t\techo \"Deleting ~/Library/Application Support/aifilesorter/llms/...\"; \\\n\t\trm -rf \"$$HOME/Library/Application Support/aifilesorter/llms\"; \\\n\telse \\\n\t\techo \"Keeping downloaded models.\"; \\\n\tfi\nendif\n\n-include $(DEPS)\n"
  },
  {
    "path": "app/build_windows.ps1",
    "content": "param(\n    [string]$VcpkgRoot,\n    [ValidateSet(\"Debug\", \"Release\")]\n    [string]$Configuration = \"Release\",\n    [switch]$Clean,\n    [string]$Generator,\n    [switch]$SkipDeploy,\n    [switch]$BuildTests,\n    [switch]$RunTests,\n    [ValidateRange(1, 512)]\n    [int]$Parallel = [System.Environment]::ProcessorCount,\n    [ValidateSet(\"Standard\", \"MsStore\", \"Standalone\")]\n    [string[]]$Variants = @(\"Standard\", \"MsStore\", \"Standalone\")\n)\n\n$ErrorActionPreference = \"Stop\"\n\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition\n$appDir = $scriptDir\n$llamaDir = Join-Path $appDir \"include/external/llama.cpp\"\n$legacySharedVcpkgInstalledDir = Join-Path $appDir \"build-windows\\\\vcpkg_installed\"\n$dedicatedSharedVcpkgInstalledDir = Join-Path $appDir \"build-windows-vcpkg_installed\"\n$sharedVcpkgInstalledDir = if (Test-Path $legacySharedVcpkgInstalledDir) {\n    $legacySharedVcpkgInstalledDir\n} else {\n    $dedicatedSharedVcpkgInstalledDir\n}\n\n$variantDefinitions = @{\n    Standard = [pscustomobject]@{\n        Name = \"Standard\"\n        BuildDir = (Join-Path $appDir \"build-windows\")\n        UpdateMode = \"AUTO_INSTALL\"\n        Description = \"Auto-install updates\"\n    }\n    MsStore = [pscustomobject]@{\n        Name = \"MsStore\"\n        BuildDir = (Join-Path $appDir \"build-windows-store\")\n        UpdateMode = \"DISABLED\"\n        Description = \"No update checks\"\n    }\n    Standalone = [pscustomobject]@{\n        Name = \"Standalone\"\n        BuildDir = (Join-Path $appDir \"build-windows-standalone\")\n        UpdateMode = \"NOTIFY_ONLY\"\n        Description = \"Notification-only updates\"\n    }\n}\n\nfunction Resolve-VcpkgRootFromPath {\n    param([string]$Path)\n\n    if (-not $Path) { return $null }\n\n    try {\n        $candidate = (Resolve-Path $Path -ErrorAction Stop).Path\n    } catch {\n        return $null\n    }\n\n    if ((Get-Item $candidate).PSIsContainer) {\n        $dir = $candidate\n    } else {\n        $dir = (Get-Item $candidate).Directory.FullName\n    }\n\n    while ($dir -and (Test-Path $dir)) {\n        $toolchain = Join-Path $dir \"scripts/buildsystems/vcpkg.cmake\"\n        if (Test-Path $toolchain) {\n            return $dir\n        }\n\n        $parent = Split-Path -Parent $dir\n        if (-not $parent -or $parent -eq $dir) {\n            break\n        }\n        $dir = $parent\n    }\n\n    return $null\n}\n\nfunction Copy-VcpkgRuntimeDlls {\n    param(\n        [string[]]$SourceDirectories,\n        [string]$Destination\n    )\n\n    $copied = @()\n    foreach ($dir in $SourceDirectories) {\n        if (-not $dir) { continue }\n        if (-not (Test-Path $dir)) { continue }\n\n        $dlls = Get-ChildItem -Path $dir -Filter \"*.dll\" -File -ErrorAction SilentlyContinue |\n            Where-Object { $_.Name -notmatch '^Qt6' }\n\n        foreach ($dll in $dlls) {\n            Copy-Item $dll.FullName -Destination $Destination -Force\n            $copied += $dll.Name\n        }\n    }\n\n    return $copied | Sort-Object -Unique\n}\n\nfunction Get-ConfigureArguments {\n    param(\n        [pscustomobject]$Variant,\n        [string]$ToolchainFile,\n        [switch]$EnableTests,\n        [int]$CMakeMajor,\n        [int]$CMakeMinor\n    )\n\n    $configureArgs = @(\"-S\", $appDir, \"-B\", $Variant.BuildDir)\n    $configureArgs += @(\"-G\", $Generator)\n    $configureArgs += \"-DCMAKE_TOOLCHAIN_FILE=$ToolchainFile\"\n    $configureArgs += \"-DVCPKG_TARGET_TRIPLET=x64-windows\"\n    $configureArgs += \"-DVCPKG_MANIFEST_DIR=$appDir\"\n    $configureArgs += \"-DVCPKG_INSTALLED_DIR=$sharedVcpkgInstalledDir\"\n    $configureArgs += \"-DAI_FILE_SORTER_UPDATE_MODE=$($Variant.UpdateMode)\"\n\n    if ($EnableTests) {\n        $configureArgs += \"-DAI_FILE_SORTER_BUILD_TESTS=ON\"\n    }\n\n    if ($env:AI_FILE_SORTER_STARTER_CONSOLE) {\n        $configureArgs += \"-DAI_FILE_SORTER_STARTER_CONSOLE=$($env:AI_FILE_SORTER_STARTER_CONSOLE)\"\n    }\n\n    if ($CMakeMajor -lt 3 -or ($CMakeMajor -eq 3 -and $CMakeMinor -lt 22)) {\n        $cmakeMajorMinor = \"$CMakeMajor.$CMakeMinor\"\n        Write-Warning \"Detected CMake $cmakeMajorMinor < 3.22; passing QT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT=$cmakeMajorMinor to satisfy Qt 6.9 requirements.\"\n        $configureArgs += \"-DQT_FORCE_MIN_CMAKE_VERSION_FOR_USING_QT=$cmakeMajorMinor\"\n    }\n\n    if ($Generator -eq \"Ninja\" -or $Generator -eq \"Ninja Multi-Config\") {\n        $configureArgs += \"-DCMAKE_BUILD_TYPE=$Configuration\"\n    } else {\n        $configureArgs += \"-A\"\n        $configureArgs += \"x64\"\n    }\n\n    return ,$configureArgs\n}\n\nfunction Resolve-OutputExecutable {\n    param(\n        [string]$BuildDir,\n        [string]$ConfigurationName\n    )\n\n    $binDir = Join-Path $appDir \"bin\"\n    $buildConfigDir = Join-Path $BuildDir $ConfigurationName\n    $outputCandidates = @(\n        (Join-Path $buildConfigDir \"aifilesorter.exe\"),\n        (Join-Path $BuildDir \"aifilesorter.exe\"),\n        (Join-Path (Join-Path $binDir $ConfigurationName) \"aifilesorter.exe\"),\n        (Join-Path $binDir \"aifilesorter.exe\")\n    )\n\n    foreach ($candidate in $outputCandidates) {\n        if ($candidate -and (Test-Path $candidate)) {\n            return $candidate\n        }\n    }\n\n    Write-Warning \"Expected executable was not found in standard locations. Reported path may not exist: $($outputCandidates[0])\"\n    return $outputCandidates[0]\n}\n\nfunction Stage-BuildOutput {\n    param(\n        [string]$OutputExe,\n        [string]$BuildDir\n    )\n\n    $outputDir = Split-Path -Parent $OutputExe\n\n    $pdfiumDll = Join-Path $appDir \"..\\\\external\\\\pdfium\\\\windows-x64\\\\bin\\\\pdfium.dll\"\n    $pdfiumDllPath = Resolve-Path -Path $pdfiumDll -ErrorAction SilentlyContinue\n    if ($pdfiumDllPath) {\n        Copy-Item $pdfiumDllPath.Path -Destination $outputDir -Force\n    } else {\n        Write-Warning \"PDFium DLL not found under external/pdfium/windows-x64/bin. Run app\\\\scripts\\\\vendor_doc_deps.ps1 (or app/scripts/vendor_doc_deps.sh) to populate it.\"\n    }\n\n    $precompiledCpuBin = Join-Path $appDir \"lib/precompiled/cpu/bin\"\n    $precompiledCudaBin = Join-Path $appDir \"lib/precompiled/cuda/bin\"\n    $precompiledVulkanBin = Join-Path $appDir \"lib/precompiled/vulkan/bin\"\n\n    $destWocuda = Join-Path $outputDir \"lib/ggml/wocuda\"\n    $destWcuda = Join-Path $outputDir \"lib/ggml/wcuda\"\n    $destWvulkan = Join-Path $outputDir \"lib/ggml/wvulkan\"\n\n    foreach ($destDir in @($destWocuda, $destWcuda, $destWvulkan)) {\n        if (-not (Test-Path $destDir)) {\n            New-Item -ItemType Directory -Path $destDir -Force | Out-Null\n        }\n    }\n\n    if (Test-Path $precompiledCpuBin) {\n        Get-ChildItem -Path $precompiledCpuBin -Filter \"*.dll\" -File -ErrorAction SilentlyContinue |\n            ForEach-Object {\n                if ($_.Name -ieq \"libcurl.dll\") { return }\n                Copy-Item $_.FullName -Destination $destWocuda -Force\n            }\n    }\n\n    $mingwRuntimeNames = @(\"libgomp-1.dll\", \"libgcc_s_seh-1.dll\", \"libgfortran-5.dll\", \"libwinpthread-1.dll\", \"libquadmath-0.dll\")\n    $runtimeSearchPaths = @()\n    if ($env:OPENBLAS_ROOT) {\n        $runtimeSearchPaths += (Join-Path $env:OPENBLAS_ROOT \"bin\")\n    }\n    $runtimeSearchPaths += \"C:\\msys64\\mingw64\\bin\"\n\n    foreach ($dllName in $mingwRuntimeNames) {\n        $found = $false\n        foreach ($path in $runtimeSearchPaths) {\n            if (-not (Test-Path $path)) { continue }\n            $candidate = Join-Path $path $dllName\n            if (Test-Path $candidate) {\n                Copy-Item $candidate -Destination $destWocuda -Force\n                Copy-Item $candidate -Destination $outputDir -Force\n                $found = $true\n                break\n            }\n        }\n        if (-not $found) {\n            Write-Warning \"Could not locate $dllName in any runtime path. Add it manually to $destWocuda if needed.\"\n        }\n    }\n\n    if (Test-Path $precompiledCudaBin) {\n        Get-ChildItem -Path $precompiledCudaBin -Filter \"*.dll\" -File -ErrorAction SilentlyContinue |\n            ForEach-Object {\n                if ($_.Name -ieq \"libcurl.dll\") { return }\n                Copy-Item $_.FullName -Destination $destWcuda -Force\n            }\n    }\n\n    if (Test-Path $precompiledVulkanBin) {\n        Get-ChildItem -Path $precompiledVulkanBin -Filter \"*.dll\" -File -ErrorAction SilentlyContinue |\n            ForEach-Object {\n                if ($_.Name -ieq \"libcurl.dll\") { return }\n                Copy-Item $_.FullName -Destination $destWvulkan -Force\n            }\n    }\n\n    foreach ($destDir in @($destWocuda, $destWcuda, $destWvulkan)) {\n        if (Test-Path $destDir) {\n            Get-ChildItem -Path $destDir -Filter \"*.lib\" -File -Recurse -ErrorAction SilentlyContinue |\n                Remove-Item -Force\n            Get-ChildItem -Path $destDir -Directory -Recurse -ErrorAction SilentlyContinue |\n                Where-Object { $_.Name -in @(\"bin\", \"lib\") } |\n                ForEach-Object { Remove-Item $_.FullName -Recurse -Force }\n        }\n    }\n\n    if (-not $SkipDeploy) {\n        $isWindowsHost = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)\n        if ($isWindowsHost) {\n            $windeployCandidates = @(\n                (Join-Path $sharedVcpkgInstalledDir \"x64-windows/tools/Qt6/bin/windeployqt.exe\"),\n                (Join-Path $BuildDir \"vcpkg_installed/x64-windows/tools/Qt6/bin/windeployqt.exe\"),\n                (Join-Path $VcpkgRoot \"installed/x64-windows/tools/Qt6/bin/windeployqt.exe\"),\n                (Join-Path $appDir \"vcpkg_installed/x64-windows/tools/Qt6/bin/windeployqt.exe\")\n            )\n            $windeploy = $null\n            foreach ($candidate in $windeployCandidates) {\n                if ($candidate -and (Test-Path $candidate)) {\n                    $windeploy = $candidate\n                    break\n                }\n            }\n            if ($windeploy) {\n                Write-Output \"Running windeployqt to stage Qt/runtime DLLs for $OutputExe...\"\n                & $windeploy --no-translations $OutputExe\n                if ($LASTEXITCODE -ne 0) {\n                    throw \"windeployqt failed with exit code $LASTEXITCODE\"\n                }\n            } else {\n                Write-Warning \"windeployqt.exe not found under vcpkg install roots. Install qtbase via vcpkg or run windeployqt manually.\"\n            }\n        } else {\n            Write-Warning \"Skipping runtime deployment; windeployqt is only available on Windows.\"\n        }\n    } else {\n        Write-Output \"Skipping windeployqt step (per -SkipDeploy).\"\n    }\n\n    $vcpkgRuntimeSources = @(\n        (Join-Path $sharedVcpkgInstalledDir \"x64-windows/bin\"),\n        (Join-Path $BuildDir \"vcpkg_installed/x64-windows/bin\"),\n        (Join-Path $VcpkgRoot \"installed/x64-windows/bin\")\n    )\n    $copiedVcpkgDlls = Copy-VcpkgRuntimeDlls -SourceDirectories $vcpkgRuntimeSources -Destination $outputDir\n    if ($copiedVcpkgDlls.Count -gt 0) {\n        Write-Output (\"Staged vcpkg runtime DLLs to {0}:\" -f $outputDir)\n        Write-Output \"  $($copiedVcpkgDlls -join ', ')\"\n    } else {\n        Write-Warning \"No vcpkg runtime DLLs were copied; ensure curl/openssl/sqlite runtimes are present beside the executable before distributing.\"\n    }\n}\n\nif (-not (Test-Path (Join-Path $llamaDir \"CMakeLists.txt\"))) {\n    throw \"llama.cpp submodule not found. Run 'git submodule update --init --recursive' before building.\"\n}\n\nif ($RunTests) {\n    $BuildTests = $true\n}\n\n$selectedVariantNames = @($Variants | Select-Object -Unique)\n$selectedVariants = foreach ($variantName in $selectedVariantNames) {\n    $variantDefinitions[$variantName]\n}\n\nif ($BuildTests -and ($selectedVariantNames -notcontains \"Standard\")) {\n    throw \"-BuildTests and -RunTests currently require the Standard variant because tests are only configured in the auto-update build.\"\n}\n\nif (-not $VcpkgRoot) {\n    $envCandidates = @($env:VCPKG_ROOT, $env:VPKG_ROOT)\n    foreach ($envCandidate in $envCandidates) {\n        $resolved = Resolve-VcpkgRootFromPath -Path $envCandidate\n        if ($resolved) {\n            $VcpkgRoot = $resolved\n            break\n        }\n    }\n}\n\nif (-not $VcpkgRoot) {\n    $commandCandidates = @(\"vcpkg\", \"vpkg\")\n    foreach ($candidate in $commandCandidates) {\n        $cmd = Get-Command $candidate -ErrorAction SilentlyContinue\n        if (-not $cmd) { continue }\n\n        $possiblePaths = @($cmd.Source, $cmd.Path, $cmd.Definition)\n        foreach ($cPath in $possiblePaths) {\n            $resolved = Resolve-VcpkgRootFromPath -Path $cPath\n            if ($resolved) {\n                $VcpkgRoot = $resolved\n                break\n            }\n        }\n\n        if ($VcpkgRoot) { break }\n    }\n}\n\nif (-not $VcpkgRoot) {\n    throw \"Could not locate vcpkg. Provide -VcpkgRoot or set the VCPKG_ROOT environment variable. If vcpkg is installed via winget, pass -VcpkgRoot explicitly (e.g. C:\\dev\\vcpkg).\"\n}\n\n$cmakeCommand = Get-Command cmake -ErrorAction SilentlyContinue\nif (-not $cmakeCommand) {\n    throw \"cmake executable not found in PATH. Install CMake (3.22+) or add it to PATH.\"\n}\n$cmakeExe = $cmakeCommand.Path\n\n$cmakeVersionOutput = & $cmakeExe --version\n$cmakeVersionPattern = [regex]'cmake version (?<major>\\d+)\\.(?<minor>\\d+)(\\.(?<patch>\\d+))?'\n$cmakeVersionMatch = $cmakeVersionPattern.Match($cmakeVersionOutput)\nif (-not $cmakeVersionMatch.Success) {\n    Write-Warning \"Unable to parse CMake version from output:`n$cmakeVersionOutput\"\n    $cmakeMajor = 0\n    $cmakeMinor = 0\n} else {\n    $cmakeMajor = [int]$cmakeVersionMatch.Groups['major'].Value\n    $cmakeMinor = [int]$cmakeVersionMatch.Groups['minor'].Value\n    if ($cmakeMajor -lt 3 -or ($cmakeMajor -eq 3 -and $cmakeMinor -lt 16)) {\n        throw \"CMake 3.16 or newer is required. Detected version $($cmakeVersionMatch.Value).\"\n    }\n}\n\n$toolchainFile = Join-Path $VcpkgRoot \"scripts/buildsystems/vcpkg.cmake\"\nif (-not (Test-Path $toolchainFile)) {\n    throw \"The provided vcpkg root '$VcpkgRoot' does not contain scripts/buildsystems/vcpkg.cmake.\"\n}\n\nif (-not $Generator) {\n    $Generator = \"Visual Studio 17 2022\"\n}\n\nif ($Generator -eq \"Ninja\" -or $Generator -eq \"Ninja Multi-Config\") {\n    $ninjaEnvArch = $env:VSCMD_ARG_TGT_ARCH\n    if ($ninjaEnvArch -and ($ninjaEnvArch -ne \"x64\")) {\n        Write-Warning \"Ninja generator selected while MSVC environment targets '$ninjaEnvArch'. Qt packages are built for x64; run from an x64 Native Tools prompt or choose -Generator \"\"Visual Studio 17 2022\"\".\"\n    } elseif (-not $ninjaEnvArch) {\n        Write-Warning \"Using Ninja generator without an initialized MSVC environment. Ensure you run from an x64 Native Tools command prompt so the 64-bit compiler is available.\"\n    }\n}\n\nif ($Parallel -lt 1) {\n    $Parallel = [Math]::Max([System.Environment]::ProcessorCount, 1)\n}\n\nif ($Clean) {\n    foreach ($variant in $selectedVariants) {\n        if (Test-Path $variant.BuildDir) {\n            Write-Output \"Removing existing build directory '$($variant.BuildDir)'...\"\n            Remove-Item -Recurse -Force $variant.BuildDir\n        }\n    }\n    if (Test-Path $sharedVcpkgInstalledDir) {\n        Write-Output \"Removing shared vcpkg install directory '$sharedVcpkgInstalledDir'...\"\n        Remove-Item -Recurse -Force $sharedVcpkgInstalledDir\n    }\n}\n\nif (-not (Test-Path $sharedVcpkgInstalledDir)) {\n    New-Item -ItemType Directory -Path $sharedVcpkgInstalledDir | Out-Null\n}\n\nWrite-Output \"Using $Parallel parallel job(s) for builds.\"\nWrite-Output \"Shared vcpkg installed directory: $sharedVcpkgInstalledDir\"\n\n$builtOutputs = New-Object System.Collections.Generic.List[object]\n\nforeach ($variant in $selectedVariants) {\n    if (-not (Test-Path $variant.BuildDir)) {\n        New-Item -ItemType Directory -Path $variant.BuildDir | Out-Null\n    }\n\n    $enableTests = $BuildTests -and $variant.Name -eq \"Standard\"\n    $configureArgs = Get-ConfigureArguments -Variant $variant `\n                                            -ToolchainFile $toolchainFile `\n                                            -EnableTests:$enableTests `\n                                            -CMakeMajor $cmakeMajor `\n                                            -CMakeMinor $cmakeMinor\n\n    Write-Output \"\"\n    Write-Output \"==== Building $($variant.Name) Variant ====\"\n    Write-Output \"Description : $($variant.Description)\"\n    Write-Output \"Build dir   : $($variant.BuildDir)\"\n    Write-Output \"Update mode : $($variant.UpdateMode)\"\n    Write-Output \"Configure   : cmake $($configureArgs -join ' ')\"\n    Write-Output \"=====================================\"\n\n    & $cmakeExe @configureArgs\n    if ($LASTEXITCODE -ne 0) {\n        throw \"cmake configure failed for the $($variant.Name) variant.\"\n    }\n\n    $buildArgs = @(\"--build\", $variant.BuildDir, \"--config\", $Configuration, \"--parallel\", $Parallel)\n    Write-Output \"Building $($variant.Name) variant...\"\n    & $cmakeExe @buildArgs\n    if ($LASTEXITCODE -ne 0) {\n        throw \"cmake build failed for the $($variant.Name) variant.\"\n    }\n\n    if ($enableTests) {\n        Write-Output \"Building unit tests in the Standard variant...\"\n        $testBuildArgs = @(\"--build\", $variant.BuildDir, \"--config\", $Configuration, \"--target\", \"ai_file_sorter_tests\", \"--parallel\", $Parallel)\n        & $cmakeExe @testBuildArgs\n        if ($LASTEXITCODE -ne 0) {\n            throw \"Failed to build unit tests in the Standard variant.\"\n        }\n\n        if ($RunTests) {\n            $ctestExe = Join-Path (Split-Path $cmakeExe) \"ctest.exe\"\n            if (-not (Test-Path $ctestExe)) {\n                $ctestExe = \"ctest\"\n            }\n\n            Push-Location $variant.BuildDir\n            try {\n                Write-Output \"Running ctest in the Standard variant...\"\n                & $ctestExe \"-C\" $Configuration \"--output-on-failure\" \"-j\" $Parallel\n                if ($LASTEXITCODE -ne 0) {\n                    throw \"ctest reported failures.\"\n                }\n            } finally {\n                Pop-Location\n            }\n        }\n    }\n\n    $outputExe = Resolve-OutputExecutable -BuildDir $variant.BuildDir -ConfigurationName $Configuration\n    Write-Output \"Executable located at: $outputExe\"\n    Stage-BuildOutput -OutputExe $outputExe -BuildDir $variant.BuildDir\n\n    $builtOutputs.Add([pscustomobject]@{\n        Variant = $variant.Name\n        UpdateMode = $variant.UpdateMode\n        Executable = $outputExe\n    }) | Out-Null\n}\n\nWrite-Output \"\"\nWrite-Output \"Build summary:\"\nforeach ($output in $builtOutputs) {\n    Write-Output (\" - {0} [{1}]: {2}\" -f $output.Variant, $output.UpdateMode, $output.Executable)\n}\n"
  },
  {
    "path": "app/include/AppInfo.hpp",
    "content": "#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#endif\n\ninline QString app_display_name() {\n    return QStringLiteral(AI_FILE_SORTER_APP_NAME);\n}\n"
  },
  {
    "path": "app/include/CategorizationDialog.hpp",
    "content": "#ifndef CATEGORIZATIONDIALOG_HPP\n#define CATEGORIZATIONDIALOG_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDialog>\n#include <QStandardItemModel>\n\n#include <memory>\n#include <optional>\n#include <tuple>\n#include <vector>\n#include <spdlog/logger.h>\n\nclass DatabaseManager;\nclass QCloseEvent;\nclass QEvent;\nclass QPushButton;\nclass QTableView;\nclass QCheckBox;\nclass QStandardItem;\n\nclass CategorizationDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(CategorizationDialog)\npublic:\n    CategorizationDialog(DatabaseManager* db_manager,\n                         bool show_subcategory_col,\n                         const std::string& undo_dir,\n                         CategoryLanguage category_language = CategoryLanguage::English,\n                         QWidget* parent = nullptr);\n\n    void set_show_subcategory_column(bool enabled);\n    bool show_subcategory_column_enabled() const { return show_subcategory_column; }\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    void test_set_entries(const std::vector<CategorizedFile>& files);\n    void test_trigger_confirm();\n    void test_trigger_undo();\n    bool test_undo_enabled() const;\n#endif\n\n    bool is_dialog_valid() const;\n    void show_results(const std::vector<CategorizedFile>& categorized_files,\n                      const std::string& base_dir_override = std::string(),\n                      bool include_subdirectories = false,\n                      bool allow_image_renames = true,\n                      bool allow_document_renames = true);\n\nprotected:\n    void closeEvent(QCloseEvent* event) override;\n    void changeEvent(QEvent* event) override;\n\nprivate:\n    enum class RowStatus {\n        None = 0,\n        Moved,\n        Renamed,\n        RenamedAndMoved,\n        Skipped,\n        NotSelected,\n        Preview\n    };\n\n    static constexpr int kStatusRole = Qt::UserRole + 100;\n    static constexpr int kFilePathRole = Qt::UserRole + 1;\n    static constexpr int kUsedConsistencyRole = Qt::UserRole + 2;\n    static constexpr int kRenameOnlyRole = Qt::UserRole + 3;\n    static constexpr int kFileTypeRole = Qt::UserRole + 4;\n    static constexpr int kRenameAppliedRole = Qt::UserRole + 5;\n    static constexpr int kRenameLockedRole = Qt::UserRole + 6;\n    static constexpr int kHiddenCategoryRole = Qt::UserRole + 7;\n    static constexpr int kHiddenSubcategoryRole = Qt::UserRole + 8;\n    static constexpr int kOriginalFileNameRole = Qt::UserRole + 9;\n    static constexpr int kOriginalCategoryRole = Qt::UserRole + 10;\n    static constexpr int kOriginalSubcategoryRole = Qt::UserRole + 11;\n    static constexpr int kCanonicalCategoryRole = Qt::UserRole + 12;\n    static constexpr int kCanonicalSubcategoryRole = Qt::UserRole + 13;\n\n    enum Column {\n        ColumnSelect = 0,\n        ColumnFile = 1,\n        ColumnType = 2,\n        ColumnSuggestedName = 3,\n        ColumnCategory = 4,\n        ColumnSubcategory = 5,\n        ColumnStatus = 6,\n        ColumnPreview = 7\n    };\n\n    struct MoveRecord {\n        int row_index;\n        std::string source_path;\n        std::string destination_path;\n        std::uintmax_t size_bytes{0};\n        std::time_t mtime{0};\n    };\n    struct PreviewRecord {\n        std::string source;\n        std::string destination;\n        std::string source_file_name;\n        std::string destination_file_name;\n        std::string category;\n        std::string subcategory;\n        bool use_subcategory{false};\n        bool rename_only{false};\n    };\n\n    void setup_ui();\n    void populate_model();\n    void ensure_unique_suggested_names_in_model();\n    void record_categorization_to_db();\n    void on_confirm_and_sort_button_clicked();\n    void on_continue_later_button_clicked();\n    void on_undo_button_clicked();\n    void show_close_button();\n    void restore_action_buttons();\n    void update_status_column(int row,\n                              bool success,\n                              bool attempted = true,\n                              bool renamed = false,\n                              bool moved = false);\n    void on_select_all_toggled(bool checked);\n    /**\n     * @brief Selects all highlighted rows for processing.\n     */\n    void on_select_highlighted_clicked();\n    void apply_select_all(bool checked);\n    /**\n     * @brief Applies a check state to the given rows in the Process column.\n     */\n    void apply_check_state_to_rows(const std::vector<int>& rows, Qt::CheckState state);\n    void on_item_changed(QStandardItem* item);\n    void update_select_all_state();\n    void update_type_icon(QStandardItem* item);\n    void retranslate_ui();\n    void apply_status_text(QStandardItem* item) const;\n    RowStatus status_from_item(const QStandardItem* item) const;\n    void on_show_subcategories_toggled(bool checked);\n    void apply_subcategory_visibility();\n    void clear_move_history();\n    void record_move_for_undo(int row,\n                              const std::string& source,\n                              const std::string& destination,\n                              std::uintmax_t size_bytes,\n                              std::time_t mtime);\n    void handle_selected_row(int row_index,\n                             const std::string& file_name,\n                             const std::string& rename_candidate,\n                             const std::string& category,\n                             const std::string& subcategory,\n                             const std::string& source_dir,\n                             const std::string& base_dir,\n                             std::vector<std::string>& files_not_moved,\n                             FileType file_type,\n                             bool rename_only,\n                             bool used_consistency_hints,\n                             bool dry_run);\n    void persist_move_plan();\n    bool undo_move_history();\n    void update_status_after_undo();\n    bool move_file_back(const std::string& source, const std::string& destination);\n    void remove_empty_parent_directories(const std::string& destination);\n    void set_preview_status(int row, const std::string& destination);\n    void update_preview_column(int row);\n    std::optional<std::string> compute_preview_path(int row) const;\n    std::optional<PreviewRecord> build_preview_record_for_row(int row, std::string* debug_reason = nullptr) const;\n    std::string resolve_destination_name(const std::string& original_name,\n                                         const std::string& rename_candidate) const;\n    bool validate_filename(const std::string& name, std::string& error) const;\n    bool resolve_row_flags(int row, bool& rename_only, bool& used_consistency_hints, FileType& file_type) const;\n    void set_show_rename_column(bool enabled);\n    void apply_rename_visibility();\n    void apply_category_visibility();\n    /**\n     * @brief Hides rows that are rename-only when required by the dialog mode.\n     */\n    void apply_rename_only_row_visibility();\n    /**\n     * @brief Syncs the rename-only checkbox state to current UI options.\n     */\n    void update_rename_only_checkbox_state();\n    /**\n     * @brief Enables/disables the subcategory checkbox based on rename-only mode.\n     */\n    void update_subcategory_checkbox_state();\n    /**\n     * @brief Marks image rows as rename-only when toggled.\n     * @param checked True when image rename-only is enabled.\n     */\n    void on_rename_images_only_toggled(bool checked);\n    /**\n     * @brief Marks document rows as rename-only when toggled.\n     * @param checked True when document rename-only is enabled.\n     */\n    void on_rename_documents_only_toggled(bool checked);\n    bool row_is_already_renamed_with_category(int row) const;\n    /**\n     * @brief Returns true if the row points to a supported image file.\n     * @param row Row index in the model.\n     * @return True when the row is an image file supported by the visual analyzer.\n     */\n    bool row_is_supported_image(int row) const;\n    /**\n     * @brief Returns true if the row points to a supported document file.\n     * @param row Row index in the model.\n     * @return True when the row is a supported document file.\n     */\n    bool row_is_supported_document(int row) const;\n    /**\n     * @brief Returns unique row indices that are highlighted in the table view.\n     */\n    std::vector<int> selected_row_indices() const;\n    /**\n     * @brief Opens a dialog to bulk edit categories for highlighted rows.\n     */\n    void on_bulk_edit_clicked();\n\n    DatabaseManager* db_manager;\n    CategoryLanguage category_language_{CategoryLanguage::English};\n    bool show_subcategory_column;\n    bool include_subdirectories_{false};\n    bool allow_image_renames_{true};\n    bool allow_document_renames_{true};\n    bool show_rename_column{false};\n    std::vector<CategorizedFile> categorized_files;\n\n    std::shared_ptr<spdlog::logger> core_logger;\n    std::shared_ptr<spdlog::logger> db_logger;\n    std::shared_ptr<spdlog::logger> ui_logger;\n\n    QTableView* table_view{nullptr};\n    QStandardItemModel* model{nullptr};\n    QPushButton* confirm_button{nullptr};\n    QPushButton* continue_button{nullptr};\n    QPushButton* close_button{nullptr};\n    QCheckBox* select_all_checkbox{nullptr};\n    QPushButton* select_highlighted_button{nullptr};\n    QPushButton* bulk_edit_button{nullptr};\n    QCheckBox* show_subcategories_checkbox{nullptr};\n    QCheckBox* dry_run_checkbox{nullptr};\n    QCheckBox* rename_images_only_checkbox{nullptr};\n    QCheckBox* rename_documents_only_checkbox{nullptr};\n    QPushButton* undo_button{nullptr};\n\n    std::vector<MoveRecord> move_history_;\n    std::vector<PreviewRecord> dry_run_plan_;\n\n    bool updating_select_all{false};\n    bool suppress_item_changed_{false};\n    std::string undo_dir_;\n    std::string base_dir_;\n};\n\n#endif // CATEGORIZATIONDIALOG_HPP\n"
  },
  {
    "path": "app/include/CategorizationProgressDialog.hpp",
    "content": "#ifndef CATEGORIZATIONPROGRESSDIALOG_HPP\n#define CATEGORIZATIONPROGRESSDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDialog>\n\n#include <array>\n#include <optional>\n#include <string>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\nclass MainApp;\nclass QLabel;\nclass QPlainTextEdit;\nclass QPushButton;\nclass QTableWidget;\nclass QTimer;\nclass QEvent;\n\nclass CategorizationProgressDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(CategorizationProgressDialog)\npublic:\n    enum class StageId {\n        ImageAnalysis,\n        DocumentAnalysis,\n        Categorization\n    };\n\n    struct StagePlan {\n        StageId id;\n        std::vector<FileEntry> items;\n    };\n\n    CategorizationProgressDialog(QWidget* parent, MainApp* main_app, bool show_subcategory_col);\n\n    void show();\n    void hide();\n    void append_text(const std::string& text);\n    void configure_stages(const std::vector<StagePlan>& stages);\n    void set_stage_items(StageId stage_id, const std::vector<FileEntry>& items);\n    void set_active_stage(StageId stage_id);\n    void mark_stage_item_pending(StageId stage_id, const FileEntry& entry);\n    void mark_stage_item_in_progress(StageId stage_id, const FileEntry& entry);\n    void mark_stage_item_completed(StageId stage_id, const FileEntry& entry);\n\nprotected:\n    void changeEvent(QEvent* event) override;\n\nprivate:\n    enum class ItemStatus {\n        NotApplicable,\n        Pending,\n        InProgress,\n        Completed\n    };\n\n    enum class DisplayType {\n        Directory,\n        File,\n        Image,\n        Document\n    };\n\n    struct StageState {\n        bool enabled{false};\n        std::unordered_set<std::string> item_keys;\n    };\n\n    struct ItemState {\n        int row{-1};\n        DisplayType display_type{DisplayType::File};\n        std::array<ItemStatus, 3> stage_statuses{\n            ItemStatus::NotApplicable,\n            ItemStatus::NotApplicable,\n            ItemStatus::NotApplicable\n        };\n    };\n\n    static constexpr int kStageCount = 3;\n\n    void setup_ui(bool show_subcategory_col);\n    void retranslate_ui();\n    void request_stop();\n    static std::string make_item_key(const std::string& full_path, FileType type);\n    static std::size_t stage_index(StageId stage_id);\n    QString stage_label(StageId stage_id) const;\n    static DisplayType classify_display_type(const FileEntry& entry);\n    QString display_type_label(DisplayType display_type) const;\n    int column_for_stage(StageId stage_id) const;\n    void ensure_stage_enabled(StageId stage_id);\n    void upsert_stage_item(StageId stage_id, const FileEntry& entry);\n    void upsert_item(const FileEntry& entry);\n    void set_stage_item_status(StageId stage_id, const FileEntry& entry, ItemStatus status);\n    void rebuild_headers();\n    void refresh_stage_overview();\n    void refresh_row(int row);\n    void refresh_summary();\n    void refresh_spinner();\n    bool has_in_progress_item() const;\n    ItemStatus stage_status_for_row(const ItemState& state, StageId stage_id) const;\n    std::optional<int> find_stage_row(StageId stage_id, ItemStatus status) const;\n    void ensure_row_visible(int row);\n\n    MainApp* main_app;\n    QLabel* stage_list_label{nullptr};\n    QLabel* summary_label{nullptr};\n    QLabel* log_label{nullptr};\n    QTableWidget* status_table{nullptr};\n    QPlainTextEdit* text_view{nullptr};\n    QPushButton* stop_button{nullptr};\n    QTimer* spinner_timer{nullptr};\n    std::array<StageState, kStageCount> stage_states_{};\n    std::vector<StageId> active_stage_order_;\n    std::optional<StageId> active_stage_;\n    std::unordered_map<std::string, ItemState> item_states_;\n    int spinner_frame_index_{0};\n};\n\n#endif // CATEGORIZATIONPROGRESSDIALOG_HPP\n"
  },
  {
    "path": "app/include/CategorizationService.hpp",
    "content": "#ifndef CATEGORIZATION_SERVICE_HPP\n#define CATEGORIZATION_SERVICE_HPP\n\n#include \"Types.hpp\"\n#include \"DatabaseManager.hpp\"\n\n#include <atomic>\n#include <deque>\n#include <future>\n#include <functional>\n#include <memory>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <unordered_map>\n#include <vector>\n\nclass Settings;\nclass ILLMClient;\nnamespace spdlog { class logger; }\n\n/**\n * @brief Provides LLM-backed file categorization with caching and validation.\n */\nclass CategorizationService {\npublic:\n    using ProgressCallback = std::function<void(const std::string&)>;\n    using QueueCallback = std::function<void(const FileEntry&)>;\n    using CompletionCallback = std::function<void(const FileEntry&)>;\n    using RecategorizationCallback = std::function<void(const CategorizedFile&, const std::string&)>;\n    /**\n     * @brief Overrides the name/path used in LLM prompts for a file entry.\n     */\n    struct PromptOverride {\n        std::string name;\n        std::string path;\n    };\n    using PromptOverrideProvider = std::function<std::optional<PromptOverride>(const FileEntry&)>;\n    /** Supplies an optional suggested rename for an entry during categorization. */\n    using SuggestedNameProvider = std::function<std::string(const FileEntry&)>;\n\n    /**\n     * @brief Constructs the service with settings, database access, and logging.\n     * @param settings Application settings reference.\n     * @param db_manager Database manager used for cache access.\n     * @param core_logger Logger for core activity.\n     */\n    CategorizationService(Settings& settings,\n                          DatabaseManager& db_manager,\n                          std::shared_ptr<spdlog::logger> core_logger);\n\n    /**\n     * @brief Verifies that required remote credentials are configured.\n     * @param error_message Optional output for a user-facing error message.\n     * @return True when credentials are present or not required.\n     */\n    bool ensure_remote_credentials(std::string* error_message = nullptr) const;\n    /**\n     * @brief Removes cached entries that have empty categories for a directory.\n     * @param directory_path Directory to clean.\n     * @return Entries that were removed.\n     */\n    std::vector<CategorizedFile> prune_empty_cached_entries(const std::string& directory_path);\n    /**\n     * @brief Loads cached categorizations for the provided directory.\n     * @param directory_path Directory to load.\n     * @return Cached entries for the directory.\n     */\n    std::vector<CategorizedFile> load_cached_entries(const std::string& directory_path) const;\n\n    /**\n     * @brief Categorizes a list of file entries using the configured LLM workflow.\n     * @param files Entries to categorize.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param stop_flag Cancellation flag.\n     * @param progress_callback Progress updates callback.\n     * @param queue_callback Called when an entry is queued.\n     * @param completion_callback Called when an entry has finished processing.\n     * @param recategorization_callback Called when an entry must be re-categorized.\n     * @param llm_factory Factory for creating an LLM client.\n     * @param prompt_override Optional prompt override provider.\n     * @param suggested_name_provider Optional suggested-name provider.\n     * @return Categorized entries that were successfully processed.\n     */\n    std::vector<CategorizedFile> categorize_entries(\n        const std::vector<FileEntry>& files,\n        bool is_local_llm,\n        std::atomic<bool>& stop_flag,\n        const ProgressCallback& progress_callback,\n        const QueueCallback& queue_callback,\n        const CompletionCallback& completion_callback,\n        const RecategorizationCallback& recategorization_callback,\n        std::function<std::unique_ptr<ILLMClient>()> llm_factory,\n        const PromptOverrideProvider& prompt_override = {},\n        const SuggestedNameProvider& suggested_name_provider = {}) const;\n\nprivate:\n    using CategoryPair = std::pair<std::string, std::string>;\n    using HintHistory = std::deque<CategoryPair>;\n    using SessionHistoryMap = std::unordered_map<std::string, HintHistory>;\n\n    /**\n     * @brief Returns a cached categorization when available, otherwise calls the LLM.\n     * @param llm LLM client used for the request.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param display_name Display name for logging.\n     * @param display_path Display path for logging.\n     * @param dir_path Full directory path for cache lookup.\n     * @param prompt_name Name used in the prompt.\n     * @param prompt_path Path used in the prompt.\n     * @param file_type File or directory.\n     * @param progress_callback Progress updates callback.\n     * @param consistency_context Consistency hints block.\n     * @return Resolved category for the item.\n     */\n    DatabaseManager::ResolvedCategory categorize_with_cache(\n        ILLMClient& llm,\n        bool is_local_llm,\n        const std::string& display_name,\n        const std::string& display_path,\n        const std::string& dir_path,\n        const std::string& prompt_name,\n        const std::string& prompt_path,\n        FileType file_type,\n        const ProgressCallback& progress_callback,\n        const std::string& consistency_context) const;\n\n    /**\n     * @brief Categorizes a single entry and persists the result.\n     * @param llm LLM client used for the request.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param entry File entry to categorize.\n     * @param prompt_override Optional prompt override.\n     * @param suggested_name Optional suggested name for renaming.\n     * @param stop_flag Cancellation flag.\n     * @param progress_callback Progress updates callback.\n     * @param recategorization_callback Callback for re-categorization events.\n     * @param session_history Mutable session history for consistency hints.\n     * @return Categorized entry when successful.\n     */\n    std::optional<CategorizedFile> categorize_single_entry(\n        ILLMClient& llm,\n        bool is_local_llm,\n        const FileEntry& entry,\n        const std::optional<PromptOverride>& prompt_override,\n        const std::string& suggested_name,\n        std::atomic<bool>& stop_flag,\n        const ProgressCallback& progress_callback,\n        const RecategorizationCallback& recategorization_callback,\n        SessionHistoryMap& session_history) const;\n\n    /**\n     * @brief Combines language, whitelist, and hint blocks into a single prompt context.\n     * @param hint_block Consistency hint block.\n     * @return Combined prompt context.\n     */\n    std::string build_combined_context(const std::string& hint_block) const;\n    DatabaseManager::ResolvedCategory localize_resolved_category(\n        ILLMClient& llm,\n        const DatabaseManager::ResolvedCategory& resolved) const;\n    std::optional<DatabaseManager::ResolvedCategory> translate_resolved_category(\n        ILLMClient& llm,\n        const DatabaseManager::ResolvedCategory& resolved) const;\n    /**\n     * @brief Runs the categorization flow with cache handling for a single entry.\n     * @param llm LLM client used for the request.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param entry File entry to categorize.\n     * @param display_path Display path for logging.\n     * @param dir_path Full directory path for cache lookup.\n     * @param prompt_name Name used in the prompt.\n     * @param prompt_path Path used in the prompt.\n     * @param progress_callback Progress updates callback.\n     * @param combined_context Combined prompt context.\n     * @return Resolved category for the item.\n     */\n    DatabaseManager::ResolvedCategory run_categorization_with_cache(\n        ILLMClient& llm,\n        bool is_local_llm,\n        const FileEntry& entry,\n        const std::string& display_path,\n        const std::string& dir_path,\n        const std::string& prompt_name,\n        const std::string& prompt_path,\n        const ProgressCallback& progress_callback,\n        const std::string& combined_context) const;\n    /**\n     * @brief Handles empty or invalid categorization results.\n     * @param entry File entry being categorized.\n     * @param dir_path Directory path of the entry.\n     * @param resolved Resolved category data.\n     * @param used_consistency_hints True if hints were applied.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param recategorization_callback Callback for re-categorization events.\n     * @return Optional replacement categorization when a retry is needed.\n     */\n    std::optional<CategorizedFile> handle_empty_result(\n        const FileEntry& entry,\n        const std::string& dir_path,\n        const DatabaseManager::ResolvedCategory& resolved,\n        bool used_consistency_hints,\n        bool is_local_llm,\n        const RecategorizationCallback& recategorization_callback) const;\n    /**\n     * @brief Persists categorization results and updates session hint history.\n     * @param entry File entry being categorized.\n     * @param dir_path Directory path of the entry.\n     * @param resolved Resolved category data.\n     * @param used_consistency_hints True if hints were applied.\n     * @param suggested_name Suggested rename value.\n     * @param session_history Session history for consistency hints.\n     */\n    void update_storage_with_result(const FileEntry& entry,\n                                    const std::string& dir_path,\n                                    const DatabaseManager::ResolvedCategory& resolved,\n                                    bool used_consistency_hints,\n                                    const std::string& suggested_name,\n                                    SessionHistoryMap& session_history) const;\n\n    /**\n     * @brief Runs the LLM request with a timeout for the given item.\n     * @param llm LLM client used for the request.\n     * @param item_name Display name for the item.\n     * @param item_path Display path for the item.\n     * @param file_type File or directory.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param consistency_context Consistency hints block.\n     * @return Raw LLM response string.\n     */\n    std::string run_llm_with_timeout(\n        ILLMClient& llm,\n        const std::string& item_name,\n        const std::string& item_path,\n        FileType file_type,\n        bool is_local_llm,\n        const std::string& consistency_context) const;\n    /**\n     * @brief Resolves the LLM timeout based on runtime and environment settings.\n     * @param is_local_llm True when using a local LLM backend.\n     * @return Timeout in seconds.\n     */\n    int resolve_llm_timeout(bool is_local_llm) const;\n    /**\n     * @brief Launches an asynchronous LLM categorization request.\n     * @param llm LLM client used for the request.\n     * @param item_name Display name for the item.\n     * @param item_path Display path for the item.\n     * @param file_type File or directory.\n     * @param consistency_context Consistency hints block.\n     * @return Future that yields the raw LLM response.\n     */\n    std::future<std::string> start_llm_future(ILLMClient& llm,\n                                              const std::string& item_name,\n                                              const std::string& item_path,\n                                              FileType file_type,\n                                              const std::string& consistency_context) const;\n\n    /**\n     * @brief Builds a whitelist context block for the prompt.\n     * @return Whitelist prompt section.\n     */\n    std::string build_whitelist_context() const;\n    /**\n     * @brief Builds a prompt instruction for non-English category languages.\n     * @return Language instruction block or empty string.\n     */\n    std::string build_category_language_context() const;\n\n    /**\n     * @brief Collects recent category assignments to provide consistency hints.\n     * @param signature Signature key for the file type/extension.\n     * @param session_history In-memory history of assignments.\n     * @param extension File extension.\n     * @param file_type File or directory.\n     * @return List of up to kMaxConsistencyHints pairs.\n     */\n    std::vector<CategoryPair> collect_consistency_hints(\n        const std::string& signature,\n        const SessionHistoryMap& session_history,\n        const std::string& extension,\n        FileType file_type) const;\n\n    /**\n     * @brief Returns a cached categorization if it is valid for the entry.\n     * @param item_name Display name for the item.\n     * @param current_path Display path for the current on-disk location.\n     * @param categorization_path Effective path used for categorization context.\n     * @param dir_path Full directory path for cache lookup.\n     * @param file_type File or directory.\n     * @param progress_callback Progress updates callback.\n     * @return Resolved category when cache is valid.\n     */\n    std::optional<DatabaseManager::ResolvedCategory> try_cached_categorization(\n        const std::string& item_name,\n        const std::string& current_path,\n        const std::string& categorization_path,\n        const std::string& dir_path,\n        FileType file_type,\n        const ProgressCallback& progress_callback) const;\n\n    /**\n     * @brief Ensures remote credentials are present and reports errors via progress callback.\n     * @param item_name Display name for the item.\n     * @param progress_callback Progress updates callback.\n     * @return True when credentials are present or not required.\n     */\n    bool ensure_remote_credentials_for_request(\n        const std::string& item_name,\n        const ProgressCallback& progress_callback) const;\n\n    /**\n     * @brief Categorizes a single item by calling the LLM and validating the response.\n     * @param llm LLM client used for the request.\n     * @param is_local_llm True when using a local LLM backend.\n     * @param display_name Display name for logging.\n     * @param display_path Display path for logging.\n     * @param prompt_name Name used in the prompt.\n     * @param prompt_path Path used in the prompt.\n     * @param file_type File or directory.\n     * @param progress_callback Progress updates callback.\n     * @param consistency_context Consistency hints block.\n     * @return Resolved category for the item.\n     */\n    DatabaseManager::ResolvedCategory categorize_via_llm(\n        ILLMClient& llm,\n        bool is_local_llm,\n        const std::string& display_name,\n        const std::string& display_path,\n        const std::string& prompt_name,\n        const std::string& prompt_path,\n        FileType file_type,\n        const ProgressCallback& progress_callback,\n        const std::string& consistency_context) const;\n\n    /**\n     * @brief Emits a formatted progress message for a categorization event.\n     * @param progress_callback Progress updates callback.\n     * @param source Label for the progress source.\n     * @param item_name Display name for the item.\n     * @param resolved Resolved category data.\n     * @param current_path Display path for the current on-disk location.\n     * @param categorization_path Effective path used for categorization context.\n     */\n    void emit_progress_message(const ProgressCallback& progress_callback,\n                               std::string_view source,\n                               const std::string& item_name,\n                               const DatabaseManager::ResolvedCategory& resolved,\n                               const std::string& current_path,\n                               const std::string& categorization_path) const;\n\n    /**\n     * @brief Builds a signature key for consistency hints.\n     * @param file_type File or directory.\n     * @param extension File extension.\n     * @return Signature key for consistency lookup.\n     */\n    static std::string make_file_signature(FileType file_type, const std::string& extension);\n    /**\n     * @brief Extracts a lowercase file extension (including the dot).\n     * @param file_name File name to inspect.\n     * @return Lowercase extension with dot, or empty string when none exists.\n     */\n    static std::string extract_extension(const std::string& file_name);\n    /**\n     * @brief Appends a unique, sanitized hint to the target list.\n     * @param target Hint list to update.\n     * @param candidate Candidate pair to append.\n     * @return True when the hint was added.\n     */\n    static bool append_unique_hint(std::vector<CategoryPair>& target, const CategoryPair& candidate);\n    /**\n     * @brief Updates in-memory hint history with the latest assignment.\n     * @param history Hint history to update.\n     * @param assignment Category/subcategory assignment to record.\n     */\n    static void record_session_assignment(HintHistory& history, const CategoryPair& assignment);\n    /**\n     * @brief Formats consistency hints into a prompt block.\n     * @param hints Consistency hints to format.\n     * @return Prompt block string.\n     */\n    std::string format_hint_block(const std::vector<CategoryPair>& hints) const;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class CategorizationServiceTestAccess;\n#endif\n\n    Settings& settings;\n    DatabaseManager& db_manager;\n    std::shared_ptr<spdlog::logger> core_logger;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/CategorizationServiceTestAccess.hpp",
    "content": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"CategorizationService.hpp\"\n\n/**\n * @brief Test-only accessors for CategorizationService internals.\n */\nclass CategorizationServiceTestAccess {\npublic:\n    /**\n     * @brief Returns the whitelist context string used in prompts.\n     * @param service CategorizationService instance under test.\n     * @return Prompt snippet describing allowed categories/subcategories.\n     */\n    static std::string build_whitelist_context(const CategorizationService& service) {\n        return service.build_whitelist_context();\n    }\n\n    /**\n     * @brief Returns the category-language context string used in prompts.\n     * @param service CategorizationService instance under test.\n     * @return Prompt snippet describing the required category language.\n     */\n    static std::string build_category_language_context(const CategorizationService& service) {\n        return service.build_category_language_context();\n    }\n};\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/CategorizationSession.hpp",
    "content": "#ifndef CATEGORIZATIONSESSION_HPP\n#define CATEGORIZATIONSESSION_HPP\n\n#include <LLMClient.hpp>\n#include <string>\n\nclass CategorizationSession {\n    std::string key;\n    std::string model;\n    std::string base_url;\n\npublic:\n    /**\n     * @brief Construct a session for OpenAI-compatible requests.\n     */\n    CategorizationSession(std::string api_key, std::string model, std::string base_url = std::string());\n    ~CategorizationSession();\n\n    LLMClient create_llm_client() const;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/CategoryLanguage.hpp",
    "content": "#ifndef CATEGORYLANGUAGE_HPP\n#define CATEGORYLANGUAGE_HPP\n\n#include <QString>\n#include <string>\n#include <array>\n\nenum class CategoryLanguage {\n    Dutch,\n    English,\n    French,\n    German,\n    Italian,\n    Polish,\n    Portuguese,\n    Spanish,\n    Turkish\n};\n\ninline QString categoryLanguageToString(CategoryLanguage language)\n{\n    static const std::array<const char*, 9> names = {\n        \"Dutch\",\n        \"English\",\n        \"French\",\n        \"German\",\n        \"Italian\",\n        \"Polish\",\n        \"Portuguese\",\n        \"Spanish\",\n        \"Turkish\"\n    };\n\n    const auto idx = static_cast<std::size_t>(language);\n    if (idx < names.size()) {\n        return QString::fromUtf8(names[idx]);\n    }\n    return QStringLiteral(\"English\");\n}\n\ninline CategoryLanguage categoryLanguageFromString(const QString& value)\n{\n    const QString lowered = value.toLower();\n    static const std::array<std::pair<QString, CategoryLanguage>, 9> mapping = {{\n        {QStringLiteral(\"dutch\"), CategoryLanguage::Dutch},\n        {QStringLiteral(\"english\"), CategoryLanguage::English},\n        {QStringLiteral(\"french\"), CategoryLanguage::French},\n        {QStringLiteral(\"german\"), CategoryLanguage::German},\n        {QStringLiteral(\"italian\"), CategoryLanguage::Italian},\n        {QStringLiteral(\"polish\"), CategoryLanguage::Polish},\n        {QStringLiteral(\"portuguese\"), CategoryLanguage::Portuguese},\n        {QStringLiteral(\"spanish\"), CategoryLanguage::Spanish},\n        {QStringLiteral(\"turkish\"), CategoryLanguage::Turkish},\n    }};\n    for (const auto& entry : mapping) {\n        if (lowered == entry.first) {\n            return entry.second;\n        }\n    }\n    return CategoryLanguage::English;\n}\n\ninline std::string categoryLanguageDisplay(CategoryLanguage lang) {\n    return categoryLanguageToString(lang).toStdString();\n}\n\n#endif // CATEGORYLANGUAGE_HPP\n"
  },
  {
    "path": "app/include/ConsistencyPassService.hpp",
    "content": "#ifndef CONSISTENCY_PASS_SERVICE_HPP\n#define CONSISTENCY_PASS_SERVICE_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"Types.hpp\"\n\n#include <atomic>\n#include <functional>\n#include <memory>\n#include <optional>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\nclass ILLMClient;\nnamespace spdlog { class logger; }\n\nclass ConsistencyPassService {\npublic:\n    using ProgressCallback = std::function<void(const std::string&)>;\n\n    ConsistencyPassService(DatabaseManager& db_manager,\n                           std::shared_ptr<spdlog::logger> logger);\n\n    void set_prompt_logging_enabled(bool enabled);\n\n    void run(std::vector<CategorizedFile>& categorized_files,\n             std::vector<CategorizedFile>& newly_categorized_files,\n             std::function<std::unique_ptr<ILLMClient>()> llm_factory,\n             std::atomic<bool>& stop_flag,\n             CategoryLanguage category_language,\n             const ProgressCallback& progress_callback) const;\n\nprivate:\n    std::unique_ptr<ILLMClient> create_llm(std::function<std::unique_ptr<ILLMClient>()> llm_factory) const;\n    void process_chunks(ILLMClient& llm,\n                        const std::vector<std::pair<std::string, std::string>>& taxonomy,\n                        std::vector<CategorizedFile>& categorized_files,\n                        std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n                        std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n                        std::atomic<bool>& stop_flag,\n                        CategoryLanguage category_language,\n                        const ProgressCallback& progress_callback) const;\n    void process_chunk(const std::vector<const CategorizedFile*>& chunk,\n                       size_t start_index,\n                       size_t end_index,\n                       size_t total_items,\n                       ILLMClient& llm,\n                       const std::vector<std::pair<std::string, std::string>>& taxonomy,\n                       std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n                       std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n                       CategoryLanguage category_language,\n                       const ProgressCallback& progress_callback) const;\n    void log_chunk_items(const std::vector<const CategorizedFile*>& chunk, const char* stage) const;\n    bool apply_harmonized_response(const std::string& response,\n                                   const std::vector<const CategorizedFile*>& chunk,\n                                   std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n                                   std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n                                   const ProgressCallback& progress_callback,\n                                   DatabaseManager& db_manager,\n                                   CategoryLanguage category_language) const;\n\n    DatabaseManager& db_manager;\n    std::shared_ptr<spdlog::logger> logger;\n    mutable bool prompt_logging_enabled{false};\n};\n\n#endif\n"
  },
  {
    "path": "app/include/CustomApiDialog.hpp",
    "content": "#ifndef CUSTOMAPIDIALOG_HPP\n#define CUSTOMAPIDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDialog>\n\nclass QCheckBox;\nclass QLineEdit;\nclass QPushButton;\nclass QTextEdit;\n\n/**\n * @brief Dialog for creating or editing custom OpenAI-compatible API entries.\n */\nclass CustomApiDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(CustomApiDialog)\npublic:\n    /**\n     * @brief Construct a dialog for a new custom API entry.\n     * @param parent Parent widget.\n     */\n    explicit CustomApiDialog(QWidget* parent = nullptr);\n    /**\n     * @brief Construct a dialog pre-populated with an existing entry.\n     * @param parent Parent widget.\n     * @param existing Existing custom API values to edit.\n     */\n    explicit CustomApiDialog(QWidget* parent, const CustomApiEndpoint& existing);\n\n    /**\n     * @brief Return the dialog values as a CustomApiEndpoint entry.\n     */\n    CustomApiEndpoint result() const;\n\nprivate:\n    /**\n     * @brief Build the dialog layout and widgets.\n     */\n    void setup_ui();\n    /**\n     * @brief Connect widget signals to validation and handlers.\n     */\n    void wire_signals();\n    /**\n     * @brief Apply existing values to the input fields.\n     * @param existing Existing custom API values to load.\n     */\n    void apply_existing(const CustomApiEndpoint& existing);\n    /**\n     * @brief Validate inputs and update the ok button state.\n     */\n    void validate_inputs();\n\n    QLineEdit* name_edit{nullptr};\n    QTextEdit* description_edit{nullptr};\n    QLineEdit* base_url_edit{nullptr};\n    QLineEdit* model_edit{nullptr};\n    QLineEdit* api_key_edit{nullptr};\n    QCheckBox* show_api_key_checkbox{nullptr};\n    QPushButton* ok_button{nullptr};\n};\n\n#endif // CUSTOMAPIDIALOG_HPP\n"
  },
  {
    "path": "app/include/CustomLLMDialog.hpp",
    "content": "#ifndef CUSTOMLLMDIALOG_HPP\n#define CUSTOMLLMDIALOG_HPP\n\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDialog>\n\nclass QLineEdit;\nclass QPushButton;\nclass QTextEdit;\n\n/**\n * @brief Dialog for creating or editing custom local LLM entries.\n */\nclass CustomLLMDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(CustomLLMDialog)\npublic:\n    /**\n     * @brief Construct a dialog for a new custom LLM entry.\n     * @param parent Parent widget.\n     */\n    explicit CustomLLMDialog(QWidget* parent = nullptr);\n    /**\n     * @brief Construct a dialog pre-populated with an existing entry.\n     * @param parent Parent widget.\n     * @param existing Existing custom LLM values to edit.\n     */\n    explicit CustomLLMDialog(QWidget* parent, const CustomLLM& existing);\n\n    /**\n     * @brief Return the dialog values as a CustomLLM entry.\n     */\n    CustomLLM result() const;\n\nprivate:\n    /**\n     * @brief Build the dialog layout and widgets.\n     */\n    void setup_ui();\n    /**\n     * @brief Connect widget signals to validation and handlers.\n     */\n    void wire_signals();\n    /**\n     * @brief Apply existing values to the input fields.\n     * @param existing Existing custom LLM values to load.\n     */\n    void apply_existing(const CustomLLM& existing);\n    /**\n     * @brief Validate inputs and update the ok button state.\n     */\n    void validate_inputs();\n    /**\n     * @brief Open a file picker to select a local model file.\n     */\n    void browse_for_file();\n\n    QLineEdit* name_edit{nullptr};\n    QTextEdit* description_edit{nullptr};\n    QLineEdit* path_edit{nullptr};\n    QPushButton* browse_button{nullptr};\n    QPushButton* ok_button{nullptr};\n};\n\n#endif // CUSTOMLLMDIALOG_HPP\n"
  },
  {
    "path": "app/include/DatabaseManager.hpp",
    "content": "#ifndef DATABASEMANAGER_HPP\n#define DATABASEMANAGER_HPP\n\n#include \"CategoryLanguage.hpp\"\n#include \"Types.hpp\"\n#include <string>\n#include <map>\n#include <vector>\n#include <unordered_map>\n#include <optional>\n#include <sqlite3.h>\n\nclass DatabaseManager {\npublic:\n    explicit DatabaseManager(std::string config_dir);\n    ~DatabaseManager();\n\n    bool is_file_already_categorized(const std::string &file_name);\n    struct ResolvedCategory {\n        int taxonomy_id;\n        std::string category;\n        std::string subcategory;\n    };\n\n    ResolvedCategory resolve_category(const std::string& category,\n                                      const std::string& subcategory);\n    ResolvedCategory resolve_category_for_language(const std::string& category,\n                                                   const std::string& subcategory,\n                                                   CategoryLanguage language);\n    std::optional<ResolvedCategory> get_category_translation(int taxonomy_id,\n                                                             CategoryLanguage language) const;\n    ResolvedCategory localize_category(const ResolvedCategory& resolved,\n                                       CategoryLanguage language) const;\n    CategorizedFile localize_categorized_file(const CategorizedFile& entry,\n                                              CategoryLanguage language) const;\n    bool upsert_category_translation(int taxonomy_id,\n                                     CategoryLanguage language,\n                                     const std::string& category,\n                                     const std::string& subcategory);\n\n    bool insert_or_update_file_with_categorization(const std::string& file_name,\n                                                   const std::string& file_type,\n                                                   const std::string& dir_path,\n                                                   const ResolvedCategory& resolved,\n                                                   bool used_consistency_hints,\n                                                   const std::string& suggested_name = \"\",\n                                                   bool rename_only = false,\n                                                   bool rename_applied = false);\n    std::vector<std::string> get_dir_contents_from_db(const std::string &dir_path);\n    bool remove_file_categorization(const std::string& dir_path,\n                                    const std::string& file_name,\n                                    const FileType file_type);\n    std::vector<CategorizedFile> remove_empty_categorizations(const std::string& dir_path);\n\n    std::vector<CategorizedFile> get_categorized_files(const std::string &directory_path);\n    std::vector<CategorizedFile> get_categorized_files_recursive(const std::string& directory_path);\n    std::optional<CategorizedFile> get_categorized_file(const std::string& dir_path,\n                                                        const std::string& file_name,\n                                                        FileType file_type);\n\n    /**\n     * @brief Looks up a cached category/subcategory for a specific directory+file.\n     * @param dir_path Directory path used for cache scoping.\n     * @param file_name File name to resolve.\n     * @param file_type File or directory.\n     * @return Pair of category/subcategory strings when present; empty when not found.\n     */\n    std::vector<std::string>\n        get_categorization_from_db(const std::string& dir_path,\n                                   const std::string& file_name,\n                                   FileType file_type);\n    void increment_taxonomy_frequency(int taxonomy_id);\n    std::vector<std::pair<std::string, std::string>>\n        get_taxonomy_snapshot(std::size_t max_entries,\n                              CategoryLanguage language = CategoryLanguage::English) const;\n    std::vector<std::pair<std::string, std::string>>\n        get_recent_categories_for_extension(const std::string& extension,\n                                            FileType file_type,\n                                            std::size_t limit) const;\n    bool clear_directory_categorizations(const std::string& dir_path,\n                                         bool recursive = false);\n    bool has_categorization_style_conflict(const std::string& dir_path,\n                                           bool desired_style,\n                                           bool recursive = false) const;\n    std::optional<bool> get_directory_categorization_style(const std::string& dir_path) const;\n\nprivate:\n    struct TaxonomyEntry {\n        int id;\n        std::string category;\n        std::string subcategory;\n        std::string normalized_category;\n        std::string normalized_subcategory;\n    };\n\n    void initialize_schema();\n    void initialize_taxonomy_schema();\n    void load_taxonomy_cache();\n    void load_translation_cache();\n    std::string normalize_label(const std::string& input) const;\n    static double string_similarity(const std::string& a, const std::string& b);\n    static std::string make_key(const std::string& norm_category,\n                                const std::string& norm_subcategory);\n    static std::string make_translation_entry_key(int taxonomy_id,\n                                                  CategoryLanguage language);\n    static std::string make_translation_lookup_key(CategoryLanguage language,\n                                                   const std::string& norm_category,\n                                                   const std::string& norm_subcategory);\n    std::pair<int, double> find_fuzzy_match(const std::string& norm_category,\n                                            const std::string& norm_subcategory) const;\n    int resolve_existing_taxonomy(const std::string& key,\n                                   const std::string& norm_category,\n                                   const std::string& norm_subcategory) const;\n    ResolvedCategory build_resolved_category(int taxonomy_id,\n                                             const std::string& fallback_category,\n                                             const std::string& fallback_subcategory,\n                                             const std::string& norm_category,\n                                             const std::string& norm_subcategory);\n    int create_taxonomy_entry(const std::string& category,\n                              const std::string& subcategory,\n                              const std::string& norm_category,\n                              const std::string& norm_subcategory);\n    int find_existing_taxonomy_id(const std::string& norm_category,\n                                  const std::string& norm_subcategory) const;\n    void ensure_alias_mapping(int taxonomy_id,\n                              const std::string& norm_category,\n                              const std::string& norm_subcategory);\n    const TaxonomyEntry* find_taxonomy_entry(int taxonomy_id) const;\n\n    std::map<std::string, std::string> cached_results;\n    std::string get_cached_category(const std::string &file_name);\n    void load_cache();\n    bool file_exists_in_db(const std::string &file_name, const std::string &file_path);\n\n    sqlite3* db;\n    const std::string config_dir;\n    const std::string db_file;\n    std::vector<TaxonomyEntry> taxonomy_entries;\n    std::unordered_map<std::string, int> canonical_lookup;\n    std::unordered_map<std::string, int> alias_lookup;\n    std::unordered_map<int, size_t> taxonomy_index;\n    std::unordered_map<std::string, ResolvedCategory> translation_entries;\n    std::unordered_map<std::string, int> translation_lookup;\n\n    static bool is_duplicate_category(\n        const std::vector<std::pair<std::string, std::string>>& results,\n        const std::pair<std::string, std::string>& candidate);\n    std::optional<std::pair<std::string, std::string>> build_recent_category_candidate(\n        const char* file_name_text,\n        const char* category_text,\n        const char* subcategory_text,\n        const std::string& normalized_extension,\n        bool has_extension) const;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/DialogUtils.hpp",
    "content": "#ifndef DIALOGUTILS_HPP\n#define DIALOGUTILS_HPP\n\n#include <string>\n\nclass QWidget;\n\nclass DialogUtils {\npublic:\n    static void show_error_dialog(QWidget* parent, const std::string& message);\n};\n\n#endif // DIALOGUTILS_HPP\n"
  },
  {
    "path": "app/include/DocumentTextAnalyzer.hpp",
    "content": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string>\n\nclass ILLMClient;\n\nstruct DocumentAnalysisResult {\n    /**\n     * @brief Short summary extracted from the document text.\n     */\n    std::string summary;\n    /**\n     * @brief Suggested filename based on the analyzed content (including extension).\n     */\n    std::string suggested_name;\n};\n\n/**\n * @brief Extracts document text and produces LLM-based summaries and rename suggestions.\n */\nclass DocumentTextAnalyzer {\npublic:\n    /**\n     * @brief Tuning knobs for document excerpting and filename cleanup.\n     */\n    struct Settings {\n        /**\n         * @brief Maximum characters to include in the excerpt sent to the LLM.\n         */\n        size_t max_characters = 8000;\n        /**\n         * @brief Maximum number of words to keep in the suggested filename.\n         */\n        size_t max_filename_words = 3;\n        /**\n         * @brief Maximum length of the suggested filename stem.\n         */\n        size_t max_filename_length = 50;\n        /**\n         * @brief Maximum number of tokens to generate for the response.\n         */\n        int max_tokens = 256;\n    };\n\n    /**\n     * @brief Construct with default settings.\n     */\n    DocumentTextAnalyzer();\n    /**\n     * @brief Construct with custom settings.\n     */\n    explicit DocumentTextAnalyzer(Settings settings);\n\n    /**\n     * @brief Analyze the document and return a summary + suggested filename.\n     * @param document_path Path to the document to analyze.\n     * @param llm LLM client used to generate the summary and filename.\n     * @return Analysis result containing summary and suggested filename.\n     */\n    DocumentAnalysisResult analyze(const std::filesystem::path& document_path,\n                                   ILLMClient& llm) const;\n\n    /**\n     * @brief Returns true if the file extension is supported for document analysis.\n     * @param path Document path to inspect.\n     * @return True when the document extension is supported.\n     */\n    static bool is_supported_document(const std::filesystem::path& path);\n    /**\n     * @brief Attempts to read a creation date from supported document metadata.\n     * @param path Document path to inspect.\n     * @return Creation date formatted as YYYY-MM when available.\n     */\n    static std::optional<std::string> extract_creation_date(const std::filesystem::path& path);\n\nprivate:\n    std::string extract_text(const std::filesystem::path& path) const;\n    std::string build_prompt(const std::string& excerpt,\n                             const std::string& file_name) const;\n    std::string sanitize_filename(const std::string& value,\n                                  size_t max_words,\n                                  size_t max_length) const;\n\n    static std::string normalize_filename(const std::string& base,\n                                          const std::filesystem::path& original_path);\n    static std::string trim(std::string value);\n    static std::string slugify(const std::string& value);\n\n    Settings settings_;\n};\n"
  },
  {
    "path": "app/include/DryRunPreviewDialog.hpp",
    "content": "#pragma once\n\n#include <QCoreApplication>\n#include <QDialog>\n#include <QTableWidget>\n\n#include <string>\n#include <vector>\n\nclass DryRunPreviewDialog : public QDialog {\n    Q_DECLARE_TR_FUNCTIONS(DryRunPreviewDialog)\npublic:\n    struct Entry {\n        std::string from_label;\n        std::string to_label;\n        std::string source_tooltip;\n        std::string destination_tooltip;\n    };\n\n    explicit DryRunPreviewDialog(const std::vector<Entry>& entries, QWidget* parent = nullptr);\n\nprivate:\n    void setup_ui(const std::vector<Entry>& entries);\n    QTableWidget* table_{nullptr};\n};\n"
  },
  {
    "path": "app/include/EmbeddedEnv.hpp",
    "content": "#ifndef EMBEDDED_ENV_H\n#define EMBEDDED_ENV_H\n\n#include <string>\n#include <stdexcept>\n\nclass EmbeddedEnv {\npublic:\n    explicit EmbeddedEnv(const std::string& resource_path);\n    void load_env();\n\nprivate:\n    std::string resource_path_;\n    std::string extract_env_content();\n    void parse_env(const std::string& env_content);\n    std::string trim(const std::string& str);\n};\n\n#endif\n"
  },
  {
    "path": "app/include/ErrorMessages.hpp",
    "content": "/**\n * @file ErrorMessages.hpp\n * @brief Translatable error message constants used throughout the UI.\n */\n#ifndef ERRORMESSAGES_H\n#define ERRORMESSAGES_H\n\n#include <libintl.h>\n\n/**\n * @brief Translate a string using gettext.\n * @param String String literal to translate.\n * @return Translated string (const char* managed by gettext).\n */\n#define _(String) gettext(String)\n\n/**\n * @brief Error message shown when no files are available for categorization.\n */\n#define ERR_NO_FILES_TO_CATEGORIZE _(\"There are no files or directories to categorize.\")\n/**\n * @brief Error message shown when the user provides an invalid path.\n */\n#define ERR_INVALID_PATH _(\"Invalid directory path.\")\n/**\n * @brief Error message shown when no internet connection is detected.\n */\n#define ERR_NO_INTERNET_CONNECTION _(\"No internet connection. Please check your network and try again.\")\n\n#endif\n"
  },
  {
    "path": "app/include/FileScanner.hpp",
    "content": "#ifndef FILE_SCANNER_HPP\n#define FILE_SCANNER_HPP\n\n#include <filesystem>\n#include <string>\n#include <vector>\n#include <optional>\n#include \"Types.hpp\"\n\nnamespace fs = std::filesystem;\n\nclass FileScanner {\npublic:\n    FileScanner() = default;\n    std::vector<FileEntry>\n        get_directory_entries(const std::string &directory_path,\n                              FileScanOptions options);\n\nprivate:\n    struct ScanContext;\n    void scan_non_recursive(const fs::path& scan_path,\n                            const ScanContext& context,\n                            std::vector<FileEntry>& results);\n    void scan_recursive(const fs::path& scan_path,\n                        const ScanContext& context,\n                        std::vector<FileEntry>& results);\n    void log_scan_warning(const ScanContext& context,\n                          const fs::path& path,\n                          const std::error_code& error,\n                          const char* action) const;\n    std::optional<FileEntry> build_entry(const fs::directory_entry& entry,\n                                         const ScanContext& context);\n    bool should_skip_entry(const fs::path& entry_path,\n                           const std::string& file_name,\n                           const ScanContext& context,\n                           const std::string& full_path) const;\n    std::optional<FileType> classify_entry(const fs::directory_entry& entry,\n                                           bool bundle,\n                                           bool is_directory,\n                                           const ScanContext& context) const;\n    bool is_file_hidden(const fs::path &path) const;\n    bool is_junk_file(const std::string& name) const;\n    bool is_file_bundle(const fs::path& path, bool is_directory) const;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/GeminiClient.hpp",
    "content": "#ifndef GEMINICLIENT_HPP\n#define GEMINICLIENT_HPP\n\n#include \"ILLMClient.hpp\"\n#include <Types.hpp>\n#include <string>\n\nclass GeminiClient : public ILLMClient {\npublic:\n    GeminiClient(std::string api_key, std::string model);\n    ~GeminiClient() override = default;\n\n    std::string categorize_file(const std::string& file_name,\n                                const std::string& file_path,\n                                FileType file_type,\n                                const std::string& consistency_context) override;\n    std::string complete_prompt(const std::string& prompt,\n                                int max_tokens) override;\n    void set_prompt_logging_enabled(bool enabled) override;\n\nprivate:\n    std::string api_key_;\n    std::string model_;\n    bool prompt_logging_enabled_{false};\n    std::string last_prompt_;\n\n    std::string send_api_request(const std::string& json_payload);\n    std::string make_categorization_payload(const std::string& file_name,\n                                            const std::string& file_path,\n                                            FileType file_type,\n                                            const std::string& consistency_context);\n    std::string make_generic_payload(const std::string& system_prompt,\n                                     const std::string& user_prompt,\n                                     int max_tokens) const;\n    std::string effective_model() const;\n};\n\n#endif // GEMINICLIENT_HPP\n"
  },
  {
    "path": "app/include/GgmlRuntimePaths.hpp",
    "content": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string_view>\n#include <vector>\n\nnamespace GgmlRuntimePaths {\n\nbool has_payload(const std::filesystem::path& dir);\n\nstd::vector<std::filesystem::path> macos_candidate_dirs(\n    const std::filesystem::path& exe_path,\n    std::string_view ggml_subdir);\n\nstd::optional<std::filesystem::path> resolve_macos_backend_dir(\n    const std::optional<std::filesystem::path>& current_dir,\n    const std::filesystem::path& exe_path,\n    std::string_view ggml_subdir);\n\n} // namespace GgmlRuntimePaths\n"
  },
  {
    "path": "app/include/ILLMClient.hpp",
    "content": "#pragma once\n#include \"Types.hpp\"\n#include <string>\n\nclass ILLMClient {\npublic:\n    virtual ~ILLMClient() = default;\n    virtual std::string categorize_file(const std::string& file_name,\n                                        const std::string& file_path,\n                                        FileType file_type,\n                                        const std::string& consistency_context) = 0;\n    virtual std::string complete_prompt(const std::string& prompt,\n                                        int max_tokens) = 0;\n    virtual void set_prompt_logging_enabled(bool enabled) = 0;\n};\n"
  },
  {
    "path": "app/include/ImageRenameMetadataService.hpp",
    "content": "#ifndef IMAGE_RENAME_METADATA_SERVICE_HPP\n#define IMAGE_RENAME_METADATA_SERVICE_HPP\n\n#include <chrono>\n#include <filesystem>\n#include <optional>\n#include <string>\n\nstruct sqlite3;\n\n/**\n * @brief Enriches image rename suggestions using EXIF date + reverse-geocoded place.\n *\n * Metadata sources:\n * - JPEG APP1 EXIF\n * - TIFF native EXIF\n * - PNG eXIf chunk\n * - HEIC/HEIF via exiftool fallback (when available in PATH)\n */\nclass ImageRenameMetadataService {\npublic:\n    /**\n     * @brief Creates a metadata enrichment service rooted in the given config directory.\n     *\n     * The directory is used to store the local reverse-geocode cache database.\n     *\n     * @param config_dir Base configuration directory for metadata cache files.\n     */\n    explicit ImageRenameMetadataService(std::string config_dir);\n    /**\n     * @brief Destroys the service and releases any open cache database resources.\n     */\n    ~ImageRenameMetadataService();\n\n    ImageRenameMetadataService(const ImageRenameMetadataService&) = delete;\n    ImageRenameMetadataService& operator=(const ImageRenameMetadataService&) = delete;\n\n    /**\n     * @brief Adds metadata prefixes to a suggested image filename when available.\n     *\n     * Prefix order is date first, then place, e.g. `2014-03-10_venice_black_ducks.jpg`.\n     * If EXIF metadata is missing or place lookup cannot be done, the original\n     * suggestion is returned unchanged.\n     *\n     * @param image_path Absolute or relative image file path.\n     * @param suggested_name Suggested filename generated by image analysis.\n     * @return Suggested filename with metadata prefixes when available.\n     */\n    std::string enrich_suggested_name(const std::filesystem::path& image_path,\n                                      const std::string& suggested_name);\n\n    /**\n     * @brief Extracts the normalized capture date (`YYYY-MM-DD`) from image metadata.\n     *\n     * Returns `std::nullopt` when no supported metadata date is available.\n     *\n     * @param image_path Absolute or relative image file path.\n     * @return Normalized capture date, or `std::nullopt` if unavailable.\n     */\n    std::optional<std::string> extract_capture_date(\n        const std::filesystem::path& image_path) const;\n\n    /**\n     * @brief Utility used by tests and callers to compose prefixed filenames.\n     *\n     * @param suggested_name Base suggested filename.\n     * @param date_prefix Optional date prefix (typically `YYYY-MM-DD`).\n     * @param place_prefix Optional place prefix.\n     * @return Filename prefixed with available metadata components.\n     */\n    static std::string apply_prefix_to_filename(const std::string& suggested_name,\n                                                const std::optional<std::string>& date_prefix,\n                                                const std::optional<std::string>& place_prefix);\n\nprivate:\n    struct ExifMetadata {\n        std::optional<std::string> capture_date;\n        std::optional<double> latitude;\n        std::optional<double> longitude;\n    };\n\n    struct CacheLookup {\n        bool found{false};\n        std::optional<std::string> place;\n    };\n\n    struct ReverseGeocodeResult {\n        bool success{false};\n        std::optional<std::string> place;\n    };\n\n    /**\n     * @brief Opens or creates the reverse-geocode cache database.\n     * @return True when the cache database is available for use.\n     */\n    bool open_cache_db();\n    /**\n     * @brief Extracts supported EXIF metadata fields from an image file.\n     * @param image_path Absolute or relative image file path.\n     * @return Parsed metadata fields used for date/place prefixing.\n     */\n    ExifMetadata extract_exif_metadata(const std::filesystem::path& image_path) const;\n    /**\n     * @brief Resolves a place prefix from GPS coordinates using cache and reverse geocoding.\n     * @param latitude GPS latitude in decimal degrees.\n     * @param longitude GPS longitude in decimal degrees.\n     * @return Slugified place prefix, or `std::nullopt` when unavailable.\n     */\n    std::optional<std::string> resolve_place_prefix(double latitude, double longitude);\n    /**\n     * @brief Looks up a cached place prefix by coordinate keys.\n     * @param lat_key Normalized latitude cache key.\n     * @param lon_key Normalized longitude cache key.\n     * @return Cache lookup result indicating hit/miss and optional place value.\n     */\n    CacheLookup lookup_cache(const std::string& lat_key, const std::string& lon_key) const;\n    /**\n     * @brief Inserts or updates a cached place prefix for coordinate keys.\n     * @param lat_key Normalized latitude cache key.\n     * @param lon_key Normalized longitude cache key.\n     * @param place Optional place prefix to store.\n     */\n    void upsert_cache(const std::string& lat_key,\n                      const std::string& lon_key,\n                      const std::optional<std::string>& place) const;\n    /**\n     * @brief Performs reverse geocoding for GPS coordinates.\n     * @param latitude GPS latitude in decimal degrees.\n     * @param longitude GPS longitude in decimal degrees.\n     * @return Reverse-geocode result with success flag and optional place prefix.\n     */\n    ReverseGeocodeResult reverse_geocode(double latitude, double longitude);\n    /**\n     * @brief Checks whether the network is available for reverse geocoding.\n     * @return True when online requests can be attempted.\n     */\n    bool network_available();\n\n    /**\n     * @brief Converts arbitrary text into a filesystem-safe lowercase slug.\n     * @param value Input text.\n     * @return Sanitized slug string.\n     */\n    static std::string slugify(const std::string& value);\n    /**\n     * @brief Normalizes EXIF date values to `YYYY-MM-DD`.\n     * @param value Raw EXIF date text.\n     * @return Normalized date, or `std::nullopt` if parsing fails.\n     */\n    static std::optional<std::string> normalize_exif_date(const std::string& value);\n    /**\n     * @brief Formats a floating-point coordinate into a stable cache key.\n     * @param value Coordinate value in decimal degrees.\n     * @return Normalized coordinate key string.\n     */\n    static std::string format_coord_key(double value);\n\n    std::string config_dir_;\n    sqlite3* cache_db_{nullptr};\n    std::chrono::steady_clock::time_point last_geocode_request_{};\n    bool network_checked_{false};\n    bool network_available_{false};\n};\n\n#endif // IMAGE_RENAME_METADATA_SERVICE_HPP\n"
  },
  {
    "path": "app/include/IniConfig.hpp",
    "content": "#ifndef INICONFIG_HPP\n#define INICONFIG_HPP\n\n#include <string>\n#include <map>\n#include <fstream>\n#include <sstream>\n\n\nclass IniConfig {\npublic:\n    bool load(const std::string &filename);\n    std::string getValue(const std::string &section, const std::string &key, const std::string &default_value = \"\") const;\n    void setValue(const std::string &section, const std::string &key, const std::string &value);\n    bool save(const std::string &filename) const;\n    bool hasValue(const std::string& section, const std::string& key) const;\n\nprivate:\n    std::map<std::string, std::map<std::string, std::string>> data;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/LLMClient.hpp",
    "content": "#ifndef LLMCLIENT_HPP\n#define LLMCLIENT_HPP\n\n#include \"ILLMClient.hpp\"\n#include <Types.hpp>\n#include <string>\n\nclass LLMClient : public ILLMClient {\npublic:\n    /**\n     * @brief Create an OpenAI-compatible client, optionally targeting a custom base URL.\n     */\n    LLMClient(std::string api_key, std::string model, std::string base_url = std::string());\n    ~LLMClient() override;\n    std::string categorize_file(const std::string& file_name,\n                                const std::string& file_path,\n                                FileType file_type,\n                                const std::string& consistency_context) override;\n    std::string complete_prompt(const std::string& prompt,\n                                int max_tokens) override;\n    void set_prompt_logging_enabled(bool enabled) override;\n\nprivate:\n    std::string api_key;\n    std::string send_api_request(std::string json_payload);\n    std::string make_payload(const std::string &file_name,\n                             const std::string &file_path,\n                                const FileType file_type,\n                                const std::string& consistency_context);\n    std::string make_generic_payload(const std::string& system_prompt,\n                                     const std::string& user_prompt,\n                                     int max_tokens) const;\n    std::string effective_model() const;\n    /**\n     * @brief Resolve the final /chat/completions URL from the base URL or default.\n     */\n    std::string resolve_api_url() const;\n    bool prompt_logging_enabled{false};\n    std::string last_prompt;\n    std::string model;\n    std::string base_url;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/LLMDownloader.hpp",
    "content": "#pragma once\n#include \"Settings.hpp\"\n#include <atomic>\n#include <curl/system.h>\n#include <functional>\n#include <map>\n#include <mutex>\n#include <string>\n#include <thread>\n#include <curl/curl.h>\n\n\n/**\n * @brief Handles downloading local LLM model files with resume support.\n */\nclass LLMDownloader\n{\npublic:\n    /**\n     * @brief Constructs a downloader for the given URL.\n     * @param download_url URL of the model to download.\n     */\n    explicit LLMDownloader(const std::string& download_url);\n    /**\n     * @brief Initializes curl state if not already initialized.\n     */\n    void init_if_needed();\n    /**\n     * @brief Returns true if initialization has completed.\n     * @return True when initialized.\n     */\n    bool is_inited();\n    /**\n     * @brief Starts an async download with callbacks.\n     * @param progress_cb Called with progress percentage (0-100).\n     * @param on_complete_cb Called when download completes successfully.\n     * @param on_status_text Called with status text updates.\n     * @param on_error_cb Called with error message on failure.\n     */\n    void start_download(std::function<void(double)> progress_cb,\n                        std::function<void()> on_complete_cb,\n                        std::function<void(const std::string &)> on_status_text,\n                        std::function<void(const std::string &)> on_error_cb);\n    /**\n     * @brief Attempts to resume a partial download.\n     */\n    void try_resume_download();\n    /**\n     * @brief Returns true if the current download can be resumed.\n     * @return True when the download is resumable.\n     */\n    bool is_download_resumable() const;\n    /**\n     * @brief Returns true when the file is fully downloaded.\n     * @return True if download is complete.\n     */\n    bool is_download_complete() const;\n\n    /**\n     * @brief Returns the server-reported content length.\n     * @return Content length in bytes, or 0 if unknown.\n     */\n    long long get_real_content_length() const;\n    /**\n     * @brief Returns the resolved destination path for the download.\n     * @return Full path to the downloaded file.\n     */\n    std::string get_download_destination() const;\n    /**\n     * @brief Returns the temporary path used for in-progress downloads.\n     * @return Full path to the partial download artifact.\n     */\n    std::string get_partial_download_destination() const;\n\n    /**\n     * @brief Starts a download with simpler callbacks.\n     * @param on_progress Called with progress percentage (0-100).\n     * @param on_complete Called with success flag and message.\n     */\n    void start(std::function<void(double)> on_progress,\n               std::function<void(bool, const std::string&)> on_complete);\n\n    /**\n     * @brief Timestamp of last progress update (exposed for UI refresh).\n     */\n    std::chrono::steady_clock::time_point last_progress_update;\n    \n    /**\n     * @brief Destructor; cancels any active download thread.\n     */\n    ~LLMDownloader();\n\n    /**\n     * @brief Download status for local or remote states.\n     */\n    enum class DownloadStatus {\n        NotStarted,\n        InProgress,\n        Complete\n    };\n    \n    /**\n     * @brief Returns status based on local filesystem state.\n     * @return Local download status.\n     */\n    DownloadStatus get_local_download_status() const;\n    /**\n     * @brief Returns the live download status.\n     * @return Current download status.\n     */\n    DownloadStatus get_download_status() const;\n    /**\n     * @brief Cancels an in-progress download.\n     */\n    void cancel_download();\n    /**\n     * @brief Updates the download URL (resets internal state).\n     * @param new_url New URL to download from.\n     */\n    void set_download_url(const std::string& new_url);\n    /**\n     * @brief Returns the current download URL.\n     * @return Download URL string.\n     */\n    std::string get_download_url();\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    class LLMDownloaderTestAccess {\n    public:\n        /**\n         * @brief Overrides the cached content length for tests.\n         * @param downloader Downloader instance under test.\n         * @param length Content length in bytes.\n         */\n        static void set_real_content_length(LLMDownloader& downloader, long long length);\n        /**\n         * @brief Overrides the download destination path for tests.\n         * @param downloader Downloader instance under test.\n         * @param path Destination file path.\n         */\n        static void set_download_destination(LLMDownloader& downloader, const std::string& path);\n        /**\n         * @brief Seeds resume headers for tests.\n         * @param downloader Downloader instance under test.\n         * @param content_length Content length in bytes.\n         */\n        static void set_resume_headers(LLMDownloader& downloader, long long content_length);\n    };\n#endif\n\nprivate:\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class LLMDownloaderTestAccess;\n#endif\n    bool initialized{false};\n    std::string url;\n    std::string destination_dir;\n\n    std::thread download_thread;\n    std::map<std::string, std::string> curl_headers;\n    mutable std::mutex mutex;\n\n    std::function<void(double)> progress_callback;\n    std::function<void()> on_download_complete;\n    std::function<void(const std::string&)> on_status_text;\n    std::function<void(const std::string&)> on_download_error;\n\n    bool resumable{false};\n    long long real_content_length{0};\n    std::string download_destination;\n\n    /**\n     * @brief Curl write callback for file download.\n     * @param ptr Data buffer.\n     * @param size Element size.\n     * @param nmemb Element count.\n     * @param stream Output file stream.\n     * @return Bytes written.\n     */\n    static size_t write_data(void* ptr, size_t size, size_t nmemb, FILE* stream);\n    /**\n     * @brief Curl callback that discards data (used for head requests).\n     * @param ptr Data buffer.\n     * @param size Element size.\n     * @param nmemb Element count.\n     * @param userdata User data.\n     * @return Bytes processed.\n     */\n    static size_t discard_callback(char *ptr, size_t size, size_t nmemb, void *userdata);\n    /**\n     * @brief Curl header callback to parse response headers.\n     * @param buffer Header buffer.\n     * @param size Element size.\n     * @param nitems Element count.\n     * @param userdata User data.\n     * @return Bytes processed.\n     */\n    static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);\n    /**\n     * @brief Curl progress callback for download updates.\n     * @param clientp User data.\n     * @param dltotal Total bytes.\n     * @param dlnow Bytes downloaded.\n     * @return 0 to continue, non-zero to abort.\n     */\n    static int progress_func(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t, curl_off_t);\n\n    /**\n     * @brief Returns the default directory for storing downloaded LLMs.\n     * @return Path to default LLM download directory.\n     */\n    std::string get_default_llm_destination();\n    /**\n     * @brief Computes and stores the download destination file path.\n     */\n    void set_download_destination();\n    /**\n     * @brief Path to cached metadata file.\n     * @return Metadata file path.\n     */\n    std::string metadata_path() const;\n    /**\n     * @brief Path to the partial download file used during transfer/resume.\n     * @return Temporary file path.\n     */\n    std::string partial_download_path() const;\n    /**\n     * @brief Loads cached metadata for resume and progress.\n     */\n    void load_cached_metadata();\n    /**\n     * @brief Persists metadata to disk.\n     */\n    void persist_cached_metadata() const;\n    /**\n     * @brief Moves legacy partial downloads from the final path into the temp path.\n     */\n    void migrate_legacy_partial_download_if_needed();\n    /**\n     * @brief Parses cached or response headers for resume support.\n     */\n    void parse_headers();\n    /**\n     * @brief Executes the download in the worker thread.\n     */\n    void perform_download();\n    /**\n     * @brief Marks the download as resumable.\n     */\n    void mark_download_resumable();\n    /**\n     * @brief Notifies subscribers that the download finished.\n     */\n    void notify_download_complete();\n    /**\n     * @brief Applies common curl options shared across requests.\n     * @param curl Curl handle.\n     */\n    void setup_common_curl_options(CURL *curl);\n    /**\n     * @brief Applies curl options for header probing.\n     * @param curl Curl handle.\n     */\n    void setup_header_curl_options(CURL *curl);\n    /**\n     * @brief Applies curl options for the download request.\n     * @param curl Curl handle.\n     * @param fp File pointer for output.\n     * @param resume_offset Resume offset in bytes.\n     */\n    void setup_download_curl_options(CURL *curl, FILE *fp, long resume_offset);\n    /**\n     * @brief Determines the byte offset for resuming downloads.\n     * @return Resume offset in bytes.\n     */\n    long determine_resume_offset() const;\n    /**\n     * @brief Opens the output file at the given resume offset.\n     * @param resume_offset Resume offset in bytes.\n     * @return File pointer or nullptr on failure.\n     */\n    FILE *open_output_file(long resume_offset) const;\n    /**\n     * @brief Returns true if a partial download exists.\n     * @return True when a partial download exists.\n     */\n    bool has_existing_partial_download() const;\n    /**\n     * @brief Returns true when the server supports resuming downloads.\n     * @return True when resume is supported.\n     */\n    bool server_supports_resume_locked() const;\n    /**\n     * @brief Validates a content-length header value.\n     * @param value Header string.\n     * @return True when the value is a valid content length.\n     */\n    bool has_valid_content_length(const std::string& value) const;\n\n    std::atomic<bool> cancel_requested{false};\n    long resume_offset = 0;\n};\n"
  },
  {
    "path": "app/include/LLMErrors.hpp",
    "content": "#ifndef LLM_ERRORS_HPP\n#define LLM_ERRORS_HPP\n\n#include <stdexcept>\n#include <string>\n\nclass BackoffError : public std::runtime_error {\npublic:\n    BackoffError(const std::string& message, int retry_seconds)\n        : std::runtime_error(message), retry_after_seconds_(retry_seconds) {}\n\n    int retry_after_seconds() const { return retry_after_seconds_; }\n\nprivate:\n    int retry_after_seconds_{0};\n};\n\n#endif // LLM_ERRORS_HPP\n"
  },
  {
    "path": "app/include/LLMSelectionDialog.hpp",
    "content": "#ifndef LLMSELECTIONDIALOG_HPP\n#define LLMSELECTIONDIALOG_HPP\n\n#include \"LLMDownloader.hpp\"\n#include \"Types.hpp\"\n\n#include <QCoreApplication>\n#include <QDialog>\n\n#include <atomic>\n#include <memory>\n#include <mutex>\n#include <string>\n\nclass QLabel;\nclass QProgressBar;\nclass QPushButton;\nclass QRadioButton;\nclass QDialogButtonBox;\nclass QWidget;\nclass QString;\nclass QComboBox;\nclass QListWidget;\nclass QLineEdit;\nclass QCheckBox;\nclass QToolButton;\nclass QScrollArea;\nclass QShowEvent;\n\nclass Settings;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nclass LLMSelectionDialogTestAccess;\n#endif\n\nclass LLMSelectionDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(LLMSelectionDialog)\npublic:\n    explicit LLMSelectionDialog(Settings& settings, QWidget* parent = nullptr);\n    ~LLMSelectionDialog() override;\n\n    LLMChoice get_selected_llm_choice() const;\n    std::string get_selected_custom_llm_id() const;\n    /**\n     * @brief Return the active custom API endpoint id.\n     */\n    std::string get_selected_custom_api_id() const;\n    std::string get_openai_api_key() const;\n    std::string get_openai_model() const;\n    std::string get_gemini_api_key() const;\n    std::string get_gemini_model() const;\n    bool get_llm_downloads_expanded() const;\n\nprivate:\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class LLMSelectionDialogTestAccess;\n#endif\n\n    struct VisualLlmDownloadEntry {\n        std::string env_var;\n        std::string display_name;\n        QWidget* container{nullptr};\n        QLabel* title_label{nullptr};\n        QLabel* remote_url_label{nullptr};\n        QLabel* local_path_label{nullptr};\n        QLabel* file_size_label{nullptr};\n        QLabel* status_label{nullptr};\n        QProgressBar* progress_bar{nullptr};\n        QPushButton* download_button{nullptr};\n        QPushButton* delete_button{nullptr};\n        std::unique_ptr<LLMDownloader> downloader;\n        std::atomic<bool> is_downloading{false};\n    };\n\n    void setup_ui();\n    void connect_signals();\n    void showEvent(QShowEvent* event) override;\n    void update_ui_for_choice();\n    void update_legacy_local_3b_visibility();\n    void update_radio_selection();\n    void update_custom_choice_ui();\n    /**\n     * @brief Update UI state for the custom API selection.\n     */\n    void update_custom_api_choice_ui();\n    void update_openai_fields_state();\n    void update_gemini_fields_state();\n    bool openai_inputs_valid() const;\n    bool gemini_inputs_valid() const;\n    void update_local_choice_ui();\n    void update_download_info();\n    void start_download();\n    /**\n     * @brief Delete the downloaded local LLM file after confirmation.\n     */\n    void handle_delete_download();\n    void refresh_downloader();\n    void set_status_message(const QString& message);\n    std::string current_download_env_var() const;\n    void refresh_custom_lists();\n    /**\n     * @brief Refresh the custom API dropdown list.\n     */\n    void refresh_custom_api_lists();\n    void handle_add_custom();\n    void handle_edit_custom();\n    void handle_delete_custom();\n    void update_custom_buttons();\n    void select_custom_by_id(const std::string& id);\n    /**\n     * @brief Open the dialog to add a custom API entry.\n     */\n    void handle_add_custom_api();\n    /**\n     * @brief Open the dialog to edit the selected custom API entry.\n     */\n    void handle_edit_custom_api();\n    /**\n     * @brief Remove the selected custom API entry.\n     */\n    void handle_delete_custom_api();\n    /**\n     * @brief Update enabled states for custom API controls.\n     */\n    void update_custom_api_buttons();\n    /**\n     * @brief Select a custom API entry by id.\n     */\n    void select_custom_api_by_id(const std::string& id);\n    /**\n     * @brief Recalculate the dialog size based on visible content.\n     */\n    void adjust_dialog_size();\n    void setup_visual_llm_download_entry(VisualLlmDownloadEntry& entry,\n                                     QWidget* parent,\n                                     const QString& title,\n                                     const std::string& env_var);\n    void refresh_visual_llm_download_entry(VisualLlmDownloadEntry& entry);\n    void update_visual_llm_download_entry(VisualLlmDownloadEntry& entry);\n    void update_visual_llm_downloads();\n    void start_visual_llm_download(VisualLlmDownloadEntry& entry);\n    /**\n     * @brief Delete a downloaded visual LLM bundle after confirmation.\n     * @param entry Visual LLM entry to delete.\n     */\n    void handle_delete_visual_download(VisualLlmDownloadEntry& entry);\n    void set_visual_status_message(VisualLlmDownloadEntry& entry, const QString& message);\n    bool legacy_local_3b_available() const;\n\n    Settings& settings;\n    LLMChoice selected_choice{LLMChoice::Unset};\n    std::string selected_custom_id;\n    std::string selected_custom_api_id;\n    std::string openai_api_key;\n    std::string openai_model;\n    std::string gemini_api_key;\n    std::string gemini_model;\n    bool downloads_expanded_{true};\n\n    QRadioButton* openai_radio{nullptr};\n    QRadioButton* gemini_radio{nullptr};\n    QRadioButton* custom_api_radio{nullptr};\n    QRadioButton* local3_radio{nullptr};\n    QRadioButton* local3_legacy_radio{nullptr};\n    QRadioButton* local7_radio{nullptr};\n    QRadioButton* custom_radio{nullptr};\n    QToolButton* download_toggle_button{nullptr};\n    QScrollArea* scroll_area_{nullptr};\n    QComboBox* custom_combo{nullptr};\n    QPushButton* add_custom_button{nullptr};\n    QPushButton* edit_custom_button{nullptr};\n    QPushButton* delete_custom_button{nullptr};\n    QComboBox* custom_api_combo{nullptr};\n    QPushButton* add_custom_api_button{nullptr};\n    QPushButton* edit_custom_api_button{nullptr};\n    QPushButton* delete_custom_api_button{nullptr};\n    QLabel* remote_url_label{nullptr};\n    QLabel* local_path_label{nullptr};\n    QLabel* file_size_label{nullptr};\n    QLabel* status_label{nullptr};\n    QLabel* local3_legacy_desc{nullptr};\n    QProgressBar* progress_bar{nullptr};\n    QPushButton* download_button{nullptr};\n    QPushButton* delete_download_button{nullptr};\n    QPushButton* ok_button{nullptr};\n    QDialogButtonBox* button_box{nullptr};\n    QWidget* downloads_container{nullptr};\n    QWidget* download_section{nullptr};\n    QWidget* visual_llm_download_section{nullptr};\n    QWidget* openai_inputs{nullptr};\n    QWidget* gemini_inputs{nullptr};\n    QLineEdit* openai_api_key_edit{nullptr};\n    QLineEdit* openai_model_edit{nullptr};\n    QLineEdit* gemini_api_key_edit{nullptr};\n    QLineEdit* gemini_model_edit{nullptr};\n    QCheckBox* show_openai_api_key_checkbox{nullptr};\n    QCheckBox* show_gemini_api_key_checkbox{nullptr};\n    QLabel* openai_help_label{nullptr};\n    QLabel* openai_link_label{nullptr};\n    QLabel* gemini_help_label{nullptr};\n    QLabel* gemini_link_label{nullptr};\n\n    std::unique_ptr<LLMDownloader> downloader;\n    std::atomic<bool> is_downloading{false};\n    std::mutex download_mutex;\n\n    VisualLlmDownloadEntry llava_model_download;\n    VisualLlmDownloadEntry llava_mmproj_download;\n\n#if defined(AI_FILE_SORTER_TEST_BUILD)\n    bool use_network_available_override_{false};\n    bool network_available_override_{true};\n#endif\n};\n\n#endif // LLMSELECTIONDIALOG_HPP\n"
  },
  {
    "path": "app/include/LLMSelectionDialogTestAccess.hpp",
    "content": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include <optional>\n\n#include <QLabel>\n#include <QProgressBar>\n#include <QPushButton>\nclass LLMDownloader;\nclass LLMSelectionDialog;\n\nclass LLMSelectionDialogTestAccess {\npublic:\n    struct VisualEntryRefs {\n        QLabel* status_label{nullptr};\n        QPushButton* download_button{nullptr};\n        QProgressBar* progress_bar{nullptr};\n        LLMDownloader* downloader{nullptr};\n    };\n\n    static VisualEntryRefs llava_model_entry(LLMSelectionDialog& dialog);\n    static VisualEntryRefs llava_mmproj_entry(LLMSelectionDialog& dialog);\n    static void refresh_visual_downloads(LLMSelectionDialog& dialog);\n    static void update_llava_model_entry(LLMSelectionDialog& dialog);\n    static void start_llava_model_download(LLMSelectionDialog& dialog);\n    static void set_network_available_override(LLMSelectionDialog& dialog, std::optional<bool> value);\n};\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/Language.hpp",
    "content": "#ifndef LANGUAGE_HPP\n#define LANGUAGE_HPP\n\n#include <QString>\n\nenum class Language {\n    English,\n    French,\n    German,\n    Italian,\n    Spanish,\n    Turkish,\n    Korean,\n    Dutch\n};\n\ninline QString languageToString(Language language)\n{\n    switch (language) {\n    case Language::German:\n        return QStringLiteral(\"German\");\n    case Language::Italian:\n        return QStringLiteral(\"Italian\");\n    case Language::Spanish:\n        return QStringLiteral(\"Spanish\");\n    case Language::Turkish:\n        return QStringLiteral(\"Turkish\");\n    case Language::Korean:\n        return QStringLiteral(\"Korean\");\n    case Language::Dutch:\n        return QStringLiteral(\"Dutch\");\n    case Language::French:\n        return QStringLiteral(\"French\");\n    case Language::English:\n    default:\n        return QStringLiteral(\"English\");\n    }\n}\n\ninline Language languageFromString(const QString& value)\n{\n    const QString lowered = value.toLower();\n    if (lowered == QStringLiteral(\"french\") || lowered == QStringLiteral(\"fr\")) {\n        return Language::French;\n    }\n    if (lowered == QStringLiteral(\"german\") || lowered == QStringLiteral(\"de\")) {\n        return Language::German;\n    }\n    if (lowered == QStringLiteral(\"italian\") || lowered == QStringLiteral(\"it\")) {\n        return Language::Italian;\n    }\n    if (lowered == QStringLiteral(\"spanish\") || lowered == QStringLiteral(\"es\")) {\n        return Language::Spanish;\n    }\n    if (lowered == QStringLiteral(\"turkish\") || lowered == QStringLiteral(\"tr\")) {\n        return Language::Turkish;\n    }\n    if (lowered == QStringLiteral(\"korean\") || lowered == QStringLiteral(\"ko\")) {\n        return Language::Korean;\n    }\n    if (lowered == QStringLiteral(\"dutch\") || lowered == QStringLiteral(\"nl\")) {\n        return Language::Dutch;\n    }\n    return Language::English;\n}\n\n#endif // LANGUAGE_HPP\n"
  },
  {
    "path": "app/include/LlamaModelParams.hpp",
    "content": "#pragma once\n\n#include \"llama.h\"\n#include <memory>\n#include <string>\n\nnamespace spdlog { class logger; }\n\nllama_model_params build_model_params_for_path(const std::string& model_path,\n                                               const std::shared_ptr<spdlog::logger>& logger);\n"
  },
  {
    "path": "app/include/LlavaImageAnalyzer.hpp",
    "content": "#pragma once\n\n#include <cstdint>\n#include <filesystem>\n#include <functional>\n#include <optional>\n#include <string>\n#include <string_view>\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\n#include \"ggml.h\"\n\nstruct llama_model;\nstruct llama_context;\nstruct llama_vocab;\nstruct mtmd_context;\nstruct mtmd_bitmap;\n#endif\n\n/**\n * @brief Result returned by LlavaImageAnalyzer.\n */\nstruct LlavaImageAnalysisResult {\n    /**\n     * @brief Natural language description of the image contents.\n     */\n    std::string description;\n    /**\n     * @brief Suggested filename derived from the description.\n     */\n    std::string suggested_name;\n};\n\n/**\n * @brief Runs local LLaVA inference to describe images and suggest filenames.\n */\nclass LlavaImageAnalyzer {\npublic:\n    /**\n     * @brief Analyzer configuration for LLaVA inference.\n     */\n    struct Settings {\n        /** @brief Context length (tokens). */\n        int32_t n_ctx = 4096;\n        /** @brief Maximum tokens to predict. */\n        int32_t n_predict = 80;\n        /** @brief Number of CPU threads to use (0 = auto). */\n        int32_t n_threads = 0;\n        /** @brief Sampling temperature. */\n        float temperature = 0.2f;\n        /** @brief Whether to use GPU acceleration. */\n        bool use_gpu = true;\n        /** @brief Enable verbose visual model logging. */\n        bool log_visual_output = false;\n        /**\n         * @brief Optional callback for image batch progress.\n         * @param current_batch Batch index (1-based).\n         * @param total_batches Total number of batches.\n         */\n        std::function<void(int32_t current_batch, int32_t total_batches)> batch_progress;\n    };\n\n    /**\n     * @brief Constructs the analyzer with explicit settings.\n     * @param model_path Path to the LLaVA text model (GGUF).\n     * @param mmproj_path Path to the LLaVA mmproj file (GGUF).\n     * @param settings Inference settings.\n     */\n    LlavaImageAnalyzer(const std::filesystem::path& model_path,\n                       const std::filesystem::path& mmproj_path,\n                       Settings settings);\n    /**\n     * @brief Constructs the analyzer with default settings.\n     * @param model_path Path to the LLaVA text model (GGUF).\n     * @param mmproj_path Path to the LLaVA mmproj file (GGUF).\n     */\n    LlavaImageAnalyzer(const std::filesystem::path& model_path,\n                       const std::filesystem::path& mmproj_path);\n    /**\n     * @brief Destructor; releases model resources.\n     */\n    ~LlavaImageAnalyzer();\n\n    LlavaImageAnalyzer(const LlavaImageAnalyzer&) = delete;\n    LlavaImageAnalyzer& operator=(const LlavaImageAnalyzer&) = delete;\n\n    /**\n     * @brief Analyze an image and return description + filename suggestion.\n     * @param image_path Path to the image file.\n     * @return Analysis result with description and suggested name.\n     */\n    LlavaImageAnalysisResult analyze(const std::filesystem::path& image_path);\n\n    /**\n     * @brief Returns true if the image path has a supported extension.\n     * @param path Path to inspect.\n     * @return True when the file is supported.\n     */\n    static bool is_supported_image(const std::filesystem::path& path);\n\nprivate:\n    /**\n     * @brief Builds the description prompt for the visual model.\n     * @return Prompt string.\n     */\n    std::string build_description_prompt() const;\n    /**\n     * @brief Builds the filename prompt from an image description.\n     * @param description Model-generated description.\n     * @return Prompt string.\n     */\n    std::string build_filename_prompt(const std::string& description) const;\n#ifdef AI_FILE_SORTER_HAS_MTMD\n    /**\n     * @brief Runs inference on the given bitmap.\n     * @param bitmap Input bitmap.\n     * @param prompt Prompt to run.\n     * @param max_tokens Maximum tokens to generate.\n     * @return Model response text.\n     */\n    std::string infer_text(mtmd_bitmap* bitmap,\n                           const std::string& prompt,\n                           int32_t max_tokens);\n#else\n    /**\n     * @brief Runs inference on the given bitmap (stub for non-MTMD builds).\n     * @param bitmap Input bitmap.\n     * @param prompt Prompt to run.\n     * @param max_tokens Maximum tokens to generate.\n     * @return Model response text.\n     */\n    std::string infer_text(void* bitmap,\n                           const std::string& prompt,\n                           int32_t max_tokens);\n#endif\n    /**\n     * @brief Sanitizes a suggested filename.\n     * @param value Raw suggested filename.\n     * @param max_words Max number of words.\n     * @param max_length Max character length.\n     * @return Sanitized filename.\n     */\n    std::string sanitize_filename(const std::string& value,\n                                  size_t max_words,\n                                  size_t max_length) const;\n\n    /**\n     * @brief Trims whitespace from both ends of a string.\n     * @param value Input string.\n     * @return Trimmed string.\n     */\n    static std::string trim(std::string value);\n    /**\n     * @brief Converts a string into a slug safe for filenames.\n     * @param value Input string.\n     * @return Slugified string.\n     */\n    static std::string slugify(const std::string& value);\n    /**\n     * @brief Normalizes a filename based on the original image path.\n     * @param base Base filename.\n     * @param original_path Path to the original image.\n     * @return Normalized filename.\n     */\n    static std::string normalize_filename(const std::string& base,\n                                          const std::filesystem::path& original_path);\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\n    llama_model* model_{nullptr};\n    llama_context* context_{nullptr};\n    mtmd_context* vision_ctx_{nullptr};\n    const llama_vocab* vocab_{nullptr};\n    std::filesystem::path model_path_;\n    std::filesystem::path mmproj_path_;\n    std::optional<bool> visual_gpu_override_;\n    int32_t context_tokens_{0};\n    int32_t batch_size_{512};\n    bool text_gpu_enabled_{false};\n    bool mmproj_gpu_enabled_{false};\n    void initialize_context();\n    void reset_context_state();\n    static void mtmd_progress_callback(const char* name,\n                                       int32_t current_batch,\n                                       int32_t total_batches,\n                                       void* user_data);\n#if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK)\n    /**\n     * @brief Optional MTMD log callback.\n     * @param level Log level.\n     * @param text Log message.\n     * @param user_data User data pointer.\n     */\n    static void mtmd_log_callback(enum ggml_log_level level,\n                                  const char* text,\n                                  void* user_data);\n#endif\n#endif\n    /**\n     * @brief Stored analyzer settings.\n     */\n    Settings settings_;\n};\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nnamespace LlavaImageAnalyzerTestAccess {\nint32_t default_visual_batch_size(bool gpu_enabled, std::string_view backend_name);\nint32_t visual_model_n_gpu_layers_for_model(const std::string& model_path);\n}\n#endif\n"
  },
  {
    "path": "app/include/LlmCatalog.hpp",
    "content": "#ifndef LLMCATALOG_HPP\n#define LLMCATALOG_HPP\n\n#include \"Settings.hpp\"\n\n#include <QString>\n#include <vector>\n\n/**\n * @brief Metadata for default local LLM downloads and labels.\n */\nstruct DefaultLlmEntry {\n    LLMChoice choice;\n    const char* url_env;\n    const char* name_env;\n    const char* fallback_name;\n};\n\n/**\n * @brief Returns the default local LLM entries in priority order.\n * @return List of default local LLM entries.\n */\nconst std::vector<DefaultLlmEntry>& default_llm_entries();\n\n/**\n * @brief Builds the UI label for a default local LLM entry.\n * @param entry Default LLM entry definition.\n * @return Localized label for display in UI/benchmark output.\n */\nQString default_llm_label(const DefaultLlmEntry& entry);\n\n/**\n * @brief Builds the UI label for a default local LLM choice.\n * @param choice LLM choice identifier.\n * @return Localized label, or a generic label when not found.\n */\nQString default_llm_label_for_choice(LLMChoice choice);\n\n#endif // LLMCATALOG_HPP\n"
  },
  {
    "path": "app/include/LocalLLMClient.hpp",
    "content": "#pragma once\n\n#include \"ILLMClient.hpp\"\n#include \"Types.hpp\"\n#include \"llama.h\"\n#include <functional>\n#include <memory>\n#include <string>\n\nnamespace spdlog { class logger; }\n\nclass LocalLLMClient : public ILLMClient {\npublic:\n    /**\n     * @brief Status events emitted by the local LLM client.\n     */\n    enum class Status {\n        /**\n         * @brief GPU backend initialization failed; the client fell back to CPU.\n         */\n        GpuFallbackToCpu\n    };\n    /**\n     * @brief Callback invoked when the local LLM client emits a status event.\n     * @param status Status event emitted by the client.\n     */\n    using StatusCallback = std::function<void(Status)>;\n    /**\n     * @brief Callback invoked when a GPU failure occurs to decide whether to retry on CPU.\n     * @param reason Short description of the failure cause.\n     * @return True to retry on CPU; false to abort.\n     */\n    using FallbackDecisionCallback = std::function<bool(const std::string& reason)>;\n\n    explicit LocalLLMClient(const std::string& model_path,\n                            FallbackDecisionCallback fallback_decision_callback = {});\n    ~LocalLLMClient();\n\n    std::string make_prompt(const std::string& file_name,\n                            const std::string& file_path,\n                            FileType file_type,\n                            const std::string& consistency_context);\n    std::string generate_response(const std::string& prompt,\n                                  int n_predict,\n                                  bool apply_sanitizer = true,\n                                  const std::string& system_prompt = {});\n    std::string categorize_file(const std::string& file_name,\n                                const std::string& file_path,\n                                FileType file_type,\n                                const std::string& consistency_context) override;\n    std::string complete_prompt(const std::string& prompt,\n                                int max_tokens) override;\n    void set_prompt_logging_enabled(bool enabled) override;\n    /**\n     * @brief Registers a status callback for runtime events.\n     * @param callback Callback to invoke when status events occur.\n     */\n    void set_status_callback(StatusCallback callback);\n    /**\n     * @brief Registers a callback to decide whether GPU failures should fall back to CPU.\n     * @param callback Callback to invoke when a GPU failure is detected.\n     */\n    void set_fallback_decision_callback(FallbackDecisionCallback callback);\n\nprivate:\n    void load_model_if_needed();\n    void configure_llama_logging(const std::shared_ptr<spdlog::logger>& logger) const;\n    llama_model_params prepare_model_params(const std::shared_ptr<spdlog::logger>& logger);\n    llama_model_params load_model_or_throw(llama_model_params model_params,\n                                           const std::shared_ptr<spdlog::logger>& logger);\n    void configure_context(int context_length, const llama_model_params& model_params);\n    /**\n     * @brief Emits a status event to the registered callback.\n     * @param status Status event to emit.\n     */\n    void notify_status(Status status) const;\n\n    std::string model_path;\n    llama_model* model;\n    llama_context* ctx;\n    const llama_vocab *vocab;\n    llama_sampler* smpl;\n    std::string sanitize_output(const std::string& output);\n    llama_context_params ctx_params;\n    bool prompt_logging_enabled{false};\n    StatusCallback status_callback_;\n    FallbackDecisionCallback fallback_decision_callback_;\n};\n"
  },
  {
    "path": "app/include/LocalLLMTestAccess.hpp",
    "content": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include <string>\n#include \"llama.h\"\n\nnamespace LocalLLMTestAccess {\n\nenum class BackendPreference {\n    Auto,\n    Cpu,\n    Cuda,\n    Vulkan\n};\n\nBackendPreference detect_preferred_backend();\nbool apply_cpu_backend(llama_model_params& params, BackendPreference preference);\nbool apply_vulkan_backend(const std::string& model_path,\n                          llama_model_params& params);\nbool handle_cuda_forced_off(bool cuda_forced_off,\n                            BackendPreference preference,\n                            llama_model_params& params);\nbool configure_cuda_backend(const std::string& model_path,\n                            llama_model_params& params);\nllama_model_params prepare_model_params_for_testing(const std::string& model_path);\nstd::string sanitize_output_for_testing(const std::string& output);\n\n} // namespace LocalLLMTestAccess\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/Logger.hpp",
    "content": "#ifndef LOGGER_HPP\n#define LOGGER_HPP\n\n#include <spdlog/spdlog.h>\n#include <spdlog/sinks/stdout_color_sinks.h>\n#include <spdlog/sinks/basic_file_sink.h>\n#include <spdlog/sinks/rotating_file_sink.h>\n#include <string>\n\nclass Logger {\npublic:\n    static std::string get_log_directory();\n    static void setup_loggers();\n    static std::shared_ptr<spdlog::logger> get_logger(const std::string &name);\n    static std::string get_log_file_path(const std::string &log_dir, const std::string &log_name);\n\nprivate:\n    static std::string get_xdg_cache_home();\n    static std::string get_windows_log_directory();\n    Logger() = delete;\n};\n\n#endif"
  },
  {
    "path": "app/include/MainApp.hpp",
    "content": "#ifndef MAINAPP_HPP\n#define MAINAPP_HPP\n\n#include \"CategorizationDialog.hpp\"\n#include \"CategorizationProgressDialog.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"CategorizationService.hpp\"\n#include \"ConsistencyPassService.hpp\"\n#include \"ResultsCoordinator.hpp\"\n#include \"FileScanner.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"Settings.hpp\"\n#include \"WhitelistStore.hpp\"\n#include \"UiTranslator.hpp\"\n#include \"UndoManager.hpp\"\n\n#include <QCoreApplication>\n#include <QMainWindow>\n#include <QPointer>\n#include <QStandardItemModel>\n#include <QMenu>\n#include <QAction>\n#include <QActionGroup>\n\n#include \"Language.hpp\"\n\n#include <atomic>\n#include <functional>\n#include <memory>\n#include <optional>\n#include <thread>\n#include <unordered_set>\n#include <unordered_map>\n#include <vector>\n\nclass QAction;\nclass QCheckBox;\nclass QRadioButton;\nclass QComboBox;\nclass QLabel;\nclass QDockWidget;\nclass QFileSystemModel;\nclass QLineEdit;\nclass QString;\nclass QPushButton;\nclass QToolButton;\nclass QTreeView;\nclass QStackedWidget;\nclass QWidget;\nclass QLabel;\nclass QEvent;\nclass MainAppUiBuilder;\nclass WhitelistManagerDialog;\nclass SuitabilityBenchmarkDialog;\n\nstruct CategorizedFile;\nstruct FileEntry;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nclass MainAppTestAccess;\n#endif\n\n/**\n * @brief Main Qt window coordinating scanning, categorization, and review flows.\n */\nclass MainApp : public QMainWindow\n{\n    Q_DECLARE_TR_FUNCTIONS(MainApp)\npublic:\n    /**\n     * @brief Outcome returned from the optional support prompt flow.\n     */\n    enum class SupportPromptResult { Support, NotSure };\n    /**\n     * @brief Constructs the main application window.\n     * @param settings Persistent settings store used by the window.\n     * @param development_mode True to enable development-only UI features.\n     * @param parent Optional parent widget.\n     */\n    explicit MainApp(Settings& settings, bool development_mode, QWidget* parent = nullptr);\n    /**\n     * @brief Destroys the main window and releases owned resources.\n     */\n    ~MainApp() override;\n\n    /**\n     * @brief Shows the main window and starts normal interactive use.\n     */\n    void run();\n    /**\n     * @brief Requests application shutdown and stops any active analysis work.\n     */\n    void shutdown();\n\n    /**\n     * @brief Opens the results review dialog for a completed categorization batch.\n     * @param categorized_files Files to display in the review dialog.\n     */\n    void show_results_dialog(const std::vector<CategorizedFile>& categorized_files);\n    /**\n     * @brief Shows a user-facing error dialog.\n     * @param message Error text to display.\n     */\n    void show_error_dialog(const std::string& message);\n    /**\n     * @brief Appends a progress message to the active progress UI.\n     * @param message Progress text to report.\n     */\n    void report_progress(const std::string& message);\n    /**\n     * @brief Requests cancellation of the currently running analysis, if any.\n     */\n    void request_stop_analysis();\n\n    /**\n     * @brief Returns the currently selected folder path from the UI.\n     * @return Folder path as UTF-8 text.\n     */\n    std::string get_folder_path() const;\n    /**\n     * @brief Returns whether the window is running in development mode.\n     * @return True when development-only features are enabled.\n     */\n    bool is_development_mode() const { return development_mode_; }\n\nprotected:\n    /**\n     * @brief Persists window state and handles shutdown when the window closes.\n     * @param event Qt close event being processed.\n     */\n    void closeEvent(QCloseEvent* event) override;\n\nprivate:\n    void setup_file_explorer();\n    void create_file_explorer_dock();\n    void setup_file_system_model();\n    void setup_file_explorer_view();\n    void connect_file_explorer_signals();\n    void apply_file_explorer_preferences();\n    void restore_tree_settings();\n    void restore_sort_folder_state();\n    void restore_file_scan_options();\n    void restore_file_explorer_visibility();\n    void restore_development_preferences();\n    void connect_signals();\n    void connect_folder_contents_signals();\n    void connect_checkbox_signals();\n    void connect_whitelist_signals();\n    void connect_edit_actions();\n    void start_updater();\n    void set_app_icon();\n\n    void load_settings();\n    void save_settings();\n    void sync_settings_to_ui();\n    void sync_ui_to_settings();\n    void retranslate_ui();\n    void on_language_selected(Language language);\n    void on_category_language_selected(CategoryLanguage language);\n    void initialize_whitelists();\n\n    void on_analyze_clicked();\n    void on_directory_selected(const QString& path,\n        bool user_initiated = false);\n    void ensure_one_checkbox_active(QCheckBox* changed_checkbox);\n    void update_file_scan_option(FileScanOptions option, bool enabled);\n    bool visual_llm_files_available() const;\n    /**\n     * @brief Enables/disables image analysis-related UI controls based on settings/state.\n     */\n    void update_image_analysis_controls();\n    /**\n     * @brief Updates the \"process images only\" toggle behavior and dependent controls.\n     */\n    void update_image_only_controls();\n    /**\n     * @brief Enables/disables document analysis-related UI controls based on settings/state.\n     */\n    void update_document_analysis_controls();\n    /**\n     * @brief Handles the main image-analysis checkbox toggling.\n     * @param checked True when image analysis is enabled.\n     */\n    void handle_image_analysis_toggle(bool checked);\n    /**\n     * @brief Opens the LLM selection dialog focused on visual model downloads.\n     */\n    void run_llm_selection_dialog_for_visual();\n    void update_analyze_button_state(bool analyzing);\n    void update_results_view_mode();\n    void update_folder_contents(const QString& directory);\n    void focus_file_explorer_on_path(const QString& path);\n\n    void handle_analysis_finished();\n    void handle_analysis_cancelled();\n    void handle_analysis_failure(const std::string& message);\n    void handle_no_files_to_sort();\n    void populate_tree_view(const std::vector<CategorizedFile>& files);\n\n    void perform_analysis();\n    void stop_running_analysis();\n    void show_llm_selection_dialog();\n    void on_about_activate();\n    void append_progress(const std::string& message);\n    void configure_progress_stages(const std::vector<CategorizationProgressDialog::StagePlan>& stages);\n    void set_progress_stage_items(CategorizationProgressDialog::StageId stage_id,\n                                  const std::vector<FileEntry>& items);\n    void set_progress_active_stage(CategorizationProgressDialog::StageId stage_id);\n    void mark_progress_stage_item_in_progress(CategorizationProgressDialog::StageId stage_id,\n                                              const FileEntry& entry);\n    void mark_progress_stage_item_completed(CategorizationProgressDialog::StageId stage_id,\n                                            const FileEntry& entry);\n    bool should_abort_analysis() const;\n    void prune_empty_cached_entries_for(const std::string& directory_path);\n    void log_cached_highlights();\n    void log_pending_queue();\n    void run_consistency_pass();\n    void handle_development_prompt_logging(bool checked);\n    void record_categorized_metrics(int count);\n    SupportPromptResult show_support_prompt_dialog(int categorized_files);\n    void undo_last_run();\n    bool perform_undo_from_plan(const QString& plan_path);\n    void show_suitability_benchmark_dialog(bool auto_start);\n    void maybe_show_suitability_benchmark();\n\n    std::unique_ptr<ILLMClient> make_llm_client();\n    void notify_recategorization_reset(const std::vector<CategorizedFile>& entries,\n                                       const std::string& reason);\n    void notify_recategorization_reset(const CategorizedFile& entry,\n                                       const std::string& reason);\n    void set_categorization_style(bool use_consistency);\n    bool ensure_folder_categorization_style(const std::string& folder_path);\n    void show_whitelist_manager();\n    void apply_whitelist_to_selector();\n\n    void run_on_ui(std::function<void()> func);\n    void run_on_ui_blocking(std::function<void()> func);\n    void changeEvent(QEvent* event) override;\n    FileScanOptions effective_scan_options() const;\n    bool prompt_text_cpu_fallback(const std::string& reason);\n\n    friend class MainAppUiBuilder;\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class MainAppTestAccess;\n#endif\n\n    Settings& settings;\n    DatabaseManager db_manager;\n    FileScanner dirscanner;\n    bool using_local_llm{false};\n\n    std::vector<CategorizedFile> already_categorized_files;\n    std::vector<CategorizedFile> new_files_with_categories;\n    std::vector<FileEntry> files_to_categorize;\n    std::vector<CategorizedFile> new_files_to_sort;\n\n    QPointer<QLineEdit> path_entry;\n    QPointer<QPushButton> analyze_button;\n    QPointer<QPushButton> browse_button;\n    QPointer<QLabel> path_label;\n    QPointer<QCheckBox> use_subcategories_checkbox;\n    QPointer<QLabel> categorization_style_heading;\n    QPointer<QRadioButton> categorization_style_refined_radio;\n    QPointer<QRadioButton> categorization_style_consistent_radio;\n    QPointer<QCheckBox> use_whitelist_checkbox;\n    QPointer<QComboBox> whitelist_selector;\n    QPointer<QCheckBox> categorize_files_checkbox;\n    QPointer<QCheckBox> categorize_directories_checkbox;\n    QPointer<QCheckBox> include_subdirectories_checkbox;\n    QPointer<QCheckBox> analyze_images_checkbox;\n    QPointer<QCheckBox> process_images_only_checkbox;\n    QPointer<QCheckBox> add_image_date_to_category_checkbox;\n    QPointer<QCheckBox> add_image_date_place_to_filename_checkbox;\n    QPointer<QCheckBox> add_audio_video_metadata_to_filename_checkbox;\n    QPointer<QCheckBox> offer_rename_images_checkbox;\n    QPointer<QCheckBox> rename_images_only_checkbox;\n    QPointer<QToolButton> image_options_toggle_button;\n    QPointer<QWidget> image_options_container;\n    QPointer<QCheckBox> analyze_documents_checkbox;\n    QPointer<QCheckBox> process_documents_only_checkbox;\n    QPointer<QCheckBox> offer_rename_documents_checkbox;\n    QPointer<QCheckBox> rename_documents_only_checkbox;\n    QPointer<QCheckBox> add_document_date_to_category_checkbox;\n    QPointer<QToolButton> document_options_toggle_button;\n    QPointer<QWidget> document_options_container;\n    QPointer<QTreeView> tree_view;\n    QPointer<QStandardItemModel> tree_model;\n    QPointer<QStackedWidget> results_stack;\n    QPointer<QTreeView> folder_contents_view;\n    QPointer<QFileSystemModel> folder_contents_model;\n    int tree_view_page_index_{-1};\n    int folder_view_page_index_{-1};\n\n    QPointer<QDockWidget> file_explorer_dock;\n    QPointer<QTreeView> file_explorer_view;\n    QPointer<QFileSystemModel> file_system_model;\n    QAction* file_explorer_menu_action{nullptr};\n    QMenu* file_menu{nullptr};\n    QMenu* edit_menu{nullptr};\n    QMenu* view_menu{nullptr};\n    QMenu* settings_menu{nullptr};\n    QMenu* development_menu{nullptr};\n    QMenu* development_settings_menu{nullptr};\n    QMenu* language_menu{nullptr};\n    QMenu* category_language_menu{nullptr};\n    QMenu* help_menu{nullptr};\n    QAction* file_quit_action{nullptr};\n    QAction* run_benchmark_action{nullptr};\n    QAction* copy_action{nullptr};\n    QAction* cut_action{nullptr};\n    QAction* paste_action{nullptr};\n    QAction* delete_action{nullptr};\n    QAction* undo_last_run_action{nullptr};\n    QAction* toggle_explorer_action{nullptr};\n    QAction* toggle_llm_action{nullptr};\n    QAction* manage_whitelists_action{nullptr};\n    QAction* development_prompt_logging_action{nullptr};\n    QAction* consistency_pass_action{nullptr};\n    QActionGroup* language_group{nullptr};\n    QAction* english_action{nullptr};\n    QAction* dutch_action{nullptr};\n    QAction* french_action{nullptr};\n    QAction* german_action{nullptr};\n    QAction* italian_action{nullptr};\n    QAction* spanish_action{nullptr};\n    QAction* turkish_action{nullptr};\n    QAction* korean_action{nullptr};\n    QActionGroup* category_language_group{nullptr};\n    QAction* category_language_dutch{nullptr};\n    QAction* category_language_english{nullptr};\n    QAction* category_language_french{nullptr};\n    QAction* category_language_german{nullptr};\n    QAction* category_language_italian{nullptr};\n    QAction* category_language_polish{nullptr};\n    QAction* category_language_portuguese{nullptr};\n    QAction* category_language_spanish{nullptr};\n    QAction* category_language_turkish{nullptr};\n    QAction* about_action{nullptr};\n    QAction* about_qt_action{nullptr};\n    QAction* about_agpl_action{nullptr};\n    QAction* support_project_action{nullptr};\n\n    std::unique_ptr<CategorizationDialog> categorization_dialog;\n    std::unique_ptr<CategorizationProgressDialog> progress_dialog;\n    std::unique_ptr<SuitabilityBenchmarkDialog> benchmark_dialog;\n\n    std::shared_ptr<spdlog::logger> core_logger;\n    std::shared_ptr<spdlog::logger> ui_logger;\n    WhitelistStore whitelist_store;\n    std::unique_ptr<WhitelistManagerDialog> whitelist_dialog;\n    CategorizationService categorization_service;\n    ConsistencyPassService consistency_pass_service;\n    ResultsCoordinator results_coordinator;\n    UndoManager undo_manager_;\n    bool development_mode_{false};\n    bool development_prompt_logging_enabled_{false};\n\n    FileScanOptions file_scan_options{FileScanOptions::None};\n    std::thread analyze_thread;\n    std::atomic<bool> stop_analysis{false};\n    bool analysis_in_progress_{false};\n    bool status_is_ready_{true};\n    bool suppress_explorer_sync_{false};\n    bool suppress_folder_view_sync_{false};\n    bool donation_prompt_active_{false};\n    std::optional<bool> text_cpu_fallback_choice_;\n    bool should_log_prompts() const;\n    void apply_development_logging();\n\n    std::unique_ptr<UiTranslator> ui_translator_;\n\n#if defined(AI_FILE_SORTER_TEST_BUILD)\n    std::function<bool()> visual_llm_available_probe_;\n    std::function<void()> llm_selection_runner_override_;\n    std::function<bool()> image_analysis_prompt_override_;\n#endif\n};\n\n#endif // MAINAPP_HPP\nclass WhitelistManagerDialog;\n"
  },
  {
    "path": "app/include/MainAppEditActions.hpp",
    "content": "#ifndef MAIN_APP_EDIT_ACTIONS_HPP\n#define MAIN_APP_EDIT_ACTIONS_HPP\n\n#include <QString>\n\nclass QLineEdit;\n\nclass MainAppEditActions {\npublic:\n    static void on_paste(QLineEdit* line_edit);\n    static void on_copy(QLineEdit* line_edit);\n    static void on_cut(QLineEdit* line_edit);\n    static void on_delete(QLineEdit* line_edit);\n\nprivate:\n    static void copy_to_clipboard(const QString& text);\n    static QString get_selection(QLineEdit* line_edit, bool delete_selection);\n};\n\n#endif\n"
  },
  {
    "path": "app/include/MainAppHelpActions.hpp",
    "content": "#ifndef MAIN_APP_HELP_ACTIONS_HPP\n#define MAIN_APP_HELP_ACTIONS_HPP\n\n#include <QString>\n\nclass QWidget;\n\nclass MainAppHelpActions {\npublic:\n    static void show_about(QWidget* parent);\n    static void show_agpl_info(QWidget* parent);\n    static QString support_page_url();\n    static bool open_support_page();\n};\n\n#endif // MAIN_APP_HELP_ACTIONS_HPP\n"
  },
  {
    "path": "app/include/MainAppTestAccess.hpp",
    "content": "/**\n * @file MainAppTestAccess.hpp\n * @brief Test-only accessors and helpers for MainApp.\n */\n#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"Types.hpp\"\n\n#include <QString>\n#include <QCheckBox>\n#include <QToolButton>\n#include <functional>\n#include <string>\n#include <unordered_set>\n#include <vector>\n\nclass MainApp;\nclass Settings;\n\n/**\n * @brief Provides test access to MainApp internals and helpers.\n */\nclass MainAppTestAccess {\npublic:\n    /**\n     * @brief Simulated responses for the support prompt flow.\n     */\n    enum class SimulatedSupportResult {\n        /// User entered a valid donation code and hid the prompt.\n        Support,\n        /// User is unsure.\n        NotSure\n    };\n\n    /**\n     * @brief Read the analyze button label text.\n     * @param app MainApp instance.\n     * @return Current analyze button text.\n     */\n    static QString analyze_button_text(const MainApp& app);\n    /**\n     * @brief Read the folder/path label text.\n     * @param app MainApp instance.\n     * @return Current path label text.\n     */\n    static QString path_label_text(const MainApp& app);\n    /**\n     * @brief Access the \\\"Categorize files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* categorize_files_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Analyze picture files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* analyze_images_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Process picture files only\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* process_images_only_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Add image creation date to category name\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* add_image_date_to_category_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Add photo date and place to filename\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* add_image_date_place_to_filename_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Add audio/video metadata to file name\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* add_audio_video_metadata_to_filename_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Offer to rename picture files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* offer_rename_images_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Do not categorize picture files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* rename_images_only_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Analyze document files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* analyze_documents_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Process document files only\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* process_documents_only_checkbox(MainApp& app);\n    /**\n     * @brief Access the \\\"Do not categorize document files\\\" checkbox.\n     * @param app MainApp instance.\n     * @return Pointer to the checkbox, or nullptr if unavailable.\n     */\n    static QCheckBox* rename_documents_only_checkbox(MainApp& app);\n    /**\n     * @brief Access the picture-analysis disclosure toggle.\n     * @param app MainApp instance.\n     * @return Pointer to the toggle button, or nullptr if unavailable.\n     */\n    static QToolButton* image_options_toggle_button(MainApp& app);\n    /**\n     * @brief Access the document-analysis disclosure toggle.\n     * @param app MainApp instance.\n     * @return Pointer to the toggle button, or nullptr if unavailable.\n     */\n    static QToolButton* document_options_toggle_button(MainApp& app);\n    /**\n     * @brief Split file entries into image/document/other buckets for analysis.\n     * @param files Input entries to split.\n     * @param analyze_images Whether to analyze images by content.\n     * @param analyze_documents Whether to analyze documents by content.\n     * @param process_images_only Whether only images should be processed.\n     * @param process_documents_only Whether only documents should be processed.\n     * @param rename_images_only Whether images should be rename-only.\n     * @param rename_documents_only Whether documents should be rename-only.\n     * @param categorize_files Whether non-analyzed files are eligible for categorization.\n     * @param use_full_path_keys Whether to key renamed files by full path.\n     * @param renamed_files Set of already-renamed file keys.\n     * @param image_entries Output vector of image entries.\n     * @param document_entries Output vector of document entries.\n     * @param other_entries Output vector of other entries.\n     */\n    static void split_entries_for_analysis(const std::vector<FileEntry>& files,\n                                           bool analyze_images,\n                                           bool analyze_documents,\n                                           bool process_images_only,\n                                           bool process_documents_only,\n                                           bool rename_images_only,\n                                           bool rename_documents_only,\n                                           bool categorize_files,\n                                           bool use_full_path_keys,\n                                           const std::unordered_set<std::string>& renamed_files,\n                                           std::vector<FileEntry>& image_entries,\n                                           std::vector<FileEntry>& document_entries,\n                                           std::vector<FileEntry>& other_entries);\n    /**\n     * @brief Override the probe used to detect visual LLM availability.\n     * @param app MainApp instance.\n     * @param probe Callback returning availability state.\n     */\n    static void set_visual_llm_available_probe(MainApp& app, std::function<bool()> probe);\n    /**\n     * @brief Override the visual LLM selection dialog runner.\n     * @param app MainApp instance.\n     * @param runner Callback invoked instead of showing the dialog.\n     */\n    static void set_llm_selection_runner(MainApp& app, std::function<void()> runner);\n    /**\n     * @brief Override the image analysis prompt flow.\n     * @param app MainApp instance.\n     * @param prompt Callback that returns whether to proceed.\n     */\n    static void set_image_analysis_prompt_override(MainApp& app, std::function<bool()> prompt);\n    /**\n     * @brief Returns whether a visual-analysis failure should offer CPU retry.\n     * @param reason Exception text produced by the failed visual analysis step.\n     * @return True when the failure looks like GPU memory pressure.\n     */\n    static bool should_offer_visual_cpu_fallback(const std::string& reason);\n    /**\n     * @brief Resolve the prompt filename used for document categorization.\n     * @param original_name Original file name.\n     * @param suggested_name Suggested file name, when available.\n     * @return Suggested name when present; otherwise the original name.\n     */\n    static std::string resolve_document_prompt_name(const std::string& original_name,\n                                                    const std::string& suggested_name);\n    /**\n     * @brief Build the document prompt path shown in categorization progress.\n     * @param full_path Original full path to the document.\n     * @param prompt_name File name to use in the categorization prompt.\n     * @param summary Optional summary appended for the LLM prompt.\n     * @return Prompt path string used for categorization.\n     */\n    static std::string build_document_prompt_path(const std::string& full_path,\n                                                  const std::string& prompt_name,\n                                                  const std::string& summary);\n    /**\n     * @brief Trigger a UI retranslate on the MainApp instance.\n     * @param app MainApp instance.\n     */\n    static void trigger_retranslate(MainApp& app);\n    /**\n     * @brief Record a count of categorized files for metrics.\n     * @param app MainApp instance.\n     * @param count Number of files to add.\n     */\n    static void add_categorized_files(MainApp& app, int count);\n    /**\n     * @brief Simulate the support prompt logic for tests.\n     * @param settings Settings instance to update.\n     * @param prompt_state Prompt state flag to mutate.\n     * @param count Number of files categorized in this increment.\n     * @param callback Callback to supply a simulated response.\n     */\n    static void simulate_support_prompt(Settings& settings,\n                                        bool& prompt_state,\n                                        int count,\n                                        std::function<SimulatedSupportResult(int)> callback);\n};\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/MainAppUiBuilder.hpp",
    "content": "#ifndef MAIN_APP_UI_BUILDER_HPP\n#define MAIN_APP_UI_BUILDER_HPP\n\n#include <QIcon>\n#include <QStyle>\n#include \"UiTranslator.hpp\"\n\nclass MainApp;\n\n/**\n * @brief Builds the MainApp widget tree, menus, and translation dependencies.\n */\nclass MainAppUiBuilder {\npublic:\n    /**\n     * @brief Builds the main window UI for the provided application instance.\n     * @param app Main application window to populate.\n     */\n    void build(MainApp& app);\n    /**\n     * @brief Collects the translator dependency bundle from the current UI state.\n     * @param app Main application window whose controls are referenced.\n     * @return Dependency bundle used by UiTranslator.\n     */\n    UiTranslator::Dependencies build_translator_dependencies(MainApp& app) const;\n\nprivate:\n    void build_central_panel(MainApp& app);\n    void build_menus(MainApp& app);\n    void build_file_menu(MainApp& app);\n    void build_edit_menu(MainApp& app);\n    void build_view_menu(MainApp& app);\n    void build_settings_menu(MainApp& app);\n    void build_development_menu(MainApp& app);\n    void build_help_menu(MainApp& app);\n    static QIcon icon_for(MainApp& app, const char* name, QStyle::StandardPixmap fallback);\n};\n\n#endif\n"
  },
  {
    "path": "app/include/MediaRenameMetadataService.hpp",
    "content": "/**\n * @file MediaRenameMetadataService.hpp\n * @brief Builds audio/video filename suggestions from embedded media metadata.\n */\n#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string>\n\n/**\n * @brief Suggests audio/video filenames using conventional metadata ordering.\n *\n * The composed format is `year_artist_album_title.ext` (missing fields are omitted,\n * while preserving order).\n */\nclass MediaRenameMetadataService {\npublic:\n    /**\n     * @brief Parsed metadata fields used for audio/video filename composition.\n     */\n    struct MetadataFields {\n        std::optional<std::string> year;\n        std::optional<std::string> artist;\n        std::optional<std::string> album;\n        std::optional<std::string> title;\n    };\n\n    /**\n     * @brief Proposes a filename for a supported audio/video file.\n     * @param media_path Full path to the media file.\n     * @return Suggested filename (including extension), or `std::nullopt` when no metadata-based\n     *         improvement is available.\n     */\n    std::optional<std::string> suggest_name(const std::filesystem::path& media_path) const;\n\n    /**\n     * @brief Returns true when the file extension is recognized as audio/video media.\n     * @param path Candidate media path.\n     * @return True for supported audio/video extensions.\n     */\n    static bool is_supported_media(const std::filesystem::path& path);\n\n    /**\n     * @brief Composes `year_artist_album_title.ext` using normalized metadata fragments.\n     * @param original_path Original file path used for extension + fallback stem.\n     * @param metadata Metadata fields used for composition.\n     * @return Composed filename, or the original filename when composition data is unavailable.\n     */\n    static std::string compose_filename(const std::filesystem::path& original_path,\n                                        const MetadataFields& metadata);\n\nprivate:\n    /**\n     * @brief Extracts audio/video metadata fields from the given media file.\n     * @param media_path Full path to the media file.\n     * @return Metadata fields on success; `std::nullopt` when unavailable.\n     */\n    static std::optional<MetadataFields> extract_metadata(const std::filesystem::path& media_path);\n\n    /**\n     * @brief Normalizes a metadata token into lowercase underscore-separated text.\n     * @param value Raw metadata text.\n     * @return Normalized slug, or empty string when no valid characters remain.\n     */\n    static std::string slugify(const std::string& value);\n\n    /**\n     * @brief Extracts a year in `YYYY` form from an arbitrary date string.\n     * @param value Raw metadata date value.\n     * @return Four-digit year when available.\n     */\n    static std::optional<std::string> normalize_year(const std::string& value);\n};\n"
  },
  {
    "path": "app/include/MovableCategorizedFile.hpp",
    "content": "#ifndef MOVABLECATEGORIZEDFILE_HPP\n#define MOVABLECATEGORIZEDFILE_HPP\n\n#include <string>\n#include <filesystem>\n\nclass MovableCategorizedFile {\npublic:\n    struct PreviewPaths {\n        std::string source;\n        std::string destination;\n    };\n\n    MovableCategorizedFile();\n    MovableCategorizedFile(const std::string& dir_path,\n                           const std::string& cat,\n                           const std::string& subcat,\n                           const std::string& file_name,\n                           const std::string& destination_name = std::string());\n    MovableCategorizedFile(const std::string& source_dir,\n                           const std::string& destination_root,\n                           const std::string& cat,\n                           const std::string& subcat,\n                           const std::string& file_name,\n                           const std::string& destination_name);\n    ~MovableCategorizedFile();\n    void create_cat_dirs(bool use_subcategory);\n    bool move_file(bool use_subcategory);\n    PreviewPaths preview_move_paths(bool use_subcategory) const;\n\n    std::string get_subcategory_path() const;\n    std::string get_category_path() const;\n    std::string get_destination_path() const;\n    std::string get_file_name() const;\n    std::string get_dir_path() const;\n    std::string get_category() const;\n    std::string get_subcategory() const;\n    void set_category(std::string& category);\n    void set_subcategory(std::string& subcategory);\n\nprivate:\n    struct MovePaths {\n        std::filesystem::path source;\n        std::filesystem::path destination;\n    };\n\n    MovePaths build_move_paths(bool use_subcategory) const;\n    bool source_is_available(const std::filesystem::path& source_path) const;\n    bool destination_is_available(const std::filesystem::path& destination_path) const;\n    bool perform_move(const std::filesystem::path& source_path,\n                      const std::filesystem::path& destination_path) const;\n\n    std::string file_name;\n    std::string destination_file_name;\n    std::string source_dir;\n    std::string dir_path;\n    std::string category;\n    std::string subcategory;\n    std::filesystem::path category_path;\n    std::filesystem::path subcategory_path;\n    std::filesystem::path destination_path;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/ResultsCoordinator.hpp",
    "content": "#ifndef RESULTS_COORDINATOR_HPP\n#define RESULTS_COORDINATOR_HPP\n\n#include \"Types.hpp\"\n#include \"FileScanner.hpp\"\n\n#include <unordered_set>\n#include <vector>\n\n/**\n * @brief Coordinates scan results and determines which files should be categorized or sorted.\n *\n * The coordinator relies on a FileScanner to list directory contents and then\n * filters/merges those results against cached or newly categorized entries.\n */\nclass ResultsCoordinator {\npublic:\n    /**\n     * @brief Constructs a coordinator that uses the provided scanner.\n     * @param scanner FileScanner used to enumerate directory entries.\n     */\n    explicit ResultsCoordinator(FileScanner& scanner);\n\n    /**\n     * @brief Lists entries in a directory using the provided scan options.\n     * @param directory Directory path to scan.\n     * @param options File scan options (files, directories, hidden files).\n     * @return Vector of FileEntry objects for items found in the directory.\n     */\n    std::vector<FileEntry> list_directory(const std::string& directory,\n                                          FileScanOptions options) const;\n\n    /**\n     * @brief Returns directory entries that are not present in the cached set.\n     * @param directory_path Directory path to scan.\n     * @param options File scan options (files, directories, hidden files).\n     * @param cached_files Set of cached file names to exclude.\n     * @return Vector of FileEntry objects that are not in the cache.\n     */\n    std::vector<FileEntry> find_files_to_categorize(const std::string& directory_path,\n                                                    FileScanOptions options,\n                                                    const std::unordered_set<std::string>& cached_files,\n                                                    bool use_full_path_keys) const;\n\n    /**\n     * @brief Filters categorized results to those still present on disk.\n     * @param directory_path Base directory path (kept for symmetry with caller context).\n     * @param options File scan options (files, directories, hidden files).\n     * @param actual_files Current directory entries to validate against.\n     * @param categorized_files Categorized entries from cache or analysis.\n     * @return Vector of CategorizedFile entries that still exist in the directory.\n     */\n    std::vector<CategorizedFile> compute_files_to_sort(const std::string& directory_path,\n                                                       FileScanOptions options,\n                                                       const std::vector<FileEntry>& actual_files,\n                                                       const std::vector<CategorizedFile>& categorized_files,\n                                                       bool use_full_path_keys) const;\n\n    /**\n     * @brief Extracts file names from categorized entries into a set.\n     * @param categorized_files Categorized entries to process.\n     * @return Set of file names contained in the categorized list.\n     */\n    std::unordered_set<std::string> extract_file_names(const std::vector<CategorizedFile>& categorized_files,\n                                                       bool use_full_path_keys) const;\n\nprivate:\n    /**\n     * @brief Scanner used to read directory entries.\n     */\n    FileScanner& scanner;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/Settings.hpp",
    "content": "#ifndef SETTINGS_HPP\n#define SETTINGS_HPP\n\n#include <IniConfig.hpp>\n#include <Types.hpp>\n#include <Language.hpp>\n#include <CategoryLanguage.hpp>\n#include <string>\n#include <filesystem>\n#include <vector>\n#include <functional>\n\n/**\n * @brief Stores and persists application configuration for UI and runtime behavior.\n */\nclass Settings\n{\npublic:\n    /**\n     * @brief Constructs a settings object with platform-appropriate defaults.\n     */\n    Settings();\n\n    /**\n     * @brief Loads configuration values from the active config file.\n     * @return True when an existing config file was loaded successfully.\n     */\n    bool load();\n    /**\n     * @brief Persists current configuration values to the active config file.\n     * @return True when the config file was written successfully.\n     */\n    bool save();\n\n    /**\n     * @brief Returns the selected LLM choice.\n     * @return Current LLM choice enum.\n     */\n    LLMChoice get_llm_choice() const;\n    /**\n     * @brief Sets the selected LLM choice.\n     * @param choice LLM choice to store.\n     */\n    void set_llm_choice(LLMChoice choice);\n    /**\n     * @brief Returns the stored OpenAI API key.\n     * @return OpenAI API key string.\n     */\n    std::string get_openai_api_key() const;\n    /**\n     * @brief Stores the OpenAI API key.\n     * @param key OpenAI API key text.\n     */\n    void set_openai_api_key(const std::string& key);\n    /**\n     * @brief Returns the configured OpenAI model identifier.\n     * @return OpenAI model name.\n     */\n    std::string get_openai_model() const;\n    /**\n     * @brief Sets the OpenAI model identifier.\n     * @param model OpenAI model name to store.\n     */\n    void set_openai_model(const std::string& model);\n    /**\n     * @brief Returns the stored Gemini API key.\n     * @return Gemini API key string.\n     */\n    std::string get_gemini_api_key() const;\n    /**\n     * @brief Stores the Gemini API key.\n     * @param key Gemini API key text.\n     */\n    void set_gemini_api_key(const std::string& key);\n    /**\n     * @brief Returns the configured Gemini model identifier.\n     * @return Gemini model name.\n     */\n    std::string get_gemini_model() const;\n    /**\n     * @brief Sets the Gemini model identifier.\n     * @param model Gemini model name to store.\n     */\n    void set_gemini_model(const std::string& model);\n    /**\n     * @brief Returns whether the LLM download UI section should remain expanded.\n     * @return True when the downloads section is expanded.\n     */\n    bool get_llm_downloads_expanded() const;\n    /**\n     * @brief Sets whether the LLM download UI section should remain expanded.\n     * @param value True to keep the downloads section expanded.\n     */\n    void set_llm_downloads_expanded(bool value);\n    /**\n     * @brief Returns the configured output language for categories.\n     * @return Selected category language.\n     */\n    CategoryLanguage get_category_language() const;\n    /**\n     * @brief Sets the output language for categories.\n     * @param language Category language to store.\n     */\n    void set_category_language(CategoryLanguage language);\n    /**\n     * @brief Returns the active custom local LLM identifier.\n     * @return Custom LLM id, or empty when none is selected.\n     */\n    std::string get_active_custom_llm_id() const;\n    /**\n     * @brief Sets the active custom local LLM identifier.\n     * @param id Custom LLM id to store.\n     */\n    void set_active_custom_llm_id(const std::string& id);\n    /**\n     * @brief Returns the configured custom local LLM entries.\n     * @return Immutable list of configured custom LLMs.\n     */\n    const std::vector<CustomLLM>& get_custom_llms() const;\n    /**\n     * @brief Adds or updates a custom local LLM entry.\n     * @param llm Custom LLM definition to upsert.\n     * @return Identifier of the saved custom LLM entry.\n     */\n    std::string upsert_custom_llm(const CustomLLM& llm);\n    /**\n     * @brief Removes a custom local LLM entry by id.\n     * @param id Custom LLM identifier to remove.\n     */\n    void remove_custom_llm(const std::string& id);\n    /**\n     * @brief Finds a custom local LLM entry by id.\n     * @param id Custom LLM identifier to resolve.\n     * @return Matching custom LLM entry, or a default-initialized value when not found.\n     */\n    CustomLLM find_custom_llm(const std::string& id) const;\n    /**\n     * @brief Return the active custom API endpoint id.\n     * @return Custom API endpoint id, or empty when none is selected.\n     */\n    std::string get_active_custom_api_id() const;\n    /**\n     * @brief Set the active custom API endpoint id.\n     * @param id Custom API endpoint id to store.\n     */\n    void set_active_custom_api_id(const std::string& id);\n    /**\n     * @brief Return the configured custom API endpoints.\n     * @return Immutable list of configured custom API endpoints.\n     */\n    const std::vector<CustomApiEndpoint>& get_custom_api_endpoints() const;\n    /**\n     * @brief Add or update a custom API endpoint entry.\n     * @param endpoint Custom endpoint definition to upsert.\n     * @return Identifier of the saved custom endpoint entry.\n     */\n    std::string upsert_custom_api_endpoint(const CustomApiEndpoint& endpoint);\n    /**\n     * @brief Remove a custom API endpoint by id.\n     * @param id Custom API endpoint identifier to remove.\n     */\n    void remove_custom_api_endpoint(const std::string& id);\n    /**\n     * @brief Find a custom API endpoint by id.\n     * @param id Custom API endpoint identifier to resolve.\n     * @return Matching custom API endpoint, or a default-initialized value when not found.\n     */\n    CustomApiEndpoint find_custom_api_endpoint(const std::string& id) const;\n    /**\n     * @brief Returns whether an LLM choice has been configured.\n     * @return True when the stored LLM choice is not unset.\n     */\n    bool is_llm_chosen() const;\n\n    /**\n     * @brief Returns whether subcategories are enabled.\n     * @return True when subcategories should be used.\n     */\n    bool get_use_subcategories() const;\n    /**\n     * @brief Enables or disables subcategories.\n     * @param value True to enable subcategories.\n     */\n    void set_use_subcategories(bool value);\n\n    /**\n     * @brief Returns whether consistency hints are enabled.\n     * @return True when consistency hints should be used.\n     */\n    bool get_use_consistency_hints() const;\n    /**\n     * @brief Enables or disables consistency hints.\n     * @param value True to enable consistency hints.\n     */\n    void set_use_consistency_hints(bool value);\n\n    /**\n     * @brief Returns whether files should be categorized.\n     * @return True when file categorization is enabled.\n     */\n    bool get_categorize_files() const;\n    /**\n     * @brief Enables or disables file categorization.\n     * @param value True to categorize files.\n     */\n    void set_categorize_files(bool value);\n\n    /**\n     * @brief Returns whether directories should be categorized.\n     * @return True when directory categorization is enabled.\n     */\n    bool get_categorize_directories() const;\n    /**\n     * @brief Enables or disables directory categorization.\n     * @param value True to categorize directories.\n     */\n    void set_categorize_directories(bool value);\n\n    /**\n     * @brief Returns whether subdirectories should be scanned.\n     * @return True when subdirectory scanning is enabled.\n     */\n    bool get_include_subdirectories() const;\n    /**\n     * @brief Enables or disables scanning of subdirectories.\n     * @param value True to scan subdirectories.\n     */\n    void set_include_subdirectories(bool value);\n\n    /**\n     * @brief Returns whether image content analysis is enabled.\n     * @return True when image analysis is enabled.\n     */\n    bool get_analyze_images_by_content() const;\n    /**\n     * @brief Enables or disables image content analysis.\n     * @param value True to enable image analysis.\n     */\n    void set_analyze_images_by_content(bool value);\n    /**\n     * @brief Returns whether image rename suggestions are enabled.\n     * @return True when image rename suggestions are enabled.\n     */\n    bool get_offer_rename_images() const;\n    /**\n     * @brief Enables or disables image rename suggestions.\n     * @param value True to enable image rename suggestions.\n     */\n    void set_offer_rename_images(bool value);\n    /**\n     * @brief Returns whether image filename suggestions should include EXIF date/place prefixes.\n     * @return True when EXIF date/place prefixes are enabled for image rename suggestions.\n     */\n    bool get_add_image_date_place_to_filename() const;\n    /**\n     * @brief Enables or disables adding EXIF date/place prefixes to image rename suggestions.\n     * @param value True to enable EXIF date/place prefixes.\n     */\n    void set_add_image_date_place_to_filename(bool value);\n    /**\n     * @brief Returns whether audio/video filename suggestions should include media metadata.\n     * @return True when audio/video metadata-based filename suggestions are enabled.\n     */\n    bool get_add_audio_video_metadata_to_filename() const;\n    /**\n     * @brief Enables or disables audio/video metadata-based filename suggestions.\n     * @param value True to enable metadata-based filename suggestions for audio/video files.\n     */\n    void set_add_audio_video_metadata_to_filename(bool value);\n    /**\n     * @brief Returns whether image creation dates should be appended to category names.\n     * @return True when image creation dates should be appended to categories.\n     */\n    bool get_add_image_date_to_category() const;\n    /**\n     * @brief Enables or disables appending image creation dates to category names.\n     * @param value True to append image creation dates to categories.\n     */\n    void set_add_image_date_to_category(bool value);\n    /**\n     * @brief Returns whether the image options group is expanded.\n     * @return True when the image options group should be expanded.\n     */\n    bool get_image_options_expanded() const;\n    /**\n     * @brief Sets whether the image options group is expanded.\n     * @param value True to keep the image options group expanded.\n     */\n    void set_image_options_expanded(bool value);\n    /**\n     * @brief Returns whether image files are treated as rename-only.\n     * @return True when image files are in rename-only mode.\n     */\n    bool get_rename_images_only() const;\n    /**\n     * @brief Enables or disables rename-only mode for images.\n     * @param value True to enable rename-only mode for images.\n     */\n    void set_rename_images_only(bool value);\n    /**\n     * @brief Returns whether only image files are processed.\n     * @return True when only image files are processed.\n     */\n    bool get_process_images_only() const;\n    /**\n     * @brief Enables or disables image-only processing.\n     * @param value True to enable image-only processing.\n     */\n    void set_process_images_only(bool value);\n    /**\n     * @brief Returns whether document content analysis is enabled.\n     * @return True when document analysis is enabled.\n     */\n    bool get_analyze_documents_by_content() const;\n    /**\n     * @brief Enables or disables document content analysis.\n     * @param value True to enable document analysis.\n     */\n    void set_analyze_documents_by_content(bool value);\n    /**\n     * @brief Returns whether document rename suggestions are enabled.\n     * @return True when document rename suggestions are enabled.\n     */\n    bool get_offer_rename_documents() const;\n    /**\n     * @brief Enables or disables document rename suggestions.\n     * @param value True to enable document rename suggestions.\n     */\n    void set_offer_rename_documents(bool value);\n    /**\n     * @brief Returns whether the document options group is expanded.\n     * @return True when the document options group should be expanded.\n     */\n    bool get_document_options_expanded() const;\n    /**\n     * @brief Sets whether the document options group is expanded.\n     * @param value True to keep the document options group expanded.\n     */\n    void set_document_options_expanded(bool value);\n    /**\n     * @brief Returns whether document files are treated as rename-only.\n     * @return True when document files are in rename-only mode.\n     */\n    bool get_rename_documents_only() const;\n    /**\n     * @brief Enables or disables rename-only mode for documents.\n     * @param value True to enable rename-only mode for documents.\n     */\n    void set_rename_documents_only(bool value);\n    /**\n     * @brief Returns whether only document files are processed.\n     * @return True when only document files are processed.\n     */\n    bool get_process_documents_only() const;\n    /**\n     * @brief Enables or disables document-only processing.\n     * @param value True to enable document-only processing.\n     */\n    void set_process_documents_only(bool value);\n    /**\n     * @brief Returns whether to append a document creation date to category names.\n     * @return True when document creation dates should be appended to categories.\n     */\n    bool get_add_document_date_to_category() const;\n    /**\n     * @brief Enables or disables appending document creation dates to category names.\n     * @param value True to append document creation dates to categories.\n     */\n    void set_add_document_date_to_category(bool value);\n\n    /**\n     * @brief Returns the current target sort folder path.\n     * @return Sort folder path as UTF-8 text.\n     */\n    std::string get_sort_folder() const;\n    /**\n     * @brief Sets the target sort folder path.\n     * @param path Sort folder path to store.\n     */\n    void set_sort_folder(const std::string &path);\n\n    /**\n     * @brief Returns whether the consistency-pass feature is enabled.\n     * @return True when the consistency pass should be available.\n     */\n    bool get_consistency_pass_enabled() const;\n    /**\n     * @brief Enables or disables the consistency-pass feature.\n     * @param value True to enable the consistency pass.\n     */\n    void set_consistency_pass_enabled(bool value);\n\n    /**\n     * @brief Returns whether category whitelists are enabled.\n     * @return True when whitelist filtering is active.\n     */\n    bool get_use_whitelist() const;\n    /**\n     * @brief Enables or disables category whitelist filtering.\n     * @param value True to enable whitelist filtering.\n     */\n    void set_use_whitelist(bool value);\n    /**\n     * @brief Returns the active category whitelist name.\n     * @return Active whitelist name.\n     */\n    std::string get_active_whitelist() const;\n    /**\n     * @brief Sets the active category whitelist name.\n     * @param name Whitelist name to store.\n     */\n    void set_active_whitelist(const std::string& name);\n\n    /**\n     * @brief Returns whether prompt logging is enabled in development mode.\n     * @return True when prompt/response logging is enabled.\n     */\n    bool get_development_prompt_logging() const;\n    /**\n     * @brief Enables or disables prompt logging in development mode.\n     * @param value True to enable prompt logging.\n     */\n    void set_development_prompt_logging(bool value);\n\n    /**\n     * @brief Resolves the full path to the active `config.ini` file.\n     * @return Platform-appropriate config file path.\n     */\n    std::string define_config_path();\n    /**\n     * @brief Returns the directory containing the active config file.\n     * @return Config directory path as UTF-8 text.\n     */\n    std::string get_config_dir();\n\n    /**\n     * @brief Stores the application version that should be skipped for update prompts.\n     * @param version Version string to suppress.\n     */\n    void set_skipped_version(const std::string &version);\n    /**\n     * @brief Returns the application version currently skipped for update prompts.\n     * @return Skipped version string, or empty when none is set.\n     */\n    std::string get_skipped_version();\n    /**\n     * @brief Sets whether the file explorer panel should be shown.\n     * @param value True to keep the file explorer visible.\n     */\n    void set_show_file_explorer(bool value);\n    /**\n     * @brief Returns whether the file explorer panel should be shown.\n     * @return True when the file explorer is visible by default.\n     */\n    bool get_show_file_explorer() const;\n    /**\n     * @brief Returns whether the suitability benchmark has been completed.\n     * @return True when the benchmark has run at least once.\n     */\n    bool get_suitability_benchmark_completed() const;\n    /**\n     * @brief Returns whether the suitability benchmark dialog is suppressed.\n     * @return True when the dialog should not auto-show on startup.\n     */\n    bool get_suitability_benchmark_suppressed() const;\n    /**\n     * @brief Marks the suitability benchmark as completed.\n     * @param value True when the benchmark has run.\n     */\n    void set_suitability_benchmark_completed(bool value);\n    /**\n     * @brief Sets whether the suitability benchmark dialog is suppressed.\n     * @param value True to suppress auto-showing the dialog.\n     */\n    void set_suitability_benchmark_suppressed(bool value);\n    /**\n     * @brief Returns the most recent benchmark report text.\n     * @return Report text (may be empty).\n     */\n    std::string get_benchmark_last_report() const;\n    /**\n     * @brief Sets the most recent benchmark report text.\n     * @param value Report text to store.\n     */\n    void set_benchmark_last_report(const std::string& value);\n    /**\n     * @brief Returns the timestamp string for the last benchmark run.\n     * @return Timestamp string (may be empty).\n     */\n    std::string get_benchmark_last_run() const;\n    /**\n     * @brief Sets the timestamp string for the last benchmark run.\n     * @param value Timestamp to store.\n     */\n    void set_benchmark_last_run(const std::string& value);\n    /**\n     * @brief Returns the selected UI language.\n     * @return Current interface language.\n     */\n    Language get_language() const;\n    /**\n     * @brief Sets the selected UI language.\n     * @param value Interface language to store.\n     */\n    void set_language(Language value);\n    /**\n     * @brief Returns the cumulative number of categorized files recorded so far.\n     * @return Total categorized file count.\n     */\n    int get_total_categorized_files() const;\n    /**\n     * @brief Adds to the cumulative categorized-file counter.\n     * @param count Number of files to add; non-positive values are ignored.\n     */\n    void add_categorized_files(int count);\n    /**\n     * @brief Returns the next file-count threshold for the support prompt.\n     * @return Next support prompt threshold.\n     */\n    int get_next_support_prompt_threshold() const;\n    /**\n     * @brief Sets the next file-count threshold for the support prompt.\n     * @param threshold Threshold value to store (clamped to the minimum supported value).\n     */\n    void set_next_support_prompt_threshold(int threshold);\n    /**\n     * @brief Returns the configured allowed category whitelist.\n     * @return Copy of the allowed category list.\n     */\n    std::vector<std::string> get_allowed_categories() const;\n    /**\n     * @brief Replaces the configured allowed category whitelist.\n     * @param values Allowed category names to store.\n     */\n    void set_allowed_categories(std::vector<std::string> values);\n    /**\n     * @brief Returns the configured allowed subcategory whitelist.\n     * @return Copy of the allowed subcategory list.\n     */\n    std::vector<std::string> get_allowed_subcategories() const;\n    /**\n     * @brief Replaces the configured allowed subcategory whitelist.\n     * @param values Allowed subcategory names to store.\n     */\n    void set_allowed_subcategories(std::vector<std::string> values);\n\nprivate:\n    LLMChoice parse_llm_choice() const;\n    void load_basic_settings(const std::function<bool(const char*, bool)>& load_bool,\n                             const std::function<int(const char*, int, int)>& load_int);\n    void load_whitelist_settings(const std::function<bool(const char*, bool)>& load_bool);\n    void load_custom_llm_settings();\n    /**\n     * @brief Load custom API endpoint entries from config.\n     */\n    void load_custom_api_settings();\n    void log_loaded_settings() const;\n\n    void save_core_settings();\n    void save_whitelist_settings();\n    void save_custom_llms();\n    /**\n     * @brief Save custom API endpoint entries to config.\n     */\n    void save_custom_api_endpoints();\n\n    std::string config_path;\n    std::filesystem::path config_dir;\n    IniConfig config;\n\n    LLMChoice llm_choice = LLMChoice::Unset;\n    std::string openai_api_key;\n    std::string openai_model{ \"gpt-4o-mini\" };\n    std::string gemini_api_key;\n    std::string gemini_model{ \"gemini-2.5-flash-lite\" };\n    bool llm_downloads_expanded{true};\n    bool use_subcategories;\n    bool categorize_files;\n    bool categorize_directories;\n    bool include_subdirectories{false};\n    bool analyze_images_by_content{false};\n    bool offer_rename_images{false};\n    bool add_image_date_place_to_filename{false};\n    bool add_audio_video_metadata_to_filename{true};\n    bool add_image_date_to_category{false};\n    bool image_options_expanded{false};\n    bool rename_images_only{false};\n    bool process_images_only{false};\n    bool analyze_documents_by_content{false};\n    bool offer_rename_documents{false};\n    bool document_options_expanded{false};\n    bool rename_documents_only{false};\n    bool process_documents_only{false};\n    bool add_document_date_to_category{false};\n    bool use_consistency_hints{false};\n    bool use_whitelist{false};\n    std::string default_sort_folder;\n    std::string sort_folder;\n    std::string skipped_version;\n    bool show_file_explorer{true};\n    bool suitability_benchmark_completed{false};\n    bool suitability_benchmark_suppressed{false};\n    std::string benchmark_last_report;\n    std::string benchmark_last_run;\n    Language language{Language::English};\n    CategoryLanguage category_language{CategoryLanguage::English};\n    bool consistency_pass_enabled{false};\n    bool development_prompt_logging{false};\n    int categorized_file_count{0};\n    int next_support_prompt_threshold{50};\n    std::vector<std::string> allowed_categories;\n    std::vector<std::string> allowed_subcategories;\n    std::string active_whitelist;\n    std::vector<CustomLLM> custom_llms;\n    std::string active_custom_llm_id;\n    std::vector<CustomApiEndpoint> custom_api_endpoints;\n    std::string active_custom_api_id;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/SuitabilityBenchmarkDialog.hpp",
    "content": "#ifndef SUITABILITY_BENCHMARK_DIALOG_HPP\n#define SUITABILITY_BENCHMARK_DIALOG_HPP\n\n#include <QCoreApplication>\n#include <QDialog>\n#include <QStringList>\n\n#include <atomic>\n#include <memory>\n#include <thread>\n\nclass QLabel;\nclass QTextEdit;\nclass QProgressBar;\nclass QPushButton;\nclass QCheckBox;\nclass Settings;\nclass QCloseEvent;\nclass QEvent;\n\n/**\n * @brief Dialog that runs a suitability benchmark for categorization and analysis features.\n */\nclass SuitabilityBenchmarkDialog : public QDialog\n{\n    Q_DECLARE_TR_FUNCTIONS(SuitabilityBenchmarkDialog)\npublic:\n    /**\n     * @brief Create a suitability benchmark dialog.\n     * @param settings Settings store used for persistence.\n     * @param parent Parent widget.\n     */\n    SuitabilityBenchmarkDialog(Settings& settings,\n                               QWidget* parent = nullptr);\n    /**\n     * @brief Destructor that joins any running benchmark thread.\n     */\n    ~SuitabilityBenchmarkDialog() override;\n\nprotected:\n    /**\n     * @brief Handle language changes for translated UI strings.\n     * @param event Qt event payload.\n     */\n    void changeEvent(QEvent* event) override;\n    /**\n     * @brief Prevent closing while the benchmark is running.\n     * @param event Qt close event.\n     */\n    void closeEvent(QCloseEvent* event) override;\n\nprivate:\n    /**\n     * @brief Build and connect the dialog UI elements.\n     */\n    void setup_ui();\n    /**\n     * @brief Update translated strings for the dialog.\n     */\n    void retranslate_ui();\n    /**\n     * @brief Start the benchmark worker thread and clear prior output.\n     */\n    void start_benchmark();\n    /**\n     * @brief Request the benchmark to stop after the current step finishes.\n     */\n    void request_stop();\n    /**\n     * @brief Run benchmark steps off the UI thread.\n     */\n    void run_benchmark_worker();\n    /**\n     * @brief Append a line to the output view.\n     * @param text Line to display.\n     * @param is_html True when the text already contains HTML markup.\n     */\n    void append_line(const QString& text, bool is_html);\n    /**\n     * @brief Toggle UI state for a running benchmark.\n     * @param running True when the benchmark is running.\n     */\n    void set_running_state(bool running);\n    /**\n     * @brief Finish the benchmark and persist results to settings.\n     */\n    void finish_benchmark();\n    /**\n     * @brief Load the most recent benchmark results from settings.\n     */\n    void load_previous_results();\n    /**\n     * @brief Render saved benchmark results into the output view.\n     */\n    void render_previous_results();\n\n    Settings& settings_;\n    QLabel* intro_label_{nullptr};\n    QTextEdit* output_view_{nullptr};\n    QProgressBar* progress_bar_{nullptr};\n    QCheckBox* suppress_checkbox_{nullptr};\n    QPushButton* run_button_{nullptr};\n    QPushButton* stop_button_{nullptr};\n    QPushButton* close_button_{nullptr};\n    std::atomic<bool> running_{false};\n    std::atomic<bool> stop_requested_{false};\n    std::thread worker_;\n    bool recording_{false};\n    bool showing_previous_results_{false};\n    QString last_run_stamp_;\n    QString last_report_;\n    QStringList current_report_;\n};\n\n#endif // SUITABILITY_BENCHMARK_DIALOG_HPP\n"
  },
  {
    "path": "app/include/SupportCodeManager.hpp",
    "content": "/**\n * @file SupportCodeManager.hpp\n * @brief Offline donation-code validation and prompt suppression helpers.\n */\n#pragma once\n\n#include <cstdint>\n#include <filesystem>\n#include <optional>\n#include <string>\n\n/**\n * @brief Handles offline donation-code validation and binary prompt suppression state.\n */\nclass SupportCodeManager {\npublic:\n    /**\n     * @brief Constructs a support-code manager rooted at the app config directory.\n     * @param config_dir Base configuration directory used for the binary suppression blob.\n     */\n    explicit SupportCodeManager(std::filesystem::path config_dir);\n\n    /**\n     * @brief Returns whether a donation code passes offline validation.\n     * @param code User-provided donation code.\n     * @return True when the code is valid.\n     */\n    static bool is_valid_code(const std::string& code);\n\n    /**\n     * @brief Validates and stores a donation code so the support prompt stays hidden.\n     * @param code User-provided donation code.\n     * @return True when the code is valid and the suppression blob was written.\n     */\n    bool redeem_code(const std::string& code) const;\n\n    /**\n     * @brief Returns whether the binary suppression blob is present and valid.\n     * @return True when the support prompt should remain hidden.\n     */\n    bool is_prompt_permanently_disabled() const;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    /**\n     * @brief Writes a valid suppression blob without requiring a real donation code.\n     * @return True when the test suppression blob was written successfully.\n     */\n    bool force_disable_prompt_for_testing() const;\n#endif\n\nprivate:\n    /**\n     * @brief Verifies a donation code and returns the signed payload on success.\n     * @param code User-provided donation code.\n     * @return Signed payload bytes when valid, otherwise `std::nullopt`.\n     */\n    static std::optional<std::string> decode_payload(const std::string& code);\n\n    /**\n     * @brief Resolves the binary suppression blob path.\n     * @return Filesystem path used for the stored suppression state.\n     */\n    std::filesystem::path storage_path() const;\n\n    /**\n     * @brief Derives the current machine binding key.\n     * @return Opaque machine-bound key material.\n     */\n    std::string machine_binding_key() const;\n\n    /**\n     * @brief Writes an opaque suppression blob for the provided signed payload.\n     * @param payload Signed payload from a valid donation code.\n     * @return True when the blob was written successfully.\n     */\n    bool write_state(const std::string& payload) const;\n\n    std::filesystem::path config_dir_;\n};\n"
  },
  {
    "path": "app/include/TestHooks.hpp",
    "content": "#pragma once\n\n#include <functional>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <curl/curl.h>\n\n#include \"Utils.hpp\"\n\nnamespace TestHooks {\n\nstruct BackendMemoryInfo {\n    Utils::CudaMemoryInfo memory;\n    bool is_integrated = false;\n    std::string name;\n};\n\nusing BackendMemoryProbe = std::function<std::optional<BackendMemoryInfo>(std::string_view backend_name)>;\nvoid set_backend_memory_probe(BackendMemoryProbe probe);\nvoid reset_backend_memory_probe();\n\nusing BackendAvailabilityProbe = std::function<bool(std::string_view backend_name)>;\nvoid set_backend_availability_probe(BackendAvailabilityProbe probe);\nvoid reset_backend_availability_probe();\n\nusing CudaAvailabilityProbe = std::function<bool()>;\nvoid set_cuda_availability_probe(CudaAvailabilityProbe probe);\nvoid reset_cuda_availability_probe();\n\nusing CudaMemoryProbe = std::function<std::optional<Utils::CudaMemoryInfo>()>;\nvoid set_cuda_memory_probe(CudaMemoryProbe probe);\nvoid reset_cuda_memory_probe();\n\nstruct CategorizationMoveInfo {\n    bool show_subcategory_folders;\n    std::string category;\n    std::string subcategory;\n    std::string file_name;\n};\n\nusing CategorizationMoveProbe = std::function<void(const CategorizationMoveInfo&)>;\nvoid set_categorization_move_probe(CategorizationMoveProbe probe);\nvoid reset_categorization_move_probe();\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nusing LLMDownloadProbe = std::function<CURLcode(long resume_offset, const std::string& destination_path)>;\nvoid set_llm_download_probe(LLMDownloadProbe probe);\nvoid reset_llm_download_probe();\n#endif\n\n} // namespace TestHooks\n"
  },
  {
    "path": "app/include/TranslationManager.hpp",
    "content": "#ifndef TRANSLATIONMANAGER_HPP\n#define TRANSLATIONMANAGER_HPP\n\n#include \"Language.hpp\"\n\n#include <QObject>\n#include <QTranslator>\n#include <memory>\n#include <vector>\n\nclass QApplication;\n\nclass TranslationManager : public QObject\n{\npublic:\n    struct LanguageInfo {\n        Language id;\n        QString code;\n        QString name;\n        QString resource_path;\n    };\n\n    static TranslationManager& instance();\n\n    void initialize(QApplication* app);\n    void initialize_for_app(QApplication* app, Language language);\n    void set_language(Language language);\n    Language current_language() const;\n    const std::vector<LanguageInfo>& available_languages() const;\n\nprivate:\n    TranslationManager();\n    bool load_translation(const LanguageInfo& info);\n\n    QApplication* app_{nullptr};\n    std::unique_ptr<QTranslator> translator_;\n    Language current_language_{Language::English};\n    std::vector<LanguageInfo> languages_;\n};\n\n#endif // TRANSLATIONMANAGER_HPP\n"
  },
  {
    "path": "app/include/Types.hpp",
    "content": "#ifndef TYPES_HPP\n#define TYPES_HPP\n\n#include <string>\n\nenum class LLMChoice {\n    Unset,\n    Remote_OpenAI,\n    Remote_Gemini,\n    Remote_Custom, ///< Custom OpenAI-compatible endpoint.\n    Local_3b,\n    Local_3b_legacy,\n    Local_7b,\n    Custom\n};\n\ninline bool is_remote_choice(LLMChoice choice) {\n    return choice == LLMChoice::Remote_OpenAI\n        || choice == LLMChoice::Remote_Gemini\n        || choice == LLMChoice::Remote_Custom;\n}\n\nenum class FileType {File, Directory};\n\nstruct CategorizedFile {\n    std::string file_path;\n    std::string file_name;\n    FileType type;\n    std::string category;\n    std::string subcategory;\n    int taxonomy_id{0};\n    bool from_cache{false};\n    bool used_consistency_hints{false};\n    std::string suggested_name;\n    bool rename_only{false};\n    bool rename_applied{false};\n    std::string canonical_category;\n    std::string canonical_subcategory;\n};\n\ninline std::string to_string(FileType type) {\n    switch (type) {\n        case FileType::File: return \"File\";\n        case FileType::Directory: return \"Directory\";\n        default: return \"Unknown\";\n    }\n}\n\nstruct FileEntry {\n    std::string full_path;\n    std::string file_name;\n    FileType type;\n};\n\nstruct CustomLLM {\n    std::string id;\n    std::string name;\n    std::string description;\n    std::string path;\n};\n\ninline bool is_valid_custom_llm(const CustomLLM& entry) {\n    return !entry.id.empty() && !entry.name.empty() && !entry.path.empty();\n}\n\n/**\n * @brief Defines a custom OpenAI-compatible API endpoint.\n */\nstruct CustomApiEndpoint {\n    std::string id;\n    std::string name;\n    std::string description;\n    std::string base_url;\n    std::string api_key;\n    std::string model;\n};\n\n/**\n * @brief Returns true when the custom endpoint has the required fields.\n */\ninline bool is_valid_custom_api_endpoint(const CustomApiEndpoint& entry) {\n    return !entry.id.empty()\n        && !entry.name.empty()\n        && !entry.base_url.empty()\n        && !entry.model.empty();\n}\n\nenum class FileScanOptions {\n    None        = 0,\n    Files       = 1 << 0,   // 0001\n    Directories = 1 << 1,   // 0010\n    HiddenFiles = 1 << 2,   // 0100\n    Recursive   = 1 << 3    // 1000\n};\n\ninline bool has_flag(FileScanOptions value, FileScanOptions flag) {\n    return (static_cast<int>(value) & static_cast<int>(flag)) != 0;\n}\n\ninline FileScanOptions operator|(FileScanOptions a, FileScanOptions b) {\n    return static_cast<FileScanOptions>(static_cast<int>(a) | static_cast<int>(b));\n}\n\ninline FileScanOptions operator&(FileScanOptions a, FileScanOptions b) {\n    return static_cast<FileScanOptions>(static_cast<int>(a) & static_cast<int>(b));\n}\n\ninline FileScanOptions operator~(FileScanOptions a) {\n    return static_cast<FileScanOptions>(~static_cast<int>(a));\n}\n\nstruct cudaDeviceProp {\n    size_t totalGlobalMem;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/UiTranslator.hpp",
    "content": "#ifndef UI_TRANSLATOR_HPP\n#define UI_TRANSLATOR_HPP\n\n#include <QPointer>\n#include <QString>\n\n#include <functional>\n\n#include <QCheckBox>\n#include <QRadioButton>\n\nclass QAction;\nclass QActionGroup;\n\nclass QDockWidget;\nclass QLabel;\nclass QMainWindow;\nclass QMenu;\nclass QPushButton;\nclass QComboBox;\nclass QStandardItemModel;\nclass QToolButton;\n\nclass Settings;\n\n#include \"Language.hpp\"\n#include \"CategoryLanguage.hpp\"\n\n/**\n * @brief Applies translated text to the main window UI and related controls.\n */\nclass UiTranslator\n{\npublic:\n    /**\n     * @brief References to the primary controls whose labels are translated together.\n     */\n    struct PrimaryControls {\n        QPointer<QLabel>& path_label;\n        QPointer<QPushButton>& browse_button;\n        QPointer<QPushButton>& analyze_button;\n        QPointer<QCheckBox>& use_subcategories_checkbox;\n        QPointer<QLabel>& categorization_style_heading;\n        QPointer<QRadioButton>& categorization_style_refined_radio;\n        QPointer<QRadioButton>& categorization_style_consistent_radio;\n        QPointer<QCheckBox>& use_whitelist_checkbox;\n        QPointer<QComboBox>& whitelist_selector;\n        QPointer<QCheckBox>& categorize_files_checkbox;\n        QPointer<QCheckBox>& categorize_directories_checkbox;\n        QPointer<QCheckBox>& include_subdirectories_checkbox;\n        QPointer<QCheckBox>& analyze_images_checkbox;\n        QPointer<QCheckBox>& process_images_only_checkbox;\n        QPointer<QCheckBox>& add_image_date_to_category_checkbox;\n        QPointer<QCheckBox>& add_image_date_place_to_filename_checkbox;\n        QPointer<QCheckBox>& add_audio_video_metadata_to_filename_checkbox;\n        QPointer<QCheckBox>& offer_rename_images_checkbox;\n        QPointer<QCheckBox>& rename_images_only_checkbox;\n        QPointer<QToolButton>& image_options_toggle_button;\n        QPointer<QCheckBox>& analyze_documents_checkbox;\n        QPointer<QCheckBox>& process_documents_only_checkbox;\n        QPointer<QCheckBox>& offer_rename_documents_checkbox;\n        QPointer<QCheckBox>& rename_documents_only_checkbox;\n        QPointer<QCheckBox>& add_document_date_to_category_checkbox;\n        QPointer<QToolButton>& document_options_toggle_button;\n    };\n\n    /**\n     * @brief References to top-level menus whose titles are translated.\n     */\n    struct MenuControls {\n        QMenu*& file_menu;\n        QMenu*& edit_menu;\n        QMenu*& view_menu;\n        QMenu*& settings_menu;\n        QMenu*& development_menu;\n        QMenu*& development_settings_menu;\n        QMenu*& language_menu;\n        QMenu*& category_language_menu;\n        QMenu*& help_menu;\n    };\n\n    /**\n     * @brief References to menu and command actions whose text is translated.\n     */\n    struct ActionControls {\n        QAction*& file_quit_action;\n        QAction*& run_benchmark_action;\n        QAction*& copy_action;\n        QAction*& cut_action;\n        QAction*& undo_last_run_action;\n        QAction*& paste_action;\n        QAction*& delete_action;\n        QAction*& toggle_explorer_action;\n        QAction*& toggle_llm_action;\n        QAction*& manage_whitelists_action;\n        QAction*& development_prompt_logging_action;\n        QAction*& consistency_pass_action;\n        QAction*& english_action;\n        QAction*& dutch_action;\n        QAction*& french_action;\n        QAction*& german_action;\n        QAction*& italian_action;\n        QAction*& spanish_action;\n        QAction*& turkish_action;\n        QAction*& korean_action;\n        QAction*& category_language_english;\n        QAction*& category_language_french;\n        QAction*& category_language_german;\n        QAction*& category_language_italian;\n        QAction*& category_language_dutch;\n        QAction*& category_language_polish;\n        QAction*& category_language_portuguese;\n        QAction*& category_language_spanish;\n        QAction*& category_language_turkish;\n        QAction*& about_action;\n        QAction*& about_qt_action;\n        QAction*& about_agpl_action;\n        QAction*& support_project_action;\n    };\n\n    /**\n     * @brief References to language-selection actions and their action group.\n     */\n    struct LanguageControls {\n        QActionGroup*& language_group;\n        QAction*& english_action;\n        QAction*& dutch_action;\n        QAction*& french_action;\n        QAction*& german_action;\n        QAction*& italian_action;\n        QAction*& spanish_action;\n        QAction*& turkish_action;\n        QAction*& korean_action;\n    };\n\n    /**\n     * @brief References to category-language actions and their action group.\n     */\n    struct CategoryLanguageControls {\n        QActionGroup*& category_language_group;\n        QAction*& dutch;\n        QAction*& english;\n        QAction*& french;\n        QAction*& german;\n        QAction*& italian;\n        QAction*& polish;\n        QAction*& portuguese;\n        QAction*& spanish;\n        QAction*& turkish;\n    };\n\n    /**\n     * @brief Runtime state inputs used when translating status-dependent text.\n     */\n    struct State {\n        bool analysis_in_progress{false};\n        bool stop_analysis_requested{false};\n        bool status_is_ready{true};\n    };\n\n    /**\n     * @brief Full dependency bundle required to translate the MainApp UI.\n     */\n    struct Dependencies {\n        QMainWindow& window;\n        PrimaryControls primary;\n        QPointer<QStandardItemModel>& tree_model;\n        MenuControls menus;\n        ActionControls actions;\n        LanguageControls language;\n        CategoryLanguageControls category_language;\n        QPointer<QDockWidget>& file_explorer_dock;\n        Settings& settings;\n        std::function<QString(const char*)> translator;\n    };\n\n    /**\n     * @brief Constructs a translator wrapper over the provided UI dependencies.\n     * @param deps References to the UI controls and translation callback.\n     */\n    explicit UiTranslator(Dependencies deps);\n\n    /**\n     * @brief Retranslates all supported UI text in one pass.\n     * @param state Current UI state used for status-dependent labels.\n     */\n    void retranslate_all(const State& state) const;\n    /**\n     * @brief Updates the main window title.\n     */\n    void translate_window_title() const;\n    /**\n     * @brief Updates the labels of the primary controls on the main window.\n     * @param analysis_in_progress True when analysis is currently active.\n     */\n    void translate_primary_controls(bool analysis_in_progress) const;\n    /**\n     * @brief Updates translated labels inside the results tree view.\n     */\n    void translate_tree_view_labels() const;\n    /**\n     * @brief Updates menu titles and action labels.\n     */\n    void translate_menus_and_actions() const;\n    /**\n     * @brief Updates the status bar message for the given runtime state.\n     * @param state Current UI state used to choose the status message.\n     */\n    void translate_status_messages(const State& state) const;\n    /**\n     * @brief Synchronizes checkmarks for language and category-language actions.\n     */\n    void update_language_checks() const;\n\nprivate:\n    QString tr(const char* source) const;\n    void update_language_group_checks(Language configured) const;\n    void update_category_language_checks(CategoryLanguage configured) const;\n\n    Dependencies deps_;\n};\n\n#endif // UI_TRANSLATOR_HPP\n#include \"Language.hpp\"\n#include \"CategoryLanguage.hpp\"\n"
  },
  {
    "path": "app/include/UndoManager.hpp",
    "content": "#pragma once\n\n#include <QString>\n#include <QStringList>\n#include <memory>\n#include <optional>\n#include <string>\n#include <vector>\n#include <cstdint>\n#include <ctime>\n\n#include <spdlog/logger.h>\n\nclass UndoManager {\npublic:\n    struct Entry {\n        std::string source;\n        std::string destination;\n        std::uintmax_t size_bytes{0};\n        std::time_t mtime{0};\n    };\n\n    explicit UndoManager(std::string undo_dir);\n\n    bool save_plan(const std::string& run_base_dir,\n                   const std::vector<Entry>& entries,\n                   const std::shared_ptr<spdlog::logger>& logger) const;\n\n    std::optional<QString> latest_plan_path() const;\n\n    struct UndoResult {\n        int restored{0};\n        int skipped{0};\n        QStringList details;\n    };\n\n    UndoResult undo_plan(const QString& plan_path) const;\n\nprivate:\n    std::string undo_dir_;\n};\n"
  },
  {
    "path": "app/include/UpdateArchiveExtractor.hpp",
    "content": "#pragma once\n\n#include <filesystem>\n#include <string>\n\nclass UpdateArchiveExtractor\n{\npublic:\n    struct ExtractionResult\n    {\n        std::filesystem::path installer_path;\n        std::string message;\n\n        static ExtractionResult success(std::filesystem::path path)\n        {\n            return ExtractionResult{std::move(path), {}};\n        }\n\n        static ExtractionResult failure(std::string error)\n        {\n            return ExtractionResult{{}, std::move(error)};\n        }\n\n        bool ok() const\n        {\n            return !installer_path.empty();\n        }\n    };\n\n    static bool supports_archive(const std::filesystem::path& package_path);\n    static ExtractionResult extract_installer(const std::filesystem::path& archive_path,\n                                              const std::filesystem::path& destination_root);\n};\n"
  },
  {
    "path": "app/include/UpdateFeed.hpp",
    "content": "#pragma once\n\n#include <optional>\n#include <string>\n\nstruct UpdateInfo\n{\n    std::string current_version;\n    std::string min_version{\"0.0.0\"};\n    std::string download_url;\n    std::string release_notes_url;\n    std::string installer_url;\n    std::string installer_sha256;\n\n    bool has_download_target() const\n    {\n        return !download_url.empty() || !installer_url.empty();\n    }\n\n    bool has_direct_installer() const\n    {\n        return !installer_url.empty();\n    }\n};\n\nclass UpdateFeed\n{\npublic:\n    enum class Platform {\n        Windows,\n        MacOS,\n        Linux\n    };\n\n    static Platform current_platform();\n    static std::optional<UpdateInfo> parse_for_current_platform(const std::string& update_json);\n    static std::optional<UpdateInfo> parse_for_platform(const std::string& update_json, Platform platform);\n};\n"
  },
  {
    "path": "app/include/UpdateInstaller.hpp",
    "content": "#pragma once\n\n#include \"Settings.hpp\"\n#include \"UpdateFeed.hpp\"\n\n#include <filesystem>\n#include <functional>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\nstruct UpdatePreparationResult\n{\n    enum class Status {\n        Ready,\n        Canceled,\n        Failed\n    };\n\n    Status status{Status::Failed};\n    std::filesystem::path installer_path;\n    std::string message;\n\n    static UpdatePreparationResult ready(std::filesystem::path path)\n    {\n        return UpdatePreparationResult{Status::Ready, std::move(path), {}};\n    }\n\n    static UpdatePreparationResult canceled(std::string message = {})\n    {\n        return UpdatePreparationResult{Status::Canceled, {}, std::move(message)};\n    }\n\n    static UpdatePreparationResult failed(std::string message)\n    {\n        return UpdatePreparationResult{Status::Failed, {}, std::move(message)};\n    }\n};\n\nclass UpdateInstaller\n{\npublic:\n    struct LaunchRequest\n    {\n        std::string program;\n        std::vector<std::string> arguments;\n    };\n\n    class DownloadCanceledError : public std::runtime_error\n    {\n    public:\n        DownloadCanceledError();\n    };\n\n    using ProgressCallback = std::function<void(double, const std::string&)>;\n    using CancelCheck = std::function<bool()>;\n    using DownloadFunction = std::function<void(const std::string&,\n                                                const std::filesystem::path&,\n                                                ProgressCallback,\n                                                CancelCheck)>;\n    using LaunchFunction = std::function<bool(const std::filesystem::path&)>;\n\n    explicit UpdateInstaller(Settings& settings,\n                             DownloadFunction download_fn = {},\n                             LaunchFunction launch_fn = {});\n\n    bool supports_auto_install(const UpdateInfo& info) const;\n    UpdatePreparationResult prepare(const UpdateInfo& info,\n                                    ProgressCallback progress_cb = {},\n                                    CancelCheck cancel_check = {}) const;\n    bool launch(const std::filesystem::path& installer_path) const;\n\nprivate:\n    Settings& settings_;\n    DownloadFunction download_fn_;\n    LaunchFunction launch_fn_;\n\n    std::filesystem::path updates_dir() const;\n    std::filesystem::path package_path_for(const UpdateInfo& info) const;\n    std::filesystem::path extracted_installer_root_for(const std::filesystem::path& package_path) const;\n    std::string compute_sha256(const std::filesystem::path& path) const;\n    bool verify_file(const std::filesystem::path& path, const std::string& expected_sha256) const;\n    static LaunchRequest build_launch_request(const std::filesystem::path& installer_path);\n\n    static void default_download(const std::string& url,\n                                 const std::filesystem::path& destination_path,\n                                 ProgressCallback progress_cb,\n                                 CancelCheck cancel_check);\n    static bool default_launch(const std::filesystem::path& installer_path);\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class UpdateInstallerTestAccess;\n#endif\n};\n"
  },
  {
    "path": "app/include/UpdateInstallerTestAccess.hpp",
    "content": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"UpdateInstaller.hpp\"\n\nclass UpdateInstallerTestAccess {\npublic:\n    static UpdateInstaller::LaunchRequest build_launch_request(const std::filesystem::path& installer_path);\n};\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/Updater.hpp",
    "content": "#ifndef UPDATER_HPP\n#define UPDATER_HPP\n\n#include \"Settings.hpp\"\n#include \"UpdateFeed.hpp\"\n#include \"UpdateInstaller.hpp\"\n#include \"Version.hpp\"\n#include <functional>\n#include <future>\n#include <optional>\n#include <string>\n\nclass QWidget;\nclass QString;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nclass UpdaterTestAccess;\n#endif\n\nclass Updater\n{\npublic:\n    explicit Updater(Settings& settings);\n    ~Updater();\n    void begin();\n\nprivate:\n    Settings& settings;\n    UpdateInstaller installer;\n    std::optional<std::string> update_spec_file_url_;\n    std::function<void(const std::string&)> open_download_url_fn_;\n    std::function<void()> quit_fn_;\n    std::optional<UpdateInfo> update_info;\n    std::future<void> update_future;\n    void check_updates();\n    std::optional<UpdateInfo> resolve_live_test_update() const;\n    std::string fetch_update_metadata() const;\n    Version string_to_Version(const std::string &version_str);\n    void display_update_dialog(bool is_required=false);\n    void show_required_update_dialog(const UpdateInfo& info, QWidget* parent);\n    void show_optional_update_dialog(const UpdateInfo& info, QWidget* parent);\n    bool is_update_available();\n    bool is_update_required();\n    bool is_update_skipped();\n    bool trigger_update_action(const UpdateInfo& info, QWidget* parent, bool quit_after_open);\n    UpdatePreparationResult prepare_installer_update(const UpdateInfo& info, QWidget* parent);\n    bool handle_update_error(const UpdateInfo& info,\n                             const QString& message,\n                             QWidget* parent,\n                             bool quit_after_open);\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    friend class UpdaterTestAccess;\n#endif\n};\n\n#endif\n"
  },
  {
    "path": "app/include/UpdaterBuildConfig.hpp",
    "content": "#pragma once\n\nnamespace UpdaterBuildConfig {\n\nenum class Mode {\n    AutoInstall,\n    NotifyOnly,\n    Disabled,\n};\n\nconstexpr Mode current_mode()\n{\n#if defined(AI_FILE_SORTER_UPDATE_MODE_DISABLED)\n    return Mode::Disabled;\n#elif defined(AI_FILE_SORTER_UPDATE_MODE_NOTIFY_ONLY)\n    return Mode::NotifyOnly;\n#elif defined(AI_FILE_SORTER_UPDATE_MODE_AUTO_INSTALL)\n    return Mode::AutoInstall;\n#else\n    return Mode::AutoInstall;\n#endif\n}\n\nconstexpr bool update_checks_enabled()\n{\n    return current_mode() != Mode::Disabled;\n}\n\nconstexpr bool auto_install_enabled()\n{\n    return current_mode() == Mode::AutoInstall;\n}\n\n} // namespace UpdaterBuildConfig\n"
  },
  {
    "path": "app/include/UpdaterLaunchOptions.hpp",
    "content": "#pragma once\n\nnamespace UpdaterLaunchOptions {\n\ninline constexpr const char* kLiveTestFlag = \"--updater-live-test\";\ninline constexpr const char* kLiveTestUrlFlag = \"--updater-live-test-url=\";\ninline constexpr const char* kLiveTestSha256Flag = \"--updater-live-test-sha256=\";\ninline constexpr const char* kLiveTestVersionFlag = \"--updater-live-test-version=\";\ninline constexpr const char* kLiveTestMinVersionFlag = \"--updater-live-test-min-version=\";\n\ninline constexpr const char* kLiveTestModeEnv = \"AI_FILE_SORTER_UPDATER_TEST_MODE\";\ninline constexpr const char* kLiveTestUrlEnv = \"AI_FILE_SORTER_UPDATER_TEST_URL\";\ninline constexpr const char* kLiveTestSha256Env = \"AI_FILE_SORTER_UPDATER_TEST_SHA256\";\ninline constexpr const char* kLiveTestVersionEnv = \"AI_FILE_SORTER_UPDATER_TEST_VERSION\";\ninline constexpr const char* kLiveTestMinVersionEnv = \"AI_FILE_SORTER_UPDATER_TEST_MIN_VERSION\";\n\n} // namespace UpdaterLaunchOptions\n"
  },
  {
    "path": "app/include/UpdaterLiveTestConfig.hpp",
    "content": "#pragma once\n\n#include <filesystem>\n#include <optional>\n#include <string>\n\nstruct UpdaterLiveTestConfig\n{\n    bool enabled{false};\n    std::optional<std::string> installer_url;\n    std::optional<std::string> installer_sha256;\n    std::optional<std::string> current_version;\n    std::optional<std::string> min_version;\n};\n\nstd::optional<std::filesystem::path> find_updater_live_test_ini(const std::filesystem::path& executable_path);\nstd::optional<std::filesystem::path> load_missing_values_from_live_test_ini(\n    UpdaterLiveTestConfig& config,\n    const std::filesystem::path& executable_path);\n"
  },
  {
    "path": "app/include/UpdaterTestAccess.hpp",
    "content": "#pragma once\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n\n#include \"UpdateFeed.hpp\"\n\n#include <QString>\n#include <functional>\n\nclass QWidget;\nclass Updater;\n\nclass UpdaterTestAccess {\npublic:\n    static bool is_update_available(Updater& updater);\n    static std::optional<UpdateInfo> current_update_info(const Updater& updater);\n    static bool has_update_task(const Updater& updater);\n    static void wait_for_update_task(Updater& updater);\n    static void set_open_download_url_handler(Updater& updater,\n                                              std::function<void(const std::string&)> handler);\n    static void set_quit_handler(Updater& updater,\n                                 std::function<void()> handler);\n    static bool trigger_update_action(Updater& updater,\n                                      const UpdateInfo& info,\n                                      QWidget* parent,\n                                      bool quit_after_open);\n    static bool handle_update_error(Updater& updater,\n                                    const UpdateInfo& info,\n                                    const QString& message,\n                                    QWidget* parent,\n                                    bool quit_after_open);\n};\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/include/Utils.hpp",
    "content": "#ifndef UTILS_HPP\n#define UTILS_HPP\n\n#include <curl/system.h>\n#include <functional>\n#include <optional>\n#include <string>\n#include <vector>\n#include <cstddef>\n#include <filesystem>\n\n\nclass Utils {\npublic:\n    Utils();\n    ~Utils();\n    static bool is_network_available();\n    static std::string get_executable_path();\n    static bool is_valid_directory(const char *path);\n    static std::vector<unsigned char> hex_to_vector(const std::string &hex);\n    static const char* to_cstr(const std::u8string& u8str);\n    static void ensure_directory_exists(const std::string &dir);\n    static bool is_os_windows();\n    static bool is_os_macos();\n    static bool is_os_linux();\n    static std::string format_size(curl_off_t bytes);\n    static int determine_ngl_cuda();\n    struct CudaMemoryInfo {\n        size_t free_bytes{0};\n        size_t total_bytes{0};\n        size_t device_total_bytes{0};\n\n        bool valid() const {\n            return total_bytes > 0 || free_bytes > 0;\n        }\n    };\n    static std::optional<CudaMemoryInfo> query_cuda_memory();\n    static int compute_ngl_from_cuda_memory(const CudaMemoryInfo& info);\n    template <typename Func> void run_on_main_thread(Func &&func);\n    static std::string get_default_llm_destination();\n    static std::string get_file_name_from_url(std::string url);\n    static std::string make_default_path_to_file_from_download_url(std::string url);\n    static bool is_cuda_available();\n    static int get_installed_cuda_runtime_version();\n    static std::string get_cudart_dll_name();\n    static std::string abbreviate_user_path(const std::string& path);\n    static std::filesystem::path ensure_ca_bundle();\n    static std::string path_to_utf8(const std::filesystem::path& path);\n    static std::filesystem::path utf8_to_path(const std::string& utf8_path);\n    static std::string sanitize_path_label(const std::string& value);\n\nprivate:\n    static int get_ngl(int vram_mb);\n};\n\n#endif\n"
  },
  {
    "path": "app/include/Version.hpp",
    "content": "#ifndef VERSION_HPP\n#define VERSION_HPP\n\n#include <initializer_list>\n#include <string>\n#include <vector>\n\n\nclass Version {\n public:\n    explicit Version(std::initializer_list<int> version_digits);\n    explicit Version(const std::vector<int>& version_digits);\n    bool operator>=(const Version& other) const;\n    bool operator<=(const Version& other) const;\n    std::string to_string() const;\n    bool operator>(const Version &other) const;\n\n private:\n    std::vector<int> digits;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/WhitelistManagerDialog.hpp",
    "content": "#ifndef WHITELIST_MANAGER_DIALOG_HPP\n#define WHITELIST_MANAGER_DIALOG_HPP\n\n#include <QCoreApplication>\n#include <QDialog>\n#include <QPointer>\n#include <QString>\n#include <functional>\n#include \"WhitelistStore.hpp\"\n\nclass QListWidget;\nclass QTextEdit;\nclass QLineEdit;\nclass QPushButton;\nclass QLabel;\n\n/**\n * @brief Dialog for creating, editing, and deleting whitelist entries.\n */\nclass WhitelistManagerDialog : public QDialog {\n    Q_DECLARE_TR_FUNCTIONS(WhitelistManagerDialog)\npublic:\n    /**\n     * @brief Constructs the whitelist manager dialog.\n     * @param store Backing store for whitelist entries.\n     * @param parent Optional parent widget.\n     */\n    explicit WhitelistManagerDialog(WhitelistStore& store, QWidget* parent = nullptr);\n\n    /**\n     * @brief Registers a callback invoked when the whitelist collection changes.\n     * @param cb Callback to invoke after changes.\n     */\n    void set_on_lists_changed(std::function<void()> cb) { on_lists_changed_ = std::move(cb); }\n\nprivate:\n    /**\n     * @brief Handles the Add button action.\n     */\n    void on_add_clicked();\n    /**\n     * @brief Handles the Edit button action.\n     */\n    void on_edit_clicked();\n    /**\n     * @brief Handles the Remove button action.\n     */\n    void on_remove_clicked();\n    /**\n     * @brief Handles selection change events.\n     * @param row Selected row index.\n     */\n    void on_selection_changed(int row);\n\n    /**\n     * @brief Refreshes the list widget from the store.\n     */\n    void refresh_list();\n    /**\n     * @brief Opens the editor UI for a whitelist entry.\n     * @param name Current whitelist name.\n     * @param entry Entry to edit (modified on success).\n     * @return True when the entry was saved.\n     */\n    bool edit_entry(const QString& name, WhitelistEntry& entry);\n    /**\n     * @brief Notifies observers that the whitelist collection changed.\n     */\n    void notify_changed();\n\n    /**\n     * @brief Backing store for whitelist data.\n     */\n    WhitelistStore& store_;\n    /**\n     * @brief List widget showing available whitelists.\n     */\n    QPointer<QListWidget> list_widget_;\n    /**\n     * @brief Add button pointer.\n     */\n    QPointer<QPushButton> add_button_;\n    /**\n     * @brief Edit button pointer.\n     */\n    QPointer<QPushButton> edit_button_;\n    /**\n     * @brief Remove button pointer.\n     */\n    QPointer<QPushButton> remove_button_;\n    /**\n     * @brief Callback invoked after list changes.\n     */\n    std::function<void()> on_lists_changed_;\n};\n\n#endif\n"
  },
  {
    "path": "app/include/WhitelistStore.hpp",
    "content": "#ifndef WHITELIST_STORE_HPP\n#define WHITELIST_STORE_HPP\n\n#include <string>\n#include <vector>\n#include <unordered_map>\n#include <optional>\n\nclass Settings;\n\nstruct WhitelistEntry {\n    std::vector<std::string> categories;\n    std::vector<std::string> subcategories;\n};\n\nclass WhitelistStore {\npublic:\n    explicit WhitelistStore(std::string config_dir);\n\n    bool load();\n    bool save() const;\n\n    std::vector<std::string> list_names() const;\n    std::optional<WhitelistEntry> get(const std::string& name) const;\n    void set(const std::string& name, WhitelistEntry entry);\n    void remove(const std::string& name);\n    bool empty() const { return entries_.empty(); }\n\n    // Migration helper\n    void ensure_default_from_legacy(const std::vector<std::string>& cats,\n                                    const std::vector<std::string>& subs);\n    void initialize_from_settings(Settings& settings);\n\n    std::string default_name() const { return default_name_; }\n\nprivate:\n    std::string file_path_;\n    std::unordered_map<std::string, WhitelistEntry> entries_;\n    std::string default_name_ = \"Default\";\n};\n\n#endif\n"
  },
  {
    "path": "app/include/app_version.hpp",
    "content": "#pragma once\n\n#include \"Version.hpp\"\n\n\nconst Version APP_VERSION = Version{1, 7, 3};\n"
  },
  {
    "path": "app/include/constants.hpp",
    "content": "#ifndef CONSTANTS_HPP\n#define CONSTANTS_HPP\n\nconstexpr auto APP_NAME = \"AI File Sorter\";\nconstexpr auto APP_NAME_DIR = \"AIFileSorter\";\n\n#endif"
  },
  {
    "path": "app/include/external/dotenv.h",
    "content": "// Copyright (c) 2018 Heikki Johannes Hildén <hildenjohannes@gmail.com>\n//\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//\n//     * Redistributions of source code must retain the above copyright\n//       notice, this list of conditions and the following disclaimer.\n//\n//     * Redistributions in binary form must reproduce the above\n//       copyright notice, this list of conditions and the following\n//       disclaimer in the documentation and/or other materials provided\n//       with the distribution.\n//\n//     * Neither the name of copyright holder nor the names of other\n//       contributors may be used to endorse or promote products derived\n//       from this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n///\n/// \\file dotenv.h\n///\n#pragma once\n\n#include <string>\n#include <cstdlib>\n#include <fstream>\n#include <iostream>\n#include <algorithm>\n#include <functional>\n#include <cctype>\n\n///\n/// Utility class for loading environment variables from a file.\n///\n/// ### Typical use\n///\n/// Given a file `.env`\n///\n/// \\code\n/// DATABASE_HOST=localhost\n/// DATABASE_USERNAME=user\n/// DATABASE_PASSWORD=\"antipasto\"\n/// \\endcode\n///\n/// and a program `example.cpp`\n///\n/// \\code\n/// // example.cpp\n/// #include <iostream>\n/// #include <dotenv.h>\n///\n/// int main()\n/// {\n///     dotenv::init();\n///\n///     std::cout << std::getenv(\"DATABASE_USERNAME\") << std::endl;\n///     std::cout << std::getenv(\"DATABASE_PASSWORD\") << std::endl;\n///\n///     return 0;\n/// }\n/// \\endcode\n///\n/// Compile and run the program, e.g. using,\n///\n/// \\code\n/// c++ example.cpp -o example -I/usr/local/include/laserpants/dotenv-0.9.3 && ./example\n/// \\endcode\n///\n/// and the output is:\n///\n/// \\code\n/// user\n/// antipasto\n/// \\endcode\n///\n/// \\see https://github.com/laserpants/dotenv-cpp\n///\nclass dotenv\n{\npublic:\n    dotenv() = delete;\n    ~dotenv() = delete;\n\n    static const unsigned char Preserve = 1 << 0;\n\n    static const int OptionsNone = 0;\n\n    static void init(const char* filename = \".env\");\n    static void init(int flags, const char* filename = \".env\");\n\n    static std::string getenv(const char* name, const std::string& def = \"\");\n\nprivate:\n    static void do_init(int flags, const char* filename);\n    static std::string strip_quotes(const std::string& str);\n\n    static std::pair<std::string,bool> resolve_vars(size_t iline, const std::string& str);\n    static void  ltrim(std::string& s);\n    static void  rtrim(std::string& s);\n    static void  trim(std::string& s);\n    static std::string trim_copy(std::string s);\n    static size_t find_var_start(const std::string& str, size_t pos, std::string& start_tag);\n    static size_t find_var_end(const std::string& str, size_t pos, const std::string& start_tag);\n};\n\n///\n/// Read and initialize environment variables from the `.env` file, or a file\n/// specified by the \\a filename argument.\n///\n/// \\param filename a file to read environment variables from\n///\ninline void dotenv::init(const char* filename)\n{\n    dotenv::do_init(OptionsNone, filename);\n}\n\n///\n/// Read and initialize environment variables using the provided configuration\n/// flags.\n///\n/// By default, if a name is already present in the environment, `dotenv::init()`\n/// will replace it with the new value. To preserve existing variables, you\n/// must pass the `Preserve` flag.\n///\n/// \\code\n/// dotenv::init(dotenv::Preserve);\n/// \\endcode\n///\n/// \\param flags    configuration flags\n/// \\param filename a file to read environment variables from\n///\ninline void dotenv::init(int flags, const char* filename)\n{\n    dotenv::do_init(flags, filename);\n}\n\n///\n/// Wrapper for std::getenv() which also takes a default value, in case the\n/// variable turns out to be empty.\n///\n/// \\param name the name of the variable to look up\n/// \\param def  a default value\n///\n/// \\returns the value of the environment variable \\a name, or \\a def if the\n///          variable is not set\n///\ninline std::string dotenv::getenv(const char* name, const std::string& def)\n{\n    const char* str = std::getenv(name);\n    return str ? std::string(str) : def;\n}\n\n#ifdef _MSC_VER\n\n// https://stackoverflow.com/questions/17258029/c-setenv-undefined-identifier-in-visual-studio\ninline int setenv(const char *name, const char *value, int overwrite)\n{\n    int errcode = 0;\n\n    if (!overwrite)\n    {\n        size_t envsize = 0;\n        errcode = getenv_s(&envsize, NULL, 0, name);\n        if (errcode || envsize) return errcode;\n    }\n    return _putenv_s(name, value);\n}\n\n#endif // _MSC_VER\n\n///\n/// Look for start of variable expression in input string\n/// on the form $VARIABLE or ${VARIABLE}\n///\n/// \\param str  in:  string to search in\n/// \\param pos  in:  search from position\n/// \\param pos  out: start tag found\n///\n/// \\returns The start position of next variable expression or std::string::npos if not found\n///\ninline size_t dotenv::find_var_start(const std::string& str, size_t pos, std::string& start_tag)\n{\n   size_t p1      = str.find('$',pos);\n   size_t p2      = str.find(\"${\",pos);\n   size_t pos_var = (std::min)(p1,p2);\n   if(pos_var != std::string::npos) start_tag = (pos_var == p2)? \"${\":\"$\";\n   return pos_var;\n}\n\n///\n/// Look for end of variable expression in input string\n/// on the form $VARIABLE or ${VARIABLE}\n///\n/// \\param str  in:  string to search in\n/// \\param pos  in:  search from position (result from find_var_start)\n/// \\param pos  in:  start tag\n///\n/// \\returns The next end position of variable expression or std::string::npos if not found\n///\ninline size_t dotenv::find_var_end(const std::string& str, size_t pos, const std::string& start_tag)\n{\n   char end_tag    = (start_tag == \"${\")? '}':' ';\n   size_t pos_end  = str.find(end_tag,pos);\n   // special case when $VARIABLE is at end of str with no trailing whitespace\n   if(pos_end == std::string::npos && end_tag==' ') pos_end = str.length();\n   return pos_end;\n}\n\n// trim whitespace from left (in place)\ninline void dotenv::ltrim(std::string& s) {\n    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) {return !std::isspace(c); }));\n}\n\n// trim whitespace from right (in place)\ninline void dotenv::rtrim(std::string& s) {\n    s.erase(std::find_if(s.rbegin(), s.rend(), [](int c) {return !std::isspace(c); }).base(), s.end());\n}\n\n// trim both ends (in place)\ninline void dotenv::trim(std::string& s) {\n    ltrim(s);\n    rtrim(s);\n}\n\n// trim from both ends (copying)\ninline std::string dotenv::trim_copy(std::string s) {\n    trim(s);\n    return s;\n}\n\n///\n/// Resolve variables of the form $VARIABLE or ${VARIABLE} in a string\n///\n/// \\param iline line number in .env file\n/// \\param str   the string to be resolved, containing 0 or more variables\n/// \\param ok    true on return if no variables found or all variables resolved ok\n///\n/// \\returns pair with <resolved, true> if ok, or <partial, false> if error\n///\ninline std::pair<std::string, bool> dotenv::resolve_vars(size_t iline, const std::string& str)\n{\n   std::string resolved;\n\n   size_t pos = 0;\n   size_t pre_pos = pos;\n   size_t nvar = 0;\n\n   bool finished=false;\n   while(!finished)\n   {\n      // look for start of variable expression after pos\n      std::string start_tag;\n      pos = find_var_start(str,pos,start_tag);\n      if(pos != std::string::npos)\n      {\n         // a variable definition detected\n         nvar++;\n\n         // keep start of variable expression\n         size_t pos_start = pos;\n\n         size_t lstart = start_tag.length();  // length of start tag\n         size_t lend   = (lstart>1)? 1 : 0;   // length of end tag\n\n         // add substring since last variable\n         resolved += str.substr(pre_pos,pos-pre_pos);\n\n         // look for end of variable expression\n         pos = find_var_end(str,pos,start_tag);\n         if(pos != std::string::npos)\n         {\n            // variable name with decoration\n            std::string var = str.substr(pos_start,pos-pos_start+1);\n\n            // variable name without decoration\n            std::string env_var = var.substr(lstart,var.length()-lstart-lend);\n\n            // remove possible whitespace at the end\n            rtrim(env_var);\n\n            // evaluate environment variable\n            if(const char* env_str = std::getenv(env_var.c_str()))\n            {\n               resolved += env_str;\n               nvar--; // decrement to indicate variable resolved\n            }\n            else\n            {\n               // could not resolve the variable, so don't decrement\n               std::cout << \"dotenv: Variable \" << var << \" is not defined on line \" << iline << std::endl;\n            }\n\n            // skip end tag\n            pre_pos = pos+lend;\n         }\n      }\n      else {\n         // no more variables\n         finished = true;\n      }\n   }\n\n   // add possible trailing non-whitespace after last variable\n   if(pre_pos < str.length())\n   {\n      resolved += str.substr(pre_pos);\n   }\n\n   // nvar must be 0, or else we have an error\n   return std::make_pair(resolved,(nvar==0));\n}\n\ninline void dotenv::do_init(int flags, const char* filename)\n{\n    std::ifstream file;\n    std::string line;\n\n    file.open(filename);\n\n    if (file)\n    {\n        unsigned int i = 1;\n\n        while (getline(file, line))\n        {\n            const auto pos = line.find(\"=\");\n\n            if (pos == std::string::npos) {\n                std::cout << \"dotenv: Ignoring ill-formed assignment on line \"\n                          << i << \": '\" << line << \"'\" << std::endl;\n            } else {\n                auto name = trim_copy(line.substr(0, pos));\n                auto line_stripped = strip_quotes(trim_copy(line.substr(pos + 1)));\n\n                // resolve any contained variable expressions in 'line_stripped'\n                auto p = resolve_vars(i,line_stripped);\n                bool ok = p.second;\n                if(!ok) {\n                   std::cout << \"dotenv: Ignoring ill-formed assignment on line \"\n                   << i << \": '\" << line << \"'\" << std::endl;\n                }\n                else {\n\n                   // variable resolved ok, set as environment variable\n                   const auto& val = p.first;\n                   setenv(name.c_str(), val.c_str(), ~flags & dotenv::Preserve);\n                }\n            }\n            ++i;\n        }\n    }\n}\n\ninline std::string dotenv::strip_quotes(const std::string& str)\n{\n    const std::size_t len = str.length();\n\n    if (len < 2)\n        return str;\n\n    const char first = str[0];\n    const char last = str[len - 1];\n\n    if (first == last && ('\"' == first || '\\'' == first))\n        return str.substr(1, len - 2);\n\n    return str;\n}\n"
  },
  {
    "path": "app/includePaths.txt",
    "content": "# Useful, for example, for VS Code\n\n${workspaceFolder}/**\n/usr/include/qt\n/usr/include/qt/QtCore\n/usr/include/qt/QtGui\n/usr/include/qt/QtWidgets\n/usr/include/x86_64-linux-gnu/qt6\n/usr/include/x86_64-linux-gnu/qt6/QtCore\n/usr/include/x86_64-linux-gnu/qt6/QtGui\n/usr/include/x86_64-linux-gnu/qt6/QtWidgets\n/usr/lib/x86_64-linux-gnu/qt6/mkspecs\n"
  },
  {
    "path": "app/lib/CategorizationDialog.cpp",
    "content": "#include \"CategorizationDialog.hpp\"\n\n#include \"DatabaseManager.hpp\"\n#include \"Logger.hpp\"\n#include \"MovableCategorizedFile.hpp\"\n#include \"TestHooks.hpp\"\n#include \"Utils.hpp\"\n#include \"UndoManager.hpp\"\n#include \"DryRunPreviewDialog.hpp\"\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n\n#include <QAbstractItemView>\n#include <QApplication>\n#include <QStyle>\n#include <QBrush>\n#include <QCheckBox>\n#include <QCloseEvent>\n#include <QDialogButtonBox>\n#include <QEvent>\n#include <QFormLayout>\n#include <QFrame>\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QPushButton>\n#include <QIcon>\n#include <QImage>\n#include <QLabel>\n#include <QLineEdit>\n#include <QMessageBox>\n#include <QStandardItem>\n#include <QStandardItemModel>\n#include <QStringList>\n#include <QShortcut>\n#include <QTableView>\n#include <QVBoxLayout>\n#include <QSignalBlocker>\n#include <QFile>\n#include <QFileIconProvider>\n#include <QFileInfo>\n#include <QPainter>\n#include <QPen>\n#include <QPixmap>\n#include <QPolygonF>\n#include <QBuffer>\n#include <QScrollArea>\n#include <QScreen>\n#include <QDir>\n#include <QJsonArray>\n#include <QJsonDocument>\n#include <QJsonObject>\n#include <QDateTime>\n\n#include <fmt/format.h>\n\n#include <algorithm>\n#include <cctype>\n#include <vector>\n#include <filesystem>\n#include <optional>\n#include <chrono>\n#include <unordered_map>\n#include <unordered_set>\n\nnamespace {\n\nTestHooks::CategorizationMoveProbe& move_probe_slot() {\n    static TestHooks::CategorizationMoveProbe probe;\n    return probe;\n}\n\nstruct ScopedFlag {\n    bool& ref;\n    explicit ScopedFlag(bool& target) : ref(target) { ref = true; }\n    ~ScopedFlag() { ref = false; }\n};\n\nvoid ensure_unique_image_suggested_names(std::vector<CategorizedFile>& files,\n                                         const std::string& base_dir,\n                                         bool use_subcategory);\n\nQString edit_icon_html(int size = 16);\n\nstd::string to_lower_copy_str(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value;\n}\n\nstd::string trim_copy(const std::string& value) {\n    std::string result = value;\n    const auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space));\n    result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end());\n    return result;\n}\n\nbool is_missing_category_label(const std::string& value) {\n    const std::string trimmed = trim_copy(value);\n    if (trimmed.empty()) {\n        return true;\n    }\n    return to_lower_copy_str(trimmed) == \"uncategorized\";\n}\n\n// Dialog for bulk editing category and subcategory values.\nclass BulkEditDialog final : public QDialog {\npublic:\n    explicit BulkEditDialog(bool allow_subcategory, QWidget* parent = nullptr)\n        : QDialog(parent),\n          allow_subcategory_(allow_subcategory) {\n        setWindowTitle(QObject::tr(\"Edit selected items\"));\n\n        auto* layout = new QVBoxLayout(this);\n        auto* form_layout = new QFormLayout();\n\n        category_edit_ = new QLineEdit(this);\n        category_edit_->setPlaceholderText(QObject::tr(\"Leave empty to keep existing\"));\n        form_layout->addRow(QObject::tr(\"Category\"), category_edit_);\n\n        if (allow_subcategory_) {\n            subcategory_edit_ = new QLineEdit(this);\n            subcategory_edit_->setPlaceholderText(QObject::tr(\"Leave empty to keep existing\"));\n            form_layout->addRow(QObject::tr(\"Subcategory\"), subcategory_edit_);\n        }\n\n        layout->addLayout(form_layout);\n\n        auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);\n        ok_button_ = buttons->button(QDialogButtonBox::Ok);\n        if (ok_button_) {\n            ok_button_->setEnabled(false);\n        }\n        connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);\n        connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);\n        connect(category_edit_, &QLineEdit::textChanged, this, &BulkEditDialog::update_ok_state);\n        if (subcategory_edit_) {\n            connect(subcategory_edit_, &QLineEdit::textChanged, this, &BulkEditDialog::update_ok_state);\n        }\n\n        layout->addWidget(buttons);\n        update_ok_state();\n    }\n\n    std::string category() const {\n        return category_edit_ ? category_edit_->text().trimmed().toStdString() : std::string();\n    }\n\n    std::string subcategory() const {\n        if (!allow_subcategory_ || !subcategory_edit_) {\n            return std::string();\n        }\n        return subcategory_edit_->text().trimmed().toStdString();\n    }\n\nprivate:\n    void update_ok_state() {\n        const bool has_category = category_edit_ && !category_edit_->text().trimmed().isEmpty();\n        const bool has_subcategory = allow_subcategory_ && subcategory_edit_ &&\n                                     !subcategory_edit_->text().trimmed().isEmpty();\n        if (ok_button_) {\n            ok_button_->setEnabled(has_category || has_subcategory);\n        }\n    }\n\n    QLineEdit* category_edit_{nullptr};\n    QLineEdit* subcategory_edit_{nullptr};\n    QPushButton* ok_button_{nullptr};\n    bool allow_subcategory_{false};\n};\n\nbool contains_only_allowed_chars(const std::string& value) {\n    for (unsigned char ch : value) {\n        if (std::iscntrl(ch)) {\n            return false;\n        }\n        static const std::string forbidden = R\"(<>:\"/\\|?*)\";\n        if (forbidden.find(static_cast<char>(ch)) != std::string::npos) {\n            return false;\n        }\n        // Everything else is allowed (including non-ASCII letters and punctuation).\n    }\n    return true;\n}\n\nbool has_leading_or_trailing_space_or_dot(const std::string& value) {\n    if (value.empty()) {\n        return false;\n    }\n    const unsigned char first = static_cast<unsigned char>(value.front());\n    const unsigned char last = static_cast<unsigned char>(value.back());\n    return std::isspace(first) || std::isspace(last) || value.front() == '.' || value.back() == '.';\n}\n\nbool is_reserved_windows_name(const std::string& value) {\n    static const std::vector<std::string> reserved = {\n        \"con\",\"prn\",\"aux\",\"nul\",\n        \"com1\",\"com2\",\"com3\",\"com4\",\"com5\",\"com6\",\"com7\",\"com8\",\"com9\",\n        \"lpt1\",\"lpt2\",\"lpt3\",\"lpt4\",\"lpt5\",\"lpt6\",\"lpt7\",\"lpt8\",\"lpt9\"\n    };\n    const std::string lower = to_lower_copy_str(value);\n    return std::find(reserved.begin(), reserved.end(), lower) != reserved.end();\n}\n\nbool looks_like_extension_label(const std::string& value) {\n    const auto dot_pos = value.rfind('.');\n    if (dot_pos == std::string::npos || dot_pos == value.size() - 1) {\n        return false;\n    }\n    const std::string ext = value.substr(dot_pos + 1);\n    if (ext.empty() || ext.size() > 5) {\n        return false;\n    }\n    return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); });\n}\n\nbool validate_labels(const std::string& category,\n                     const std::string& subcategory,\n                     std::string& error,\n                     bool allow_identical = false) {\n    constexpr size_t kMaxLabelLength = 80;\n    if (category.empty() || subcategory.empty()) {\n        error = \"Category or subcategory is empty\";\n        return false;\n    }\n    if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) {\n        error = \"Category or subcategory exceeds max length\";\n        return false;\n    }\n    if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) {\n        error = \"Category or subcategory contains disallowed characters\";\n        return false;\n    }\n    if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) {\n        error = \"Category or subcategory looks like a file extension\";\n        return false;\n    }\n    if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) {\n        error = \"Category or subcategory is a reserved name\";\n        return false;\n    }\n    if (!allow_identical && to_lower_copy_str(category) == to_lower_copy_str(subcategory)) {\n        error = \"Category and subcategory are identical\";\n        return false;\n    }\n    return true;\n}\n\nstd::chrono::system_clock::time_point to_system_clock(std::filesystem::file_time_type file_time) {\n#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907L\n    return std::chrono::clock_cast<std::chrono::system_clock>(file_time);\n#else\n    const auto now = decltype(file_time)::clock::now();\n    const auto delta = std::chrono::duration_cast<std::chrono::system_clock::duration>(file_time - now);\n    return std::chrono::system_clock::now() + delta;\n#endif\n}\n\n} // namespace\n\nnamespace TestHooks {\n\nvoid set_categorization_move_probe(CategorizationMoveProbe probe) {\n    move_probe_slot() = std::move(probe);\n}\n\nvoid reset_categorization_move_probe() {\n    move_probe_slot() = CategorizationMoveProbe{};\n}\n\n} // namespace TestHooks\n\nCategorizationDialog::CategorizationDialog(DatabaseManager* db_manager,\n                                           bool show_subcategory_col,\n                                           const std::string& undo_dir,\n                                           CategoryLanguage category_language,\n                                           QWidget* parent)\n    : QDialog(parent),\n      db_manager(db_manager),\n      category_language_(category_language),\n      show_subcategory_column(show_subcategory_col),\n      core_logger(Logger::get_logger(\"core_logger\")),\n      db_logger(Logger::get_logger(\"db_logger\")),\n      ui_logger(Logger::get_logger(\"ui_logger\")),\n      undo_dir_(undo_dir)\n{\n    resize(1100, 720);\n    setSizeGripEnabled(true);\n    Qt::WindowFlags flags = windowFlags();\n    flags &= ~Qt::WindowType_Mask;\n    flags |= Qt::Window;\n    flags |= Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint;\n    flags &= ~Qt::MSWindowsFixedSizeDialogHint;\n    setWindowFlags(flags);\n    setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);\n    setup_ui();\n    retranslate_ui();\n}\n\n\nbool CategorizationDialog::is_dialog_valid() const\n{\n    return model != nullptr && table_view != nullptr;\n}\n\n\nvoid CategorizationDialog::show_results(const std::vector<CategorizedFile>& files,\n                                        const std::string& base_dir_override,\n                                        bool include_subdirectories,\n                                        bool allow_image_renames,\n                                        bool allow_document_renames)\n{\n    categorized_files = files;\n    include_subdirectories_ = include_subdirectories;\n    allow_image_renames_ = allow_image_renames;\n    allow_document_renames_ = allow_document_renames;\n    base_dir_.clear();\n    if (!base_dir_override.empty()) {\n        base_dir_ = base_dir_override;\n    } else if (!categorized_files.empty()) {\n        base_dir_ = categorized_files.front().file_path;\n    }\n    ensure_unique_image_suggested_names(categorized_files, base_dir_, show_subcategory_column);\n    set_show_rename_column(std::any_of(categorized_files.begin(),\n                                       categorized_files.end(),\n                                       [](const CategorizedFile& file) {\n                                           return !file.suggested_name.empty();\n                                       }));\n    update_rename_only_checkbox_state();\n    apply_category_visibility();\n    apply_subcategory_visibility();\n    dry_run_plan_.clear();\n    clear_move_history();\n    if (undo_button) {\n        undo_button->setEnabled(false);\n        undo_button->setVisible(false);\n    }\n    {\n        ScopedFlag guard(suppress_item_changed_);\n        populate_model();\n    }\n    on_rename_images_only_toggled(rename_images_only_checkbox && rename_images_only_checkbox->isChecked());\n    on_rename_documents_only_toggled(rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked());\n    update_subcategory_checkbox_state();\n    exec();\n}\n\n\nvoid CategorizationDialog::setup_ui()\n{\n    auto* layout = new QVBoxLayout(this);\n\n    auto* scroll_area = new QScrollArea(this);\n    scroll_area->setWidgetResizable(true);\n    scroll_area->setFrameShape(QFrame::NoFrame);\n\n    auto* scroll_widget = new QWidget(scroll_area);\n    auto* scroll_layout = new QVBoxLayout(scroll_widget);\n    scroll_layout->setContentsMargins(0, 0, 0, 0);\n\n    auto* select_layout = new QHBoxLayout();\n    select_layout->setContentsMargins(0, 0, 0, 0);\n\n    select_all_checkbox = new QCheckBox(this);\n    select_all_checkbox->setChecked(true);\n    select_highlighted_button = new QPushButton(this);\n    bulk_edit_button = new QPushButton(this);\n\n    select_layout->addWidget(select_all_checkbox);\n    select_layout->addWidget(select_highlighted_button);\n    select_layout->addWidget(bulk_edit_button);\n    select_layout->addStretch(1);\n    scroll_layout->addLayout(select_layout);\n\n    show_subcategories_checkbox = new QCheckBox(this);\n    show_subcategories_checkbox->setChecked(show_subcategory_column);\n    scroll_layout->addWidget(show_subcategories_checkbox);\n\n    dry_run_checkbox = new QCheckBox(this);\n    dry_run_checkbox->setChecked(false);\n    scroll_layout->addWidget(dry_run_checkbox);\n\n    rename_images_only_checkbox = new QCheckBox(this);\n    rename_images_only_checkbox->setChecked(false);\n    rename_images_only_checkbox->setEnabled(false);\n    scroll_layout->addWidget(rename_images_only_checkbox);\n\n    rename_documents_only_checkbox = new QCheckBox(this);\n    rename_documents_only_checkbox->setChecked(false);\n    rename_documents_only_checkbox->setEnabled(false);\n    scroll_layout->addWidget(rename_documents_only_checkbox);\n\n    model = new QStandardItemModel(this);\n    model->setColumnCount(8);\n\n    table_view = new QTableView(this);\n    table_view->setModel(model);\n    table_view->setSelectionBehavior(QAbstractItemView::SelectRows);\n    table_view->setSelectionMode(QAbstractItemView::ExtendedSelection);\n    table_view->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed);\n    table_view->horizontalHeader()->setStretchLastSection(true);\n    table_view->verticalHeader()->setVisible(false);\n    table_view->horizontalHeader()->setSectionsClickable(true);\n    table_view->horizontalHeader()->setSortIndicatorShown(true);\n    table_view->setSortingEnabled(true);\n    table_view->setColumnHidden(ColumnType, false);\n    table_view->setColumnHidden(ColumnSuggestedName, !show_rename_column);\n    table_view->setColumnHidden(ColumnSubcategory, !show_subcategory_column);\n    table_view->setColumnHidden(ColumnPreview, false);\n    table_view->setColumnWidth(ColumnSelect, 70);\n    table_view->setIconSize(QSize(16, 16));\n    table_view->setColumnWidth(ColumnType, table_view->iconSize().width() + 12);\n    scroll_layout->addWidget(table_view, 1);\n\n    auto* tip_label = new QLabel(this);\n    tip_label->setWordWrap(true);\n    QFont tip_font = tip_label->font();\n    tip_font.setItalic(true);\n    tip_label->setFont(tip_font);\n    tip_label->setTextFormat(Qt::RichText);\n    tip_label->setText(tr(\"Tip: Click %1 cells to rename them.\")\n                           .arg(edit_icon_html()));\n    scroll_layout->addWidget(tip_label);\n\n    confirm_button = new QPushButton(this);\n    continue_button = new QPushButton(this);\n    undo_button = new QPushButton(this);\n    undo_button->setEnabled(false);\n    undo_button->setVisible(false);\n    close_button = new QPushButton(this);\n    close_button->setVisible(false);\n\n    scroll_area->setWidget(scroll_widget);\n    layout->addWidget(scroll_area, 1);\n\n    auto* bottom_layout = new QHBoxLayout();\n    bottom_layout->setContentsMargins(0, 0, 0, 0);\n    bottom_layout->setSpacing(8);\n    bottom_layout->addStretch(1);\n    bottom_layout->addWidget(confirm_button);\n    bottom_layout->addWidget(continue_button);\n    bottom_layout->addWidget(undo_button);\n    bottom_layout->addWidget(close_button);\n\n    layout->addLayout(bottom_layout);\n\n    if (auto* screen = this->screen()) {\n        const QRect available = screen->availableGeometry();\n        const int max_height = static_cast<int>(available.height() * 0.9);\n        setMaximumHeight(max_height);\n    }\n\n    connect(confirm_button, &QPushButton::clicked, this, &CategorizationDialog::on_confirm_and_sort_button_clicked);\n    connect(continue_button, &QPushButton::clicked, this, &CategorizationDialog::on_continue_later_button_clicked);\n    connect(close_button, &QPushButton::clicked, this, &CategorizationDialog::accept);\n    connect(undo_button, &QPushButton::clicked, this, &CategorizationDialog::on_undo_button_clicked);\n    connect(select_all_checkbox, &QCheckBox::toggled, this, &CategorizationDialog::on_select_all_toggled);\n    connect(select_highlighted_button, &QPushButton::clicked, this, &CategorizationDialog::on_select_highlighted_clicked);\n    connect(bulk_edit_button, &QPushButton::clicked, this, &CategorizationDialog::on_bulk_edit_clicked);\n    connect(model, &QStandardItemModel::itemChanged, this, &CategorizationDialog::on_item_changed);\n    connect(show_subcategories_checkbox, &QCheckBox::toggled,\n            this, &CategorizationDialog::on_show_subcategories_toggled);\n    connect(rename_images_only_checkbox, &QCheckBox::toggled,\n            this, &CategorizationDialog::on_rename_images_only_toggled);\n    connect(rename_documents_only_checkbox, &QCheckBox::toggled,\n            this, &CategorizationDialog::on_rename_documents_only_toggled);\n\n    auto* select_highlighted_shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Space), this);\n    connect(select_highlighted_shortcut, &QShortcut::activated,\n            this, &CategorizationDialog::on_select_highlighted_clicked);\n}\n\n\nnamespace {\nQFileIconProvider& file_icon_provider()\n{\n    static QFileIconProvider provider;\n    return provider;\n}\n\nQIcon fallback_image_icon()\n{\n    static QIcon icon;\n    if (!icon.isNull()) {\n        return icon;\n    }\n\n    auto make_pixmap = [](int size) {\n        QPixmap pixmap(size, size);\n        pixmap.fill(Qt::transparent);\n\n        QPainter painter(&pixmap);\n        painter.setRenderHint(QPainter::Antialiasing, true);\n        QPen frame_pen(QColor(120, 120, 120));\n        frame_pen.setWidthF(1.0);\n        painter.setPen(frame_pen);\n        painter.setBrush(QColor(240, 240, 240));\n        painter.drawRoundedRect(QRectF(1, 1, size - 2, size - 2), 2, 2);\n\n        QRectF image_rect(3, 4, size - 6, size - 7);\n        painter.setPen(Qt::NoPen);\n        painter.setBrush(QColor(140, 200, 245));\n        painter.drawRect(image_rect);\n\n        QPolygonF mountain;\n        mountain << QPointF(image_rect.left() + 1, image_rect.bottom() - 1)\n                 << QPointF(image_rect.center().x() - 1, image_rect.top() + 2)\n                 << QPointF(image_rect.right() - 1, image_rect.bottom() - 1);\n        painter.setBrush(QColor(90, 170, 125));\n        painter.drawPolygon(mountain);\n\n        painter.setBrush(QColor(255, 210, 80));\n        painter.drawEllipse(QPointF(image_rect.right() - 3, image_rect.top() + 3), 1.6, 1.6);\n\n        return pixmap;\n    };\n\n    icon.addPixmap(make_pixmap(16));\n    icon.addPixmap(make_pixmap(32));\n    return icon;\n}\n\n#if defined(Q_OS_WIN)\nbool icons_match(const QIcon& left, const QIcon& right, const QSize& size)\n{\n    if (left.isNull() || right.isNull()) {\n        return false;\n    }\n    const QPixmap left_pixmap = left.pixmap(size);\n    const QPixmap right_pixmap = right.pixmap(size);\n    if (left_pixmap.isNull() || right_pixmap.isNull()) {\n        return false;\n    }\n    const QImage left_image = left_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);\n    const QImage right_image = right_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);\n    if (left_image.size() != right_image.size()) {\n        return false;\n    }\n    return left_image == right_image;\n}\n#endif\n\nQIcon type_icon(const QString& code, const QString& file_path)\n{\n    if (auto* style = QApplication::style()) {\n        if (code == QStringLiteral(\"D\")) {\n            return style->standardIcon(QStyle::SP_DirIcon);\n        }\n        if (code == QStringLiteral(\"I\")) {\n            QIcon icon = QIcon::fromTheme(QStringLiteral(\"image-x-generic\"));\n            if (icon.isNull()) {\n                icon = QIcon::fromTheme(QStringLiteral(\"image\"));\n            }\n            if (icon.isNull()) {\n                icon = QIcon::fromTheme(QStringLiteral(\"image-x-generic-symbolic\"));\n            }\n            if (icon.isNull() && !file_path.isEmpty()) {\n                icon = file_icon_provider().icon(QFileInfo(file_path));\n            }\n            if (icon.isNull()) {\n                icon = fallback_image_icon();\n            }\n#if defined(Q_OS_WIN)\n            if (icons_match(icon, style->standardIcon(QStyle::SP_FileIcon), QSize(16, 16))) {\n                icon = fallback_image_icon();\n            }\n#endif\n            return icon.isNull() ? style->standardIcon(QStyle::SP_FileIcon) : icon;\n        }\n        return style->standardIcon(QStyle::SP_FileIcon);\n    }\n    return {};\n}\n\nQIcon edit_icon()\n{\n    QIcon icon = QIcon::fromTheme(QStringLiteral(\"edit-rename\"));\n    if (!icon.isNull()) {\n        return icon;\n    }\n    icon = QIcon::fromTheme(QStringLiteral(\"document-edit\"));\n    if (!icon.isNull()) {\n        return icon;\n    }\n    if (auto* style = QApplication::style()) {\n        return style->standardIcon(QStyle::SP_FileDialogDetailedView);\n    }\n    return QIcon();\n}\n\nQString edit_icon_html(int size)\n{\n    const QIcon icon = edit_icon();\n    const QPixmap pixmap = icon.pixmap(size, size);\n    if (pixmap.isNull()) {\n        return QStringLiteral(\"[edit]\");\n    }\n    QByteArray bytes;\n    QBuffer buffer(&bytes);\n    buffer.open(QIODevice::WriteOnly);\n    pixmap.save(&buffer, \"PNG\");\n    return QStringLiteral(\"<img src=\\\"data:image/png;base64,%1\\\" width=\\\"%2\\\" height=\\\"%2\\\"/>\")\n        .arg(QString::fromLatin1(bytes.toBase64()))\n        .arg(size);\n}\n\nbool is_supported_image_entry(const std::string& file_path,\n                              const std::string& file_name,\n                              FileType file_type)\n{\n    if (file_type != FileType::File) {\n        return false;\n    }\n    const auto full_path = Utils::utf8_to_path(file_path) / Utils::utf8_to_path(file_name);\n    return LlavaImageAnalyzer::is_supported_image(full_path);\n}\n\nbool is_supported_document_entry(const std::string& file_path,\n                                 const std::string& file_name,\n                                 FileType file_type)\n{\n    if (file_type != FileType::File) {\n        return false;\n    }\n    const auto full_path = Utils::utf8_to_path(file_path) / Utils::utf8_to_path(file_name);\n    return DocumentTextAnalyzer::is_supported_document(full_path);\n}\n\nstd::filesystem::path build_suggested_target_dir(const CategorizedFile& file,\n                                                 const std::string& base_dir_override,\n                                                 bool use_subcategory)\n{\n    const auto source_dir = Utils::utf8_to_path(file.file_path);\n    const auto base_dir = base_dir_override.empty()\n        ? source_dir\n        : Utils::utf8_to_path(base_dir_override);\n    if (file.rename_only || file.category.empty()) {\n        return source_dir;\n    }\n\n    const auto category = Utils::utf8_to_path(file.category);\n    if (use_subcategory && !file.subcategory.empty()) {\n        const auto subcategory = Utils::utf8_to_path(file.subcategory);\n        return base_dir / category / subcategory;\n    }\n    return base_dir / category;\n}\n\nstruct NumericSuffix {\n    std::string base;\n    int value{0};\n    bool has_suffix{false};\n};\n\nNumericSuffix split_numeric_suffix(const std::string& stem) {\n    NumericSuffix result{stem, 0, false};\n    const auto pos = stem.rfind('_');\n    if (pos == std::string::npos || pos + 1 >= stem.size()) {\n        return result;\n    }\n    const std::string suffix = stem.substr(pos + 1);\n    if (suffix.empty()) {\n        return result;\n    }\n    for (unsigned char ch : suffix) {\n        if (!std::isdigit(ch)) {\n            return result;\n        }\n    }\n    int value = 0;\n    try {\n        value = std::stoi(suffix);\n    } catch (...) {\n        return result;\n    }\n    if (value <= 0) {\n        return result;\n    }\n    const std::string base = stem.substr(0, pos);\n    if (base.empty()) {\n        return result;\n    }\n    result.base = base;\n    result.value = value;\n    result.has_suffix = true;\n    return result;\n}\n\nstruct ParentheticalSuffix {\n    std::string base;\n    int value{0};\n    bool has_suffix{false};\n};\n\nParentheticalSuffix split_parenthetical_suffix(const std::string& stem) {\n    ParentheticalSuffix result{stem, 0, false};\n    if (stem.size() < 4) {\n        return result;\n    }\n    if (stem.back() != ')') {\n        return result;\n    }\n    const auto open_pos = stem.rfind('(');\n    if (open_pos == std::string::npos || open_pos == 0) {\n        return result;\n    }\n    if (open_pos == 0 || stem[open_pos - 1] != ' ') {\n        return result;\n    }\n    const std::string number = stem.substr(open_pos + 1, stem.size() - open_pos - 2);\n    if (number.empty()) {\n        return result;\n    }\n    for (unsigned char ch : number) {\n        if (!std::isdigit(ch)) {\n            return result;\n        }\n    }\n    int value = 0;\n    try {\n        value = std::stoi(number);\n    } catch (...) {\n        return result;\n    }\n    if (value <= 0) {\n        return result;\n    }\n    const std::string base = stem.substr(0, open_pos - 1);\n    if (base.empty()) {\n        return result;\n    }\n    result.base = base;\n    result.value = value;\n    result.has_suffix = true;\n    return result;\n}\n\nstd::string build_unique_suggested_name(const std::string& desired_name,\n                                        const std::filesystem::path& target_dir,\n                                        std::unordered_set<std::string>& used_names,\n                                        std::unordered_map<std::string, int>& next_index,\n                                        bool force_numbering)\n{\n    auto conflicts = [&](const std::string& candidate) -> bool {\n        const std::string candidate_lower = to_lower_copy_str(candidate);\n        if (used_names.count(candidate_lower) > 0) {\n            return true;\n        }\n        if (!target_dir.empty()) {\n            std::error_code ec;\n            const auto candidate_path = target_dir / Utils::utf8_to_path(candidate);\n            if (std::filesystem::exists(candidate_path, ec)) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    const auto desired_path = Utils::utf8_to_path(desired_name);\n    std::string stem = Utils::path_to_utf8(desired_path.stem());\n    std::string ext = Utils::path_to_utf8(desired_path.extension());\n    if (stem.empty()) {\n        stem = desired_name;\n        ext.clear();\n    }\n\n    const NumericSuffix suffix = split_numeric_suffix(stem);\n    std::string base_stem = stem;\n    int index = 1;\n    bool has_suffix = false;\n    if (suffix.has_suffix) {\n        base_stem = suffix.base;\n        index = suffix.value;\n        has_suffix = true;\n    }\n\n    if (!force_numbering && !conflicts(desired_name)) {\n        return desired_name;\n    }\n    if (has_suffix && !conflicts(desired_name)) {\n        return desired_name;\n    }\n\n    const std::string key = has_suffix\n                                ? to_lower_copy_str(base_stem + ext)\n                                : to_lower_copy_str(desired_name);\n    auto it = next_index.find(key);\n    if (it != next_index.end()) {\n        index = it->second;\n    }\n\n    while (true) {\n        std::string candidate = base_stem + \"_\" + std::to_string(index) + ext;\n        if (!conflicts(candidate)) {\n            next_index[key] = index + 1;\n            return candidate;\n        }\n        ++index;\n    }\n}\n\nstd::string build_unique_move_name(const std::string& desired_name,\n                                   const std::filesystem::path& target_dir,\n                                   std::unordered_set<std::string>& used_names,\n                                   std::unordered_map<std::string, int>& next_index)\n{\n    auto conflicts = [&](const std::string& candidate) -> bool {\n        const std::string candidate_lower = to_lower_copy_str(candidate);\n        if (used_names.count(candidate_lower) > 0) {\n            return true;\n        }\n        if (!target_dir.empty()) {\n            std::error_code ec;\n            const auto candidate_path = target_dir / Utils::utf8_to_path(candidate);\n            if (std::filesystem::exists(candidate_path, ec)) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    if (!conflicts(desired_name)) {\n        return desired_name;\n    }\n\n    const auto desired_path = Utils::utf8_to_path(desired_name);\n    std::string stem = Utils::path_to_utf8(desired_path.stem());\n    std::string ext = Utils::path_to_utf8(desired_path.extension());\n    if (stem.empty()) {\n        stem = desired_name;\n        ext.clear();\n    }\n\n    const ParentheticalSuffix suffix = split_parenthetical_suffix(stem);\n    std::string base_stem = suffix.has_suffix ? suffix.base : stem;\n    int index = suffix.has_suffix ? suffix.value : 1;\n\n    const std::string key = to_lower_copy_str(base_stem + ext);\n    auto it = next_index.find(key);\n    if (it != next_index.end()) {\n        index = std::max(index, it->second);\n    }\n\n    while (true) {\n        std::string candidate = base_stem + \" (\" + std::to_string(index) + \")\" + ext;\n        if (!conflicts(candidate)) {\n            next_index[key] = index + 1;\n            return candidate;\n        }\n        ++index;\n    }\n}\n\nvoid ensure_unique_image_suggested_names(std::vector<CategorizedFile>& files,\n                                         const std::string& base_dir,\n                                         bool use_subcategory)\n{\n    std::unordered_map<std::string, std::unordered_map<std::string, int>> counts;\n    counts.reserve(files.size());\n\n    for (const auto& file : files) {\n        if (file.suggested_name.empty()) {\n            continue;\n        }\n        if (file.rename_applied) {\n            continue;\n        }\n        if (to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name)) {\n            continue;\n        }\n        if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) {\n            continue;\n        }\n        const auto target_dir = build_suggested_target_dir(file, base_dir, use_subcategory);\n        const std::string dir_key = Utils::path_to_utf8(target_dir);\n        const std::string name_key = to_lower_copy_str(file.suggested_name);\n        counts[dir_key][name_key] += 1;\n    }\n\n    std::unordered_map<std::string, std::unordered_set<std::string>> used_names;\n    std::unordered_map<std::string, std::unordered_map<std::string, int>> next_index;\n\n    for (auto& file : files) {\n        if (file.suggested_name.empty()) {\n            continue;\n        }\n        if (file.rename_applied) {\n            continue;\n        }\n        if (to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name)) {\n            continue;\n        }\n        if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) {\n            continue;\n        }\n        const auto target_dir = build_suggested_target_dir(file, base_dir, use_subcategory);\n        const std::string dir_key = Utils::path_to_utf8(target_dir);\n        const std::string name_key = to_lower_copy_str(file.suggested_name);\n        const bool force_numbering = counts[dir_key][name_key] > 1;\n        auto& dir_used = used_names[dir_key];\n        auto& dir_next = next_index[dir_key];\n\n        const std::string unique_name = build_unique_suggested_name(file.suggested_name,\n                                                                    target_dir,\n                                                                    dir_used,\n                                                                    dir_next,\n                                                                    force_numbering);\n        file.suggested_name = unique_name;\n        dir_used.insert(to_lower_copy_str(unique_name));\n    }\n}\n}\n\nvoid CategorizationDialog::ensure_unique_suggested_names_in_model()\n{\n    if (!model) {\n        return;\n    }\n\n    struct RowEntry {\n        int row{0};\n        std::string file_path;\n        std::string file_name;\n        FileType type{FileType::File};\n        std::string category;\n        std::string subcategory;\n        std::string suggested_name;\n        bool rename_only{false};\n        bool rename_applied{false};\n    };\n\n    std::vector<RowEntry> entries;\n    entries.reserve(model->rowCount());\n\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (!row_is_supported_image(row)) {\n            continue;\n        }\n        auto* file_item = model->item(row, ColumnFile);\n        auto* rename_item = model->item(row, ColumnSuggestedName);\n        if (!file_item || !rename_item) {\n            continue;\n        }\n        const std::string suggested = rename_item->text().toStdString();\n        if (suggested.empty()) {\n            continue;\n        }\n\n        RowEntry entry;\n        entry.row = row;\n        entry.file_path = file_item->data(kFilePathRole).toString().toStdString();\n        if (entry.file_path.empty()) {\n            entry.file_path = base_dir_;\n        }\n        entry.file_name = file_item->text().toStdString();\n        if (to_lower_copy_str(suggested) == to_lower_copy_str(entry.file_name)) {\n            continue;\n        }\n        entry.type = static_cast<FileType>(file_item->data(kFileTypeRole).toInt());\n        entry.rename_only = file_item->data(kRenameOnlyRole).toBool();\n        entry.rename_applied = file_item->data(kRenameAppliedRole).toBool();\n        if (entry.rename_applied) {\n            continue;\n        }\n        if (auto* category_item = model->item(row, ColumnCategory)) {\n            entry.category = category_item->text().toStdString();\n            if (is_missing_category_label(entry.category)) {\n                entry.category.clear();\n            }\n        }\n        if (auto* subcategory_item = model->item(row, ColumnSubcategory)) {\n            entry.subcategory = subcategory_item->text().toStdString();\n            if (is_missing_category_label(entry.subcategory)) {\n                entry.subcategory.clear();\n            }\n        }\n        entry.suggested_name = suggested;\n        entries.push_back(std::move(entry));\n    }\n\n    std::unordered_map<std::string, std::unordered_map<std::string, int>> counts;\n    counts.reserve(entries.size());\n\n    for (const auto& entry : entries) {\n        CategorizedFile file;\n        file.file_path = entry.file_path;\n        file.file_name = entry.file_name;\n        file.type = entry.type;\n        file.category = entry.category;\n        file.subcategory = entry.subcategory;\n        file.rename_only = entry.rename_only;\n        file.suggested_name = entry.suggested_name;\n        file.rename_applied = entry.rename_applied;\n        const auto target_dir = build_suggested_target_dir(file, base_dir_, show_subcategory_column);\n        const std::string dir_key = Utils::path_to_utf8(target_dir);\n        const std::string name_key = to_lower_copy_str(entry.suggested_name);\n        counts[dir_key][name_key] += 1;\n    }\n\n    std::unordered_map<std::string, std::unordered_set<std::string>> used_names;\n    std::unordered_map<std::string, std::unordered_map<std::string, int>> next_index;\n\n    for (auto& entry : entries) {\n        CategorizedFile file;\n        file.file_path = entry.file_path;\n        file.file_name = entry.file_name;\n        file.type = entry.type;\n        file.category = entry.category;\n        file.subcategory = entry.subcategory;\n        file.rename_only = entry.rename_only;\n        file.suggested_name = entry.suggested_name;\n        file.rename_applied = entry.rename_applied;\n        const auto target_dir = build_suggested_target_dir(file, base_dir_, show_subcategory_column);\n        const std::string dir_key = Utils::path_to_utf8(target_dir);\n        const std::string name_key = to_lower_copy_str(entry.suggested_name);\n        const bool force_numbering = counts[dir_key][name_key] > 1;\n        auto& dir_used = used_names[dir_key];\n        auto& dir_next = next_index[dir_key];\n\n        const std::string unique_name = build_unique_suggested_name(entry.suggested_name,\n                                                                    target_dir,\n                                                                    dir_used,\n                                                                    dir_next,\n                                                                    force_numbering);\n        dir_used.insert(to_lower_copy_str(unique_name));\n        if (unique_name != entry.suggested_name) {\n            if (auto* rename_item = model->item(entry.row, ColumnSuggestedName)) {\n                rename_item->setText(QString::fromStdString(unique_name));\n            }\n            entry.suggested_name = unique_name;\n        }\n    }\n}\n\nvoid CategorizationDialog::populate_model()\n{\n    ScopedFlag guard(suppress_item_changed_);\n    model->removeRows(0, model->rowCount());\n\n    const int type_col_width = table_view ? table_view->iconSize().width() + 12 : 28;\n    if (table_view) {\n        table_view->setColumnWidth(2, type_col_width);\n    }\n\n    updating_select_all = true;\n\n    for (const auto& file : categorized_files) {\n        QList<QStandardItem*> row;\n\n        auto* select_item = new QStandardItem;\n        select_item->setCheckable(true);\n        select_item->setCheckState(Qt::Checked);\n        select_item->setEditable(false);\n        select_item->setData(Qt::AlignCenter, Qt::TextAlignmentRole);\n\n        auto* file_item = new QStandardItem(QString::fromStdString(file.file_name));\n        file_item->setEditable(false);\n        file_item->setData(QString::fromStdString(file.file_path), kFilePathRole);\n        file_item->setData(QString::fromStdString(file.file_name), kOriginalFileNameRole);\n        file_item->setData(file.used_consistency_hints, kUsedConsistencyRole);\n        file_item->setData(file.rename_only, kRenameOnlyRole);\n        file_item->setData(static_cast<int>(file.type), kFileTypeRole);\n        const bool rename_locked = file.rename_applied ||\n                                   (!file.suggested_name.empty() &&\n                                    to_lower_copy_str(file.suggested_name) == to_lower_copy_str(file.file_name));\n        file_item->setData(file.rename_applied, kRenameAppliedRole);\n        file_item->setData(rename_locked, kRenameLockedRole);\n\n        const bool is_image_entry = is_supported_image_entry(file.file_path, file.file_name, file.type);\n\n        auto* type_item = new QStandardItem;\n        type_item->setEditable(false);\n        if (file.type == FileType::Directory) {\n            type_item->setData(QStringLiteral(\"D\"), Qt::UserRole);\n        } else if (is_image_entry) {\n            type_item->setData(QStringLiteral(\"I\"), Qt::UserRole);\n        } else {\n            type_item->setData(QStringLiteral(\"F\"), Qt::UserRole);\n        }\n        type_item->setData(Qt::AlignCenter, Qt::TextAlignmentRole);\n        update_type_icon(type_item);\n\n        const std::string suggested_name = rename_locked ? std::string() : file.suggested_name;\n        auto* suggested_item = new QStandardItem(QString::fromStdString(suggested_name));\n        const bool allow_rename = !suggested_name.empty();\n        suggested_item->setEditable(allow_rename);\n        if (allow_rename) {\n            suggested_item->setIcon(edit_icon());\n        }\n\n        std::string category_text = file.category;\n        if (is_image_entry && is_missing_category_label(category_text)) {\n            category_text.clear();\n        }\n        auto* category_item = new QStandardItem(QString::fromStdString(category_text));\n        category_item->setData(QString::fromStdString(category_text), kOriginalCategoryRole);\n        category_item->setData(QString::fromStdString(\n            file.canonical_category.empty() ? file.category : file.canonical_category), kCanonicalCategoryRole);\n        category_item->setEditable(!file.rename_only);\n        if (!file.rename_only) {\n            category_item->setIcon(edit_icon());\n        }\n\n        std::string subcategory_text = file.subcategory;\n        if (is_image_entry && is_missing_category_label(subcategory_text)) {\n            subcategory_text.clear();\n        }\n        auto* subcategory_item = new QStandardItem(QString::fromStdString(subcategory_text));\n        subcategory_item->setData(QString::fromStdString(subcategory_text), kOriginalSubcategoryRole);\n        subcategory_item->setData(QString::fromStdString(\n            file.canonical_subcategory.empty() ? file.subcategory : file.canonical_subcategory), kCanonicalSubcategoryRole);\n        subcategory_item->setEditable(!file.rename_only);\n        if (!file.rename_only) {\n            subcategory_item->setIcon(edit_icon());\n        }\n\n        auto* status_item = new QStandardItem;\n        status_item->setEditable(false);\n        status_item->setData(static_cast<int>(RowStatus::None), kStatusRole);\n        apply_status_text(status_item);\n        status_item->setForeground(QBrush());\n\n        auto* preview_item = new QStandardItem;\n        preview_item->setEditable(false);\n\n        row << select_item\n            << file_item\n            << type_item\n            << suggested_item\n            << category_item\n            << subcategory_item\n            << status_item\n            << preview_item;\n        model->appendRow(row);\n        update_preview_column(model->rowCount() - 1);\n    }\n\n    updating_select_all = false;\n    apply_subcategory_visibility();\n    apply_rename_visibility();\n    table_view->resizeColumnsToContents();\n    update_select_all_state();\n}\n\nvoid CategorizationDialog::update_type_icon(QStandardItem* item)\n{\n    if (!item) {\n        return;\n    }\n\n    const QString code = item->data(Qt::UserRole).toString();\n    QString full_path;\n    if (code == QStringLiteral(\"I\") && model) {\n        if (auto* file_item = model->item(item->row(), ColumnFile)) {\n            const QString file_name = file_item->text();\n            const QString base_dir = file_item->data(kFilePathRole).toString();\n            if (!base_dir.isEmpty()) {\n                full_path = QDir(base_dir).filePath(file_name);\n            } else if (!base_dir_.empty()) {\n                full_path = QDir(QString::fromStdString(base_dir_)).filePath(file_name);\n            } else {\n                full_path = file_name;\n            }\n        }\n    }\n    item->setIcon(type_icon(code, full_path));\n    item->setText(QString());\n}\n\n\nvoid CategorizationDialog::record_categorization_to_db()\n{\n    if (!db_manager) {\n        return;\n    }\n\n    auto entry_is_unchanged = [](const CategorizedFile& cached,\n                                 const DatabaseManager::ResolvedCategory& resolved,\n                                 const std::string& suggested_name,\n                                 bool rename_only,\n                                 bool used_consistency) {\n        if (cached.rename_only != rename_only) {\n            return false;\n        }\n        if (cached.suggested_name != suggested_name) {\n            return false;\n        }\n        if (cached.used_consistency_hints != used_consistency) {\n            return false;\n        }\n        if (cached.category != resolved.category || cached.subcategory != resolved.subcategory) {\n            return false;\n        }\n        if (!resolved.category.empty() && cached.taxonomy_id != resolved.taxonomy_id) {\n            return false;\n        }\n        return true;\n    };\n    auto read_role_text = [](QStandardItem* item, int role) {\n        return item && item->data(role).isValid()\n            ? item->data(role).toString().toStdString()\n            : std::string();\n    };\n    auto update_category_roles = [](QStandardItem* item,\n                                    const std::string& display_value,\n                                    const std::string& canonical_value,\n                                    int original_role,\n                                    int canonical_role) {\n        if (!item) {\n            return;\n        }\n        item->setText(QString::fromStdString(display_value));\n        item->setData(QString::fromStdString(display_value), original_role);\n        item->setData(QString::fromStdString(canonical_value), canonical_role);\n    };\n    auto resolve_for_storage = [this, &read_role_text](QStandardItem* category_item,\n                                                       QStandardItem* subcategory_item,\n                                                       const std::string& category,\n                                                       const std::string& subcategory) {\n        const std::string original_category = read_role_text(category_item, kOriginalCategoryRole);\n        const std::string original_subcategory = read_role_text(subcategory_item, kOriginalSubcategoryRole);\n        const std::string canonical_category = read_role_text(category_item, kCanonicalCategoryRole);\n        const std::string canonical_subcategory = read_role_text(subcategory_item, kCanonicalSubcategoryRole);\n        const bool unchanged_display =\n            category == original_category &&\n            subcategory == original_subcategory &&\n            !canonical_category.empty();\n        if (unchanged_display) {\n            return db_manager->resolve_category(canonical_category, canonical_subcategory);\n        }\n        return db_manager->resolve_category_for_language(category,\n                                                        subcategory,\n                                                        category_language_);\n    };\n\n    for (int row = 0; row < model->rowCount(); ++row) {\n        auto* file_item = model->item(row, ColumnFile);\n        if (!file_item) {\n            continue;\n        }\n        bool rename_only = file_item->data(kRenameOnlyRole).toBool();\n        auto* category_item = model->item(row, ColumnCategory);\n        auto* subcategory_item = model->item(row, ColumnSubcategory);\n        std::string category = category_item ? category_item->text().toStdString() : std::string();\n        std::string subcategory = show_subcategory_column && subcategory_item\n                                      ? subcategory_item->text().toStdString()\n                                      : std::string();\n        const bool is_image = row_is_supported_image(row);\n        const bool is_document = row_is_supported_document(row);\n        if (is_image || is_document) {\n            if (is_missing_category_label(category)) {\n                category.clear();\n            }\n            if (is_missing_category_label(subcategory)) {\n                subcategory.clear();\n            }\n        }\n        if (!rename_only && (is_image || is_document) && category.empty()) {\n            rename_only = true;\n        }\n        const auto* suggested_item = model->item(row, ColumnSuggestedName);\n        const std::string suggested_name = suggested_item\n                                               ? suggested_item->text().toStdString()\n                                               : std::string();\n\n        const std::string file_name = file_item->text().toStdString();\n        const std::string file_path = file_item->data(kFilePathRole).toString().toStdString();\n        const bool used_consistency = file_item->data(kUsedConsistencyRole).toBool();\n        const FileType file_type = static_cast<FileType>(file_item->data(kFileTypeRole).toInt());\n        const auto cached_entry = db_manager->get_categorized_file(file_path, file_name, file_type);\n        if (rename_only) {\n            if (cached_entry) {\n                const auto localized_cached = db_manager->localize_categorized_file(*cached_entry, category_language_);\n                category = localized_cached.category;\n                subcategory = localized_cached.subcategory;\n            } else {\n                category.clear();\n                subcategory.clear();\n            }\n            if (is_missing_category_label(category)) {\n                category.clear();\n            }\n            if (is_missing_category_label(subcategory)) {\n                subcategory.clear();\n            }\n            if (category_item) {\n                category_item->setText(QString::fromStdString(category));\n            }\n            if (show_subcategory_column && subcategory_item) {\n                subcategory_item->setText(QString::fromStdString(subcategory));\n            }\n            if (cached_entry) {\n                update_category_roles(category_item,\n                                      category,\n                                      cached_entry->category,\n                                      kOriginalCategoryRole,\n                                      kCanonicalCategoryRole);\n                update_category_roles(subcategory_item,\n                                      subcategory,\n                                      cached_entry->subcategory,\n                                      kOriginalSubcategoryRole,\n                                      kCanonicalSubcategoryRole);\n            }\n        }\n        if (rename_only) {\n            DatabaseManager::ResolvedCategory resolved{0, \"\", \"\"};\n            if (cached_entry && !cached_entry->category.empty()) {\n                resolved.taxonomy_id = cached_entry->taxonomy_id;\n                resolved.category = cached_entry->category;\n                resolved.subcategory = cached_entry->subcategory;\n            }\n            const std::string file_type_label = (file_type == FileType::Directory) ? \"D\" : \"F\";\n            if (cached_entry &&\n                entry_is_unchanged(*cached_entry, resolved, suggested_name, rename_only, used_consistency)) {\n                continue;\n            }\n            db_manager->insert_or_update_file_with_categorization(\n                file_name, file_type_label, file_path, resolved, used_consistency, suggested_name, true);\n            continue;\n        }\n\n        if (!category_item) {\n            continue;\n        }\n\n        auto resolved = resolve_for_storage(category_item, subcategory_item, category, subcategory);\n\n        const std::string file_type_label = (file_type == FileType::Directory) ? \"D\" : \"F\";\n        if (cached_entry &&\n            entry_is_unchanged(*cached_entry, resolved, suggested_name, rename_only, used_consistency)) {\n            continue;\n        }\n        db_manager->insert_or_update_file_with_categorization(\n            file_name, file_type_label, file_path, resolved, used_consistency, suggested_name);\n\n        const auto display_resolved = db_manager->localize_category(resolved, category_language_);\n        update_category_roles(category_item,\n                              display_resolved.category,\n                              resolved.category,\n                              kOriginalCategoryRole,\n                              kCanonicalCategoryRole);\n        if (show_subcategory_column) {\n            update_category_roles(subcategory_item,\n                                  display_resolved.subcategory,\n                                  resolved.subcategory,\n                                  kOriginalSubcategoryRole,\n                                  kCanonicalSubcategoryRole);\n        }\n    }\n}\n\n\nvoid CategorizationDialog::on_confirm_and_sort_button_clicked()\n{\n    record_categorization_to_db();\n\n    if (categorized_files.empty()) {\n        if (ui_logger) {\n            ui_logger->warn(\"No categorized files available for sorting.\");\n        }\n        return;\n    }\n\n    const std::string base_dir = base_dir_.empty()\n        ? categorized_files.front().file_path\n        : base_dir_;\n    dry_run_plan_.clear();\n    clear_move_history();\n    if (undo_button) {\n        undo_button->setEnabled(false);\n        undo_button->setVisible(false);\n    }\n\n    const bool dry_run = dry_run_checkbox && dry_run_checkbox->isChecked();\n    if (dry_run && core_logger) {\n        core_logger->info(\"Dry run enabled; will not move files.\");\n    }\n\n    std::vector<std::string> files_not_moved;\n    ScopedFlag guard(suppress_item_changed_);\n    if (include_subdirectories_) {\n        struct CollisionState {\n            std::unordered_set<std::string> used_names;\n            std::unordered_map<std::string, int> next_index;\n        };\n        std::unordered_map<std::string, CollisionState> collisions;\n        collisions.reserve(static_cast<size_t>(model->rowCount()));\n\n        for (int row_index = 0; row_index < model->rowCount(); ++row_index) {\n            auto* select_item = model->item(row_index, ColumnSelect);\n            if (select_item && select_item->checkState() != Qt::Checked) {\n                continue;\n            }\n            auto* file_item = model->item(row_index, ColumnFile);\n            auto* category_item = model->item(row_index, ColumnCategory);\n            auto* subcategory_item = model->item(row_index, ColumnSubcategory);\n            auto* rename_item = model->item(row_index, ColumnSuggestedName);\n            if (!file_item || !category_item) {\n                continue;\n            }\n\n            bool rename_only = false;\n            bool used_consistency_hints = false;\n            FileType file_type = FileType::File;\n            if (!resolve_row_flags(row_index, rename_only, used_consistency_hints, file_type)) {\n                continue;\n            }\n            (void)used_consistency_hints;\n            if (rename_only) {\n                continue;\n            }\n\n            std::string category = category_item->text().toStdString();\n            if (is_missing_category_label(category)) {\n                continue;\n            }\n            std::string subcategory = show_subcategory_column && subcategory_item\n                ? subcategory_item->text().toStdString()\n                : std::string();\n            if (is_missing_category_label(subcategory)) {\n                subcategory.clear();\n            }\n\n            const std::string file_name = file_item->text().toStdString();\n            const std::string rename_candidate = rename_item\n                                                     ? rename_item->text().toStdString()\n                                                     : std::string();\n            std::string source_dir = file_item->data(kFilePathRole).toString().toStdString();\n            if (source_dir.empty()) {\n                source_dir = base_dir;\n            }\n\n            CategorizedFile file;\n            file.file_path = source_dir;\n            file.file_name = file_name;\n            file.type = file_type;\n            file.category = category;\n            file.subcategory = subcategory;\n            file.rename_only = false;\n\n            const auto target_dir = build_suggested_target_dir(file, base_dir, show_subcategory_column);\n            const std::string dir_key = Utils::path_to_utf8(target_dir);\n            auto& state = collisions[dir_key];\n            const std::string desired_name = resolve_destination_name(file_name, rename_candidate);\n            const std::string unique_name = build_unique_move_name(desired_name,\n                                                                   target_dir,\n                                                                   state.used_names,\n                                                                   state.next_index);\n            state.used_names.insert(to_lower_copy_str(unique_name));\n            if (unique_name != desired_name) {\n                if (rename_item) {\n                    rename_item->setText(QString::fromStdString(unique_name));\n                }\n                update_preview_column(row_index);\n            }\n        }\n    }\n\n    for (int row_index = 0; row_index < model->rowCount(); ++row_index) {\n        auto* select_item = model->item(row_index, ColumnSelect);\n        if (select_item && select_item->checkState() != Qt::Checked) {\n            update_status_column(row_index, false, false);\n            continue;\n        }\n\n        auto* file_item = model->item(row_index, ColumnFile);\n        auto* category_item = model->item(row_index, ColumnCategory);\n        auto* subcategory_item = model->item(row_index, ColumnSubcategory);\n        auto* rename_item = model->item(row_index, ColumnSuggestedName);\n        if (!file_item || !category_item) {\n            update_status_column(row_index, false);\n            continue;\n        }\n\n        bool rename_only = false;\n        bool used_consistency_hints = false;\n        FileType file_type = FileType::File;\n        if (!resolve_row_flags(row_index, rename_only, used_consistency_hints, file_type)) {\n            update_status_column(row_index, false);\n            continue;\n        }\n\n        const std::string file_name = file_item->text().toStdString();\n        const std::string category = category_item->text().toStdString();\n        const std::string subcategory = show_subcategory_column && subcategory_item\n                                            ? subcategory_item->text().toStdString()\n                                            : std::string();\n        const std::string rename_candidate = rename_item\n                                                 ? rename_item->text().toStdString()\n                                                 : std::string();\n        std::string source_dir = file_item->data(kFilePathRole).toString().toStdString();\n        if (source_dir.empty()) {\n            source_dir = base_dir;\n        }\n\n        handle_selected_row(row_index,\n                            file_name,\n                            rename_candidate,\n                            category,\n                            subcategory,\n                            source_dir,\n                            base_dir,\n                            files_not_moved,\n                            file_type,\n                            rename_only,\n                            used_consistency_hints,\n                            dry_run);\n    }\n\n    if (files_not_moved.empty()) {\n        if (core_logger) {\n            core_logger->info(\"All files have been sorted and moved successfully.\");\n        }\n    } else if (ui_logger) {\n        ui_logger->info(\"Categorization complete. Unmoved files: {}\", files_not_moved.size());\n    }\n\n    if (dry_run) {\n        // Show preview dialog of planned moves.\n        std::vector<DryRunPreviewDialog::Entry> entries;\n        entries.reserve(static_cast<size_t>(model->rowCount()));\n        for (int row = 0; row < model->rowCount(); ++row) {\n            if (auto* select_item = model->item(row, ColumnSelect)) {\n                if (select_item->checkState() != Qt::Checked) {\n                    continue;\n                }\n            }\n            const auto* file_item = model->item(row, ColumnFile);\n            const auto* cat_item = model->item(row, ColumnCategory);\n            if (!file_item || !cat_item) {\n                continue;\n            }\n            std::string debug_reason;\n            auto rec = build_preview_record_for_row(row, &debug_reason);\n            if (!rec) {\n                if (core_logger) {\n                    core_logger->warn(\"Dry run preview skipped row {}: {}\", row, debug_reason);\n                }\n                continue;\n            }\n            const bool rename_images_only_active = rename_images_only_checkbox &&\n                                                   rename_images_only_checkbox->isChecked() &&\n                                                   row_is_supported_image(row);\n            std::string to_label;\n            std::string destination;\n#ifdef _WIN32\n            const char sep = '\\\\\\\\';\n#else\n            const char sep = '/';\n#endif\n            if (rename_images_only_active) {\n                to_label = rec->destination_file_name;\n                if (!base_dir.empty()) {\n                    destination = Utils::path_to_utf8(\n                        Utils::utf8_to_path(base_dir) / Utils::utf8_to_path(rec->destination_file_name));\n                } else {\n                    destination = rec->destination;\n                }\n            } else if (rec->rename_only) {\n                to_label = rec->destination_file_name;\n                destination = rec->destination;\n            } else {\n                to_label = rec->category;\n                if (rec->use_subcategory && !rec->subcategory.empty()) {\n                    to_label += std::string(1, sep) + rec->subcategory;\n                }\n                to_label += std::string(1, sep) + rec->destination_file_name;\n                destination = rec->destination;\n            }\n#ifdef _WIN32\n            std::replace(destination.begin(), destination.end(), '/', '\\\\');\n#endif\n            std::string source_tooltip = rec->source;\n#ifdef _WIN32\n            std::replace(source_tooltip.begin(), source_tooltip.end(), '/', '\\\\');\n#endif\n\n            entries.push_back(DryRunPreviewDialog::Entry{\n                /*from_label*/ rec->source_file_name,\n                /*to_label*/ to_label,\n                /*source_tooltip*/ source_tooltip,\n                /*destination_tooltip*/ destination});\n        }\n        if (core_logger) {\n            core_logger->info(\"Dry run preview entries built: {}\", entries.size());\n        }\n        DryRunPreviewDialog preview_dialog(entries, this);\n        preview_dialog.exec();\n\n        // In preview mode, keep the dialog actionable so the user can uncheck Dry run and re-run.\n        if (undo_button) {\n            undo_button->setVisible(false);\n            undo_button->setEnabled(false);\n        }\n        restore_action_buttons();\n        return;\n    }\n\n    if (!move_history_.empty() && undo_button) {\n        undo_button->setVisible(true);\n        undo_button->setEnabled(true);\n    }\n\n    if (!move_history_.empty()) {\n        persist_move_plan();\n    }\n\n    show_close_button();\n}\n\nvoid CategorizationDialog::handle_selected_row(int row_index,\n                                               const std::string& file_name,\n                                               const std::string& rename_candidate,\n                                               const std::string& category,\n                                               const std::string& subcategory,\n                                               const std::string& source_dir,\n                                               const std::string& base_dir,\n                                               std::vector<std::string>& files_not_moved,\n                                               FileType file_type,\n                                               bool rename_only,\n                                               bool used_consistency_hints,\n                                               bool dry_run)\n{\n    const std::string destination_name = resolve_destination_name(file_name, rename_candidate);\n    const bool rename_active = destination_name != file_name;\n    auto* category_item_ref = model ? model->item(row_index, ColumnCategory) : nullptr;\n    auto* subcategory_item_ref = model ? model->item(row_index, ColumnSubcategory) : nullptr;\n    auto read_role_text = [](QStandardItem* item, int role) {\n        return item && item->data(role).isValid()\n            ? item->data(role).toString().toStdString()\n            : std::string();\n    };\n    auto apply_successful_rename = [this, row_index, &destination_name]() {\n        if (!model) {\n            return;\n        }\n        if (auto* file_item = model->item(row_index, ColumnFile)) {\n            if (!file_item->data(kOriginalFileNameRole).isValid()) {\n                file_item->setData(file_item->text(), kOriginalFileNameRole);\n            }\n            file_item->setData(true, kRenameAppliedRole);\n            file_item->setData(true, kRenameLockedRole);\n        }\n        if (auto* rename_item = model->item(row_index, ColumnSuggestedName)) {\n            rename_item->setText(QString::fromStdString(destination_name));\n        }\n        update_preview_column(row_index);\n    };\n\n    if (auto& probe = move_probe_slot()) {\n        const std::string effective_subcategory = subcategory.empty() ? category : subcategory;\n        probe(TestHooks::CategorizationMoveInfo{\n            show_subcategory_column,\n            category,\n            effective_subcategory,\n            file_name\n        });\n        update_status_column(row_index, true, true, rename_active, !rename_only);\n        return;\n    }\n\n    if (rename_active) {\n        std::string rename_error;\n        if (!validate_filename(destination_name, rename_error)) {\n            update_status_column(row_index, false);\n            files_not_moved.push_back(file_name);\n            if (core_logger) {\n                core_logger->warn(\"Skipping rename for '{}' due to invalid filename: {} (rename='{}')\",\n                                  file_name,\n                                  rename_error,\n                                  destination_name);\n            }\n            return;\n        }\n    }\n\n    if (rename_only) {\n        if (!rename_active) {\n            update_status_column(row_index, true, true, false, false);\n            return;\n        }\n\n        const auto source_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(file_name);\n        const auto dest_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(destination_name);\n\n        if (dry_run) {\n            const std::string source_display = Utils::path_to_utf8(source_path);\n            const std::string dest_display = Utils::path_to_utf8(dest_path);\n            set_preview_status(row_index, dest_display);\n            dry_run_plan_.push_back(PreviewRecord{\n                source_display,\n                dest_display,\n                file_name,\n                destination_name,\n                std::string(),\n                std::string(),\n                false,\n                true});\n            if (core_logger) {\n                core_logger->info(\"Dry run: would rename '{}' to '{}'\",\n                                  source_display,\n                                  dest_display);\n            }\n            return;\n        }\n\n        if (!std::filesystem::exists(source_path)) {\n            update_status_column(row_index, false);\n            files_not_moved.push_back(file_name);\n            if (core_logger) {\n                core_logger->warn(\"Source file missing when renaming '{}'\", file_name);\n            }\n            return;\n        }\n        if (std::filesystem::exists(dest_path)) {\n            update_status_column(row_index, false);\n            files_not_moved.push_back(file_name);\n            if (core_logger) {\n                core_logger->warn(\"Destination already exists for rename '{}'\", destination_name);\n            }\n            return;\n        }\n\n        try {\n            std::filesystem::rename(source_path, dest_path);\n            update_status_column(row_index, true, true, rename_active, false);\n\n            std::error_code ec;\n            const std::uintmax_t size_bytes = std::filesystem::file_size(dest_path, ec);\n            std::time_t mtime_value = 0;\n            if (!ec) {\n                const auto ftime = std::filesystem::last_write_time(dest_path, ec);\n                if (!ec) {\n                    const auto sys = to_system_clock(ftime);\n                    mtime_value = std::chrono::system_clock::to_time_t(sys);\n                }\n            }\n            record_move_for_undo(row_index,\n                                 Utils::path_to_utf8(source_path),\n                                 Utils::path_to_utf8(dest_path),\n                                 size_bytes,\n                                 mtime_value);\n            if (db_manager) {\n                DatabaseManager::ResolvedCategory resolved{0, \"\", \"\"};\n                if (auto cached = db_manager->get_categorized_file(source_dir, file_name, file_type)) {\n                    if (!is_missing_category_label(cached->category)) {\n                        resolved.category = cached->category;\n                        if (!is_missing_category_label(cached->subcategory)) {\n                            resolved.subcategory = cached->subcategory;\n                        }\n                        resolved.taxonomy_id = cached->taxonomy_id;\n                    }\n                }\n                const std::string file_type_label = (file_type == FileType::Directory) ? \"D\" : \"F\";\n                db_manager->remove_file_categorization(source_dir, file_name, file_type);\n                db_manager->insert_or_update_file_with_categorization(\n                    destination_name,\n                    file_type_label,\n                    source_dir,\n                    resolved,\n                    used_consistency_hints,\n                    destination_name,\n                    true,\n                    true);\n            }\n            apply_successful_rename();\n        } catch (const std::exception& ex) {\n            update_status_column(row_index, false);\n            files_not_moved.push_back(file_name);\n            if (core_logger) {\n                core_logger->error(\"Failed to rename '{}': {}\", file_name, ex.what());\n            }\n        }\n        return;\n    }\n\n    const std::string effective_subcategory = subcategory.empty() ? category : subcategory;\n    std::string validation_error;\n    const bool allow_identical = !show_subcategory_column;\n    if (!validate_labels(category, effective_subcategory, validation_error, allow_identical)) {\n        update_status_column(row_index, false);\n        files_not_moved.push_back(file_name);\n        if (core_logger) {\n            core_logger->warn(\"Skipping move for '{}' due to invalid category/subcategory: {} (cat='{}', sub='{}')\",\n                              file_name,\n                              validation_error,\n                              category,\n                              effective_subcategory);\n        }\n        return;\n    }\n\n    try {\n        MovableCategorizedFile categorized_file(\n            source_dir, base_dir, category, effective_subcategory, file_name, destination_name);\n\n        const auto preview_paths = categorized_file.preview_move_paths(show_subcategory_column);\n\n        if (dry_run) {\n            set_preview_status(row_index, preview_paths.destination);\n            dry_run_plan_.push_back(PreviewRecord{\n                preview_paths.source,\n                preview_paths.destination,\n                file_name,\n                destination_name,\n                category,\n                effective_subcategory,\n                show_subcategory_column,\n                false});\n            if (core_logger) {\n                core_logger->info(\"Dry run: would move '{}' to '{}'\",\n                                  preview_paths.source,\n                                  preview_paths.destination);\n            }\n            return;\n        }\n\n        categorized_file.create_cat_dirs(show_subcategory_column);\n        bool moved = categorized_file.move_file(show_subcategory_column);\n        update_status_column(row_index, moved, true, rename_active && moved, moved);\n\n        if (!moved) {\n            files_not_moved.push_back(file_name);\n            if (core_logger) {\n                core_logger->warn(\"File {} already exists in the destination.\", file_name);\n            }\n        } else {\n            std::error_code ec;\n            const std::uintmax_t size_bytes = std::filesystem::file_size(Utils::utf8_to_path(preview_paths.destination), ec);\n            std::time_t mtime_value = 0;\n            if (!ec) {\n                const auto ftime = std::filesystem::last_write_time(Utils::utf8_to_path(preview_paths.destination), ec);\n                if (!ec) {\n                    const auto sys = to_system_clock(ftime);\n                    mtime_value = std::chrono::system_clock::to_time_t(sys);\n                }\n            }\n            record_move_for_undo(row_index, preview_paths.source, preview_paths.destination, size_bytes, mtime_value);\n\n            if (db_manager && (rename_active || include_subdirectories_)) {\n                const std::string original_category = read_role_text(category_item_ref, kOriginalCategoryRole);\n                const std::string original_subcategory = read_role_text(subcategory_item_ref, kOriginalSubcategoryRole);\n                const std::string canonical_category = read_role_text(category_item_ref, kCanonicalCategoryRole);\n                const std::string canonical_subcategory = read_role_text(subcategory_item_ref, kCanonicalSubcategoryRole);\n                const std::string original_effective_subcategory =\n                    original_subcategory.empty() ? original_category : original_subcategory;\n                const bool unchanged_display =\n                    category == original_category &&\n                    effective_subcategory == original_effective_subcategory &&\n                    !canonical_category.empty();\n                auto resolved = unchanged_display\n                    ? db_manager->resolve_category(canonical_category, canonical_subcategory)\n                    : db_manager->resolve_category_for_language(category,\n                                                                effective_subcategory,\n                                                                category_language_);\n                const std::string source_db_dir = include_subdirectories_ ? source_dir : base_dir;\n                std::string destination_db_dir = base_dir;\n                if (include_subdirectories_) {\n                    const auto dest_parent = Utils::utf8_to_path(preview_paths.destination).parent_path();\n                    destination_db_dir = Utils::path_to_utf8(dest_parent);\n                }\n                std::string suggested_name;\n                bool rename_applied = rename_active;\n                if (rename_active) {\n                    suggested_name = destination_name;\n                } else if (auto cached = db_manager->get_categorized_file(source_db_dir, file_name, file_type)) {\n                    suggested_name = cached->suggested_name;\n                    rename_applied = cached->rename_applied;\n                }\n                db_manager->remove_file_categorization(source_db_dir, file_name, file_type);\n                db_manager->insert_or_update_file_with_categorization(\n                    destination_name,\n                    file_type == FileType::Directory ? \"D\" : \"F\",\n                    destination_db_dir,\n                    resolved,\n                    used_consistency_hints,\n                    suggested_name,\n                    false,\n                    rename_applied);\n            }\n            if (rename_active) {\n                apply_successful_rename();\n            }\n        }\n    } catch (const std::exception& ex) {\n        update_status_column(row_index, false);\n        files_not_moved.push_back(file_name);\n        if (core_logger) {\n            core_logger->error(\"Failed to move '{}': {}\", file_name, ex.what());\n        }\n    }\n}\n\n\nvoid CategorizationDialog::on_continue_later_button_clicked()\n{\n    record_categorization_to_db();\n    accept();\n}\n\nvoid CategorizationDialog::on_undo_button_clicked()\n{\n    if (!undo_move_history()) {\n        return;\n    }\n\n    update_status_after_undo();\n    restore_action_buttons();\n    clear_move_history();\n    if (undo_button) {\n        undo_button->setEnabled(false);\n        undo_button->setVisible(false);\n    }\n}\n\n\nvoid CategorizationDialog::show_close_button()\n{\n    if (confirm_button) {\n        confirm_button->setVisible(false);\n    }\n    if (continue_button) {\n        continue_button->setVisible(false);\n    }\n    if (close_button) {\n        close_button->setVisible(true);\n    }\n}\n\nvoid CategorizationDialog::restore_action_buttons()\n{\n    if (confirm_button) {\n        confirm_button->setVisible(true);\n    }\n    if (continue_button) {\n        continue_button->setVisible(true);\n    }\n    if (close_button) {\n        close_button->setVisible(false);\n    }\n}\n\n\nvoid CategorizationDialog::update_status_column(int row,\n                                                bool success,\n                                                bool attempted,\n                                                bool renamed,\n                                                bool moved)\n{\n    if (auto* status_item = model->item(row, ColumnStatus)) {\n        RowStatus status = RowStatus::None;\n        if (!attempted) {\n            status = RowStatus::NotSelected;\n            status_item->setForeground(QBrush(Qt::gray));\n        } else if (success) {\n            if (renamed && moved) {\n                status = RowStatus::RenamedAndMoved;\n            } else if (renamed) {\n                status = RowStatus::Renamed;\n            } else {\n                status = RowStatus::Moved;\n            }\n            status_item->setForeground(QBrush(Qt::darkGreen));\n        } else {\n            status = RowStatus::Skipped;\n            status_item->setForeground(QBrush(Qt::red));\n        }\n\n        if (status == RowStatus::None) {\n            status_item->setForeground(QBrush());\n        }\n\n        status_item->setData(static_cast<int>(status), kStatusRole);\n        apply_status_text(status_item);\n    }\n}\n\n\nvoid CategorizationDialog::on_select_all_toggled(bool checked)\n{\n    apply_select_all(checked);\n}\n\nstd::vector<int> CategorizationDialog::selected_row_indices() const\n{\n    std::vector<int> rows;\n    if (!table_view || !table_view->selectionModel()) {\n        return rows;\n    }\n\n    const QModelIndexList selected = table_view->selectionModel()->selectedRows();\n    rows.reserve(selected.size());\n    for (const auto& index : selected) {\n        rows.push_back(index.row());\n    }\n    std::sort(rows.begin(), rows.end());\n    rows.erase(std::unique(rows.begin(), rows.end()), rows.end());\n    return rows;\n}\n\nvoid CategorizationDialog::on_select_highlighted_clicked()\n{\n    const auto rows = selected_row_indices();\n    if (rows.empty()) {\n        QMessageBox::information(this,\n                                 tr(\"No items selected\"),\n                                 tr(\"Highlight one or more rows to select them for processing.\"));\n        return;\n    }\n    apply_check_state_to_rows(rows, Qt::Checked);\n}\n\nvoid CategorizationDialog::record_move_for_undo(int row,\n                                                const std::string& source,\n                                                const std::string& destination,\n                                                std::uintmax_t size_bytes,\n                                                std::time_t mtime)\n{\n    move_history_.push_back(MoveRecord{row, source, destination, size_bytes, mtime});\n}\n\nvoid CategorizationDialog::remove_empty_parent_directories(const std::string& destination)\n{\n    std::filesystem::path dest_path = Utils::utf8_to_path(destination);\n    auto parent = dest_path.parent_path();\n    while (!parent.empty()) {\n        std::error_code ec;\n        if (!std::filesystem::exists(parent)) {\n            parent = parent.parent_path();\n            continue;\n        }\n        if (std::filesystem::is_directory(parent) &&\n            std::filesystem::is_empty(parent, ec) && !ec) {\n            std::filesystem::remove(parent, ec);\n            parent = parent.parent_path();\n        } else {\n            break;\n        }\n    }\n}\n\nbool CategorizationDialog::move_file_back(const std::string& source, const std::string& destination)\n{\n    std::error_code ec;\n    auto destination_path = Utils::utf8_to_path(destination);\n    auto source_path = Utils::utf8_to_path(source);\n\n    if (!std::filesystem::exists(destination_path)) {\n        if (core_logger) {\n            core_logger->warn(\"Undo skipped; destination '{}' missing\", destination);\n        }\n        return false;\n    }\n\n    std::filesystem::create_directories(source_path.parent_path(), ec);\n\n    try {\n        std::filesystem::rename(destination_path, source_path);\n    } catch (const std::filesystem::filesystem_error& ex) {\n        if (core_logger) {\n            core_logger->error(\"Undo move failed '{}' -> '{}': {}\", destination, source, ex.what());\n        }\n        return false;\n    }\n\n    remove_empty_parent_directories(destination);\n    return true;\n}\n\nbool CategorizationDialog::undo_move_history()\n{\n    if (move_history_.empty()) {\n    return false;\n    }\n\n    bool any_success = false;\n    for (auto it = move_history_.rbegin(); it != move_history_.rend(); ++it) {\n        if (move_file_back(it->source_path, it->destination_path)) {\n            any_success = true;\n        }\n    }\n\n    if (any_success && core_logger) {\n        core_logger->info(\"Undo completed for {} moved file(s)\", move_history_.size());\n    }\n\n    return any_success;\n}\n\nvoid CategorizationDialog::update_status_after_undo()\n{\n    ScopedFlag guard(suppress_item_changed_);\n    for (const auto& record : move_history_) {\n        update_status_column(record.row_index, false, false);\n        if (!model) {\n            continue;\n        }\n        auto* file_item = model->item(record.row_index, ColumnFile);\n        if (!file_item) {\n            continue;\n        }\n        const auto source_path = Utils::utf8_to_path(record.source_path);\n        const std::string source_name = Utils::path_to_utf8(source_path.filename());\n        if (!source_name.empty() && file_item->text().toStdString() != source_name) {\n            file_item->setText(QString::fromStdString(source_name));\n        }\n        update_preview_column(record.row_index);\n    }\n}\n\n\nvoid CategorizationDialog::apply_select_all(bool checked)\n{\n    updating_select_all = true;\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (auto* item = model->item(row, ColumnSelect)) {\n            item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);\n        }\n        update_preview_column(row);\n    }\n    updating_select_all = false;\n    update_select_all_state();\n}\n\nvoid CategorizationDialog::apply_check_state_to_rows(const std::vector<int>& rows, Qt::CheckState state)\n{\n    if (!model) {\n        return;\n    }\n    updating_select_all = true;\n    for (int row : rows) {\n        if (row < 0 || row >= model->rowCount()) {\n            continue;\n        }\n        if (auto* item = model->item(row, ColumnSelect)) {\n            item->setCheckState(state);\n        }\n        update_preview_column(row);\n    }\n    updating_select_all = false;\n    update_select_all_state();\n}\n\nvoid CategorizationDialog::on_bulk_edit_clicked()\n{\n    if (!model || !table_view) {\n        return;\n    }\n    if (table_view->isColumnHidden(ColumnCategory)) {\n        QMessageBox::information(this,\n                                 tr(\"Bulk edit unavailable\"),\n                                 tr(\"Bulk editing categories is unavailable while picture rename-only mode is active.\"));\n        return;\n    }\n    const auto rows = selected_row_indices();\n    if (rows.empty()) {\n        QMessageBox::information(this,\n                                 tr(\"No items selected\"),\n                                 tr(\"Highlight one or more rows to edit their categories.\"));\n        return;\n    }\n\n    const bool allow_subcategory = !table_view->isColumnHidden(ColumnSubcategory);\n    BulkEditDialog dialog(allow_subcategory, this);\n    if (dialog.exec() != QDialog::Accepted) {\n        return;\n    }\n\n    const std::string category = dialog.category();\n    const std::string subcategory = dialog.subcategory();\n    if (category.empty() && subcategory.empty()) {\n        return;\n    }\n\n    for (int row : rows) {\n        bool rename_only = false;\n        bool used_consistency_hints = false;\n        FileType file_type = FileType::File;\n        if (!resolve_row_flags(row, rename_only, used_consistency_hints, file_type)) {\n            continue;\n        }\n        if (rename_only) {\n            continue;\n        }\n        if (!category.empty()) {\n            if (auto* category_item = model->item(row, ColumnCategory)) {\n                category_item->setText(QString::fromStdString(category));\n            }\n        }\n        if (allow_subcategory && !subcategory.empty()) {\n            if (auto* subcategory_item = model->item(row, ColumnSubcategory)) {\n                subcategory_item->setText(QString::fromStdString(subcategory));\n            }\n        }\n    }\n}\n\nvoid CategorizationDialog::on_show_subcategories_toggled(bool checked)\n{\n    show_subcategory_column = checked;\n    apply_subcategory_visibility();\n    apply_rename_only_row_visibility();\n    for (int row = 0; row < model->rowCount(); ++row) {\n        update_preview_column(row);\n    }\n}\n\nvoid CategorizationDialog::on_rename_images_only_toggled(bool checked)\n{\n    if (!model) {\n        return;\n    }\n\n    ScopedFlag guard(suppress_item_changed_);\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (!row_is_supported_image(row)) {\n            continue;\n        }\n        auto* file_item = model->item(row, ColumnFile);\n        if (!file_item) {\n            continue;\n        }\n        file_item->setData(checked, kRenameOnlyRole);\n\n        if (auto* category_item = model->item(row, ColumnCategory)) {\n            category_item->setEditable(!checked);\n            category_item->setIcon(checked ? QIcon() : edit_icon());\n        }\n        if (auto* subcategory_item = model->item(row, ColumnSubcategory)) {\n            subcategory_item->setEditable(!checked);\n            subcategory_item->setIcon(checked ? QIcon() : edit_icon());\n        }\n    }\n\n    ensure_unique_suggested_names_in_model();\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (!row_is_supported_image(row)) {\n            continue;\n        }\n        update_preview_column(row);\n    }\n\n    dry_run_plan_.clear();\n    apply_category_visibility();\n    apply_subcategory_visibility();\n    apply_rename_only_row_visibility();\n    update_subcategory_checkbox_state();\n}\n\nvoid CategorizationDialog::on_rename_documents_only_toggled(bool checked)\n{\n    if (!model) {\n        return;\n    }\n\n    ScopedFlag guard(suppress_item_changed_);\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (!row_is_supported_document(row)) {\n            continue;\n        }\n        auto* file_item = model->item(row, ColumnFile);\n        if (!file_item) {\n            continue;\n        }\n        file_item->setData(checked, kRenameOnlyRole);\n\n        if (auto* category_item = model->item(row, ColumnCategory)) {\n            category_item->setEditable(!checked);\n            category_item->setIcon(checked ? QIcon() : edit_icon());\n        }\n        if (auto* subcategory_item = model->item(row, ColumnSubcategory)) {\n            subcategory_item->setEditable(!checked);\n            subcategory_item->setIcon(checked ? QIcon() : edit_icon());\n        }\n    }\n\n    ensure_unique_suggested_names_in_model();\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (!row_is_supported_document(row)) {\n            continue;\n        }\n        update_preview_column(row);\n    }\n\n    dry_run_plan_.clear();\n    apply_category_visibility();\n    apply_subcategory_visibility();\n    apply_rename_only_row_visibility();\n    update_subcategory_checkbox_state();\n}\n\nvoid CategorizationDialog::apply_subcategory_visibility()\n{\n    if (table_view) {\n        const bool rename_images_active = rename_images_only_checkbox && rename_images_only_checkbox->isChecked();\n        const bool rename_documents_active = rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked();\n        auto should_hide_row = [&](int row) {\n            if (rename_images_active && row_is_supported_image(row)) {\n                return true;\n            }\n            if (rename_documents_active && row_is_supported_document(row)) {\n                return true;\n            }\n            return false;\n        };\n        auto should_show_category_column = [&]() {\n            if (!rename_images_active && !rename_documents_active) {\n                return true;\n            }\n            if (!model) {\n                return true;\n            }\n            for (int row = 0; row < model->rowCount(); ++row) {\n                if (should_hide_row(row)) {\n                    continue;\n                }\n                auto* item = model->item(row, ColumnCategory);\n                if (item && !item->text().trimmed().isEmpty()) {\n                    return true;\n                }\n                if (item && item->data(kHiddenCategoryRole).isValid() &&\n                    !item->data(kHiddenCategoryRole).toString().trimmed().isEmpty()) {\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        const bool show_category_column = should_show_category_column();\n        const bool hide_subcategory = !show_subcategory_column || !show_category_column;\n        table_view->setColumnHidden(ColumnSubcategory, hide_subcategory);\n        table_view->setColumnHidden(ColumnPreview, false);\n        if (model) {\n            auto update_item = [](QStandardItem* item, int role, bool hide) {\n                if (!item) {\n                    return;\n                }\n                if (hide) {\n                    if (!item->data(role).isValid() && !item->text().trimmed().isEmpty()) {\n                        item->setData(item->text(), role);\n                    }\n                    item->setText(QString());\n                } else if (item->data(role).isValid()) {\n                    item->setText(item->data(role).toString());\n                    item->setData(QVariant(), role);\n                }\n            };\n            for (int row = 0; row < model->rowCount(); ++row) {\n                const bool hide_row = show_subcategory_column && show_category_column &&\n                                      (rename_images_active || rename_documents_active) &&\n                                      should_hide_row(row);\n                update_item(model->item(row, ColumnSubcategory), kHiddenSubcategoryRole, hide_row);\n            }\n        }\n    }\n}\n\nvoid CategorizationDialog::apply_category_visibility()\n{\n    if (table_view) {\n        const bool rename_images_active = rename_images_only_checkbox && rename_images_only_checkbox->isChecked();\n        const bool rename_documents_active = rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked();\n        auto should_hide_row = [&](int row) {\n            if (rename_images_active && row_is_supported_image(row)) {\n                return true;\n            }\n            if (rename_documents_active && row_is_supported_document(row)) {\n                return true;\n            }\n            return false;\n        };\n        bool show_category_column = true;\n        if ((rename_images_active || rename_documents_active) && model) {\n            show_category_column = false;\n            for (int row = 0; row < model->rowCount(); ++row) {\n                if (should_hide_row(row)) {\n                    continue;\n                }\n                auto* item = model->item(row, ColumnCategory);\n                if (item && !item->text().trimmed().isEmpty()) {\n                    show_category_column = true;\n                    break;\n                }\n                if (item && item->data(kHiddenCategoryRole).isValid() &&\n                    !item->data(kHiddenCategoryRole).toString().trimmed().isEmpty()) {\n                    show_category_column = true;\n                    break;\n                }\n            }\n        }\n        table_view->setColumnHidden(ColumnCategory, !show_category_column);\n        if (bulk_edit_button) {\n            bulk_edit_button->setEnabled(show_category_column);\n        }\n        if (model) {\n            auto update_item = [](QStandardItem* item, int role, bool hide) {\n                if (!item) {\n                    return;\n                }\n                if (hide) {\n                    if (!item->data(role).isValid() && !item->text().trimmed().isEmpty()) {\n                        item->setData(item->text(), role);\n                    }\n                    item->setText(QString());\n                } else if (item->data(role).isValid()) {\n                    item->setText(item->data(role).toString());\n                    item->setData(QVariant(), role);\n                }\n            };\n            for (int row = 0; row < model->rowCount(); ++row) {\n                const bool hide_row = show_category_column &&\n                                      (rename_images_active || rename_documents_active) &&\n                                      should_hide_row(row);\n                update_item(model->item(row, ColumnCategory), kHiddenCategoryRole, hide_row);\n            }\n        }\n    }\n}\n\nvoid CategorizationDialog::apply_rename_only_row_visibility()\n{\n    if (!table_view || !model) {\n        return;\n    }\n\n    for (int row = 0; row < model->rowCount(); ++row) {\n        bool hide_row = false;\n        if (rename_images_only_checkbox &&\n            rename_images_only_checkbox->isChecked() &&\n            row_is_supported_image(row) &&\n            row_is_already_renamed_with_category(row)) {\n            hide_row = true;\n        }\n        if (rename_documents_only_checkbox &&\n            rename_documents_only_checkbox->isChecked() &&\n            row_is_supported_document(row) &&\n            row_is_already_renamed_with_category(row)) {\n            hide_row = true;\n        }\n        table_view->setRowHidden(row, hide_row);\n    }\n}\n\nvoid CategorizationDialog::apply_rename_visibility()\n{\n    if (table_view) {\n        table_view->setColumnHidden(ColumnSuggestedName, !show_rename_column);\n    }\n}\n\nvoid CategorizationDialog::update_rename_only_checkbox_state()\n{\n    if (!rename_images_only_checkbox) {\n        return;\n    }\n\n    bool has_images = false;\n    bool all_rename_only = true;\n    for (const auto& file : categorized_files) {\n        if (!is_supported_image_entry(file.file_path, file.file_name, file.type)) {\n            continue;\n        }\n        has_images = true;\n        if (!file.rename_only) {\n            all_rename_only = false;\n        }\n    }\n\n    QSignalBlocker blocker(rename_images_only_checkbox);\n    const bool enable_images_checkbox = has_images && allow_image_renames_;\n    rename_images_only_checkbox->setEnabled(enable_images_checkbox);\n    rename_images_only_checkbox->setChecked(enable_images_checkbox && all_rename_only);\n\n    if (rename_documents_only_checkbox) {\n        bool has_documents = false;\n        bool all_doc_rename_only = true;\n        for (const auto& file : categorized_files) {\n            if (!is_supported_document_entry(file.file_path, file.file_name, file.type)) {\n                continue;\n            }\n            has_documents = true;\n            if (!file.rename_only) {\n                all_doc_rename_only = false;\n            }\n        }\n\n        QSignalBlocker doc_blocker(rename_documents_only_checkbox);\n        const bool enable_documents_checkbox = has_documents && allow_document_renames_;\n        rename_documents_only_checkbox->setEnabled(enable_documents_checkbox);\n        rename_documents_only_checkbox->setChecked(enable_documents_checkbox && all_doc_rename_only);\n    }\n\n    update_subcategory_checkbox_state();\n}\n\nvoid CategorizationDialog::update_subcategory_checkbox_state()\n{\n    if (!show_subcategories_checkbox || !model) {\n        return;\n    }\n\n    const bool rename_only_active =\n        (rename_images_only_checkbox && rename_images_only_checkbox->isChecked()) ||\n        (rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked());\n    const bool enable_checkbox = !rename_only_active;\n\n    QSignalBlocker blocker(show_subcategories_checkbox);\n    show_subcategories_checkbox->setEnabled(enable_checkbox);\n    if (!enable_checkbox) {\n        show_subcategory_column = false;\n        show_subcategories_checkbox->setChecked(false);\n        apply_subcategory_visibility();\n    }\n}\n\nbool CategorizationDialog::row_is_supported_image(int row) const\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return false;\n    }\n    auto* file_item = model->item(row, ColumnFile);\n    if (!file_item) {\n        return false;\n    }\n    const std::string file_name = file_item->text().toStdString();\n    const std::string file_path = file_item->data(kFilePathRole).toString().toStdString();\n    const FileType file_type = static_cast<FileType>(file_item->data(kFileTypeRole).toInt());\n    return is_supported_image_entry(file_path, file_name, file_type);\n}\n\nbool CategorizationDialog::row_is_supported_document(int row) const\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return false;\n    }\n    auto* file_item = model->item(row, ColumnFile);\n    if (!file_item) {\n        return false;\n    }\n    const std::string file_name = file_item->text().toStdString();\n    const std::string file_path = file_item->data(kFilePathRole).toString().toStdString();\n    const FileType file_type = static_cast<FileType>(file_item->data(kFileTypeRole).toInt());\n    return is_supported_document_entry(file_path, file_name, file_type);\n}\n\nbool CategorizationDialog::row_is_already_renamed_with_category(int row) const\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return false;\n    }\n    auto* file_item = model->item(row, ColumnFile);\n    if (!file_item) {\n        return false;\n    }\n    if (!file_item->data(kRenameLockedRole).toBool()) {\n        return false;\n    }\n\n    auto* category_item = model->item(row, ColumnCategory);\n    std::string category = category_item ? category_item->text().toStdString() : std::string();\n    if (is_missing_category_label(category)) {\n        category.clear();\n    }\n    if (category.empty()) {\n        return false;\n    }\n    if (!show_subcategory_column) {\n        return true;\n    }\n\n    auto* subcategory_item = model->item(row, ColumnSubcategory);\n    std::string subcategory = subcategory_item ? subcategory_item->text().toStdString() : std::string();\n    if (is_missing_category_label(subcategory)) {\n        subcategory.clear();\n    }\n    return !subcategory.empty();\n}\n\nstd::optional<std::string> CategorizationDialog::compute_preview_path(int row) const\n{\n    auto rec = build_preview_record_for_row(row);\n    if (rec) {\n        return rec->destination;\n    }\n    return std::nullopt;\n}\n\nstd::optional<CategorizationDialog::PreviewRecord>\nCategorizationDialog::build_preview_record_for_row(int row, std::string* debug_reason) const\n{\n    auto fail = [&](std::string reason) -> std::optional<PreviewRecord> {\n        if (debug_reason) {\n            *debug_reason = std::move(reason);\n        }\n        return std::nullopt;\n    };\n\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return fail(\"Invalid model or row\");\n    }\n    if (base_dir_.empty()) {\n        return fail(\"Base dir empty\");\n    }\n\n    const auto* file_item = model->item(row, ColumnFile);\n    const auto* category_item = model->item(row, ColumnCategory);\n    const auto* subcategory_item = model->item(row, ColumnSubcategory);\n    const auto* rename_item = model->item(row, ColumnSuggestedName);\n    if (!file_item || !category_item) {\n        return fail(\"Missing file/category item\");\n    }\n\n    const std::string file_name = file_item->text().toStdString();\n    std::string source_dir = file_item->data(kFilePathRole).toString().toStdString();\n    if (source_dir.empty()) {\n        source_dir = base_dir_;\n    }\n    const std::string rename_candidate = rename_item ? rename_item->text().toStdString() : std::string();\n    const std::string destination_name = resolve_destination_name(file_name, rename_candidate);\n    const bool rename_active = destination_name != file_name;\n    bool rename_only = false;\n    bool used_consistency_hints = false;\n    FileType file_type = FileType::File;\n    if (!resolve_row_flags(row, rename_only, used_consistency_hints, file_type)) {\n        return fail(\"Missing row metadata\");\n    }\n    (void)used_consistency_hints;\n    (void)file_type;\n    if (rename_active) {\n        std::string rename_error;\n        if (!validate_filename(destination_name, rename_error)) {\n            return fail(\"Invalid rename: \" + rename_error);\n        }\n    }\n\n    if (rename_only) {\n        const auto source_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(file_name);\n        const auto destination_path = Utils::utf8_to_path(source_dir) / Utils::utf8_to_path(destination_name);\n        return PreviewRecord{\n            Utils::path_to_utf8(source_path),\n            Utils::path_to_utf8(destination_path),\n            file_name,\n            destination_name,\n            std::string(),\n            std::string(),\n            false,\n            true};\n    }\n\n    const std::string category = category_item->text().toStdString();\n    const std::string subcategory = show_subcategory_column && subcategory_item\n        ? subcategory_item->text().toStdString()\n        : std::string();\n    const std::string effective_subcategory = subcategory.empty() ? category : subcategory;\n\n    std::string validation_error;\n    const bool allow_identical = !show_subcategory_column;\n    if (!validate_labels(category, effective_subcategory, validation_error, allow_identical)) {\n        return fail(\"Validation failed: \" + validation_error);\n    }\n\n    try {\n        MovableCategorizedFile categorized_file(source_dir,\n                                                base_dir_,\n                                                category,\n                                                effective_subcategory,\n                                                file_name,\n                                                destination_name);\n        const auto preview_paths = categorized_file.preview_move_paths(show_subcategory_column);\n        return PreviewRecord{\n            preview_paths.source,\n            preview_paths.destination,\n            file_name,\n            destination_name,\n            category,\n            effective_subcategory,\n            show_subcategory_column,\n            false};\n    } catch (...) {\n        return fail(\"Exception building preview record\");\n    }\n}\n\nstd::string CategorizationDialog::resolve_destination_name(const std::string& original_name,\n                                                           const std::string& rename_candidate) const\n{\n    std::string trimmed = trim_copy(rename_candidate);\n    if (trimmed.empty()) {\n        return original_name;\n    }\n    if (trimmed == original_name) {\n        return original_name;\n    }\n\n    const std::filesystem::path original_path = Utils::utf8_to_path(original_name);\n    const std::filesystem::path candidate_path = Utils::utf8_to_path(trimmed);\n    if (!candidate_path.has_extension() && original_path.has_extension()) {\n        return Utils::path_to_utf8(candidate_path) + original_path.extension().string();\n    }\n\n    return trimmed;\n}\n\nbool CategorizationDialog::validate_filename(const std::string& name, std::string& error) const\n{\n    if (name.empty()) {\n        error = \"Filename is empty\";\n        return false;\n    }\n    if (name == \".\" || name == \"..\") {\n        error = \"Filename is invalid\";\n        return false;\n    }\n    if (!contains_only_allowed_chars(name)) {\n        error = \"Filename contains disallowed characters\";\n        return false;\n    }\n    if (has_leading_or_trailing_space_or_dot(name)) {\n        error = \"Filename has leading/trailing space or dot\";\n        return false;\n    }\n\n    const auto path = Utils::utf8_to_path(name);\n    const std::string stem = Utils::path_to_utf8(path.stem());\n    if (stem.empty()) {\n        error = \"Filename is missing a base name\";\n        return false;\n    }\n    if (is_reserved_windows_name(stem)) {\n        error = \"Filename is a reserved name\";\n        return false;\n    }\n    return true;\n}\n\nbool CategorizationDialog::resolve_row_flags(int row,\n                                             bool& rename_only,\n                                             bool& used_consistency_hints,\n                                             FileType& file_type) const\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return false;\n    }\n    auto* file_item = model->item(row, ColumnFile);\n    if (!file_item) {\n        return false;\n    }\n\n    rename_only = file_item->data(kRenameOnlyRole).toBool();\n    used_consistency_hints = file_item->data(kUsedConsistencyRole).toBool();\n    file_type = static_cast<FileType>(file_item->data(kFileTypeRole).toInt());\n    if (!rename_only && (row_is_supported_image(row) || row_is_supported_document(row))) {\n        auto* category_item = model->item(row, ColumnCategory);\n        if (category_item) {\n            const std::string category_text = category_item->text().toStdString();\n            if (is_missing_category_label(category_text)) {\n                rename_only = true;\n            }\n        }\n    }\n    return true;\n}\n\nvoid CategorizationDialog::update_preview_column(int row)\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return;\n    }\n    auto* preview_item = model->item(row, ColumnPreview);\n    if (!preview_item) {\n        return;\n    }\n    if (rename_images_only_checkbox &&\n        rename_images_only_checkbox->isChecked() &&\n        row_is_supported_image(row)) {\n        preview_item->setText(QStringLiteral(\"-\"));\n        preview_item->setToolTip(QString());\n        return;\n    }\n    if (rename_documents_only_checkbox &&\n        rename_documents_only_checkbox->isChecked() &&\n        row_is_supported_document(row)) {\n        preview_item->setText(QStringLiteral(\"-\"));\n        preview_item->setToolTip(QString());\n        return;\n    }\n    const auto preview = compute_preview_path(row);\n    if (preview) {\n        std::string display = *preview;\n#ifdef _WIN32\n        std::replace(display.begin(), display.end(), '/', '\\\\');\n#endif\n        preview_item->setText(QString::fromStdString(display));\n        preview_item->setToolTip(QString::fromStdString(display));\n    } else {\n        preview_item->setText(QStringLiteral(\"-\"));\n        preview_item->setToolTip(QString());\n    }\n}\n\nvoid CategorizationDialog::set_preview_status(int row, const std::string& destination)\n{\n    if (!model || row < 0 || row >= model->rowCount()) {\n        return;\n    }\n    if (auto* status_item = model->item(row, ColumnStatus)) {\n        status_item->setData(static_cast<int>(RowStatus::Preview), kStatusRole);\n        status_item->setText(tr(\"Preview\"));\n        status_item->setForeground(QBrush(Qt::blue));\n        std::string display = destination;\n#ifdef _WIN32\n        std::replace(display.begin(), display.end(), '/', '\\\\');\n#endif\n        status_item->setToolTip(QString::fromStdString(display));\n    }\n}\n\nvoid CategorizationDialog::persist_move_plan()\n{\n    if (undo_dir_.empty() || base_dir_.empty() || move_history_.empty()) {\n        return;\n    }\n\n    std::vector<UndoManager::Entry> entries;\n    entries.reserve(move_history_.size());\n    for (const auto& rec : move_history_) {\n        entries.push_back(UndoManager::Entry{\n            rec.source_path,\n            rec.destination_path,\n            rec.size_bytes,\n            rec.mtime});\n    }\n\n    UndoManager manager(undo_dir_);\n    manager.save_plan(base_dir_, entries, core_logger);\n}\n\nvoid CategorizationDialog::clear_move_history()\n{\n    move_history_.clear();\n}\n\nvoid CategorizationDialog::retranslate_ui()\n{\n    setWindowTitle(tr(\"Review and Confirm\"));\n\n    const auto set_text_if = [](auto* widget, const QString& text) {\n        if (widget) {\n            widget->setText(text);\n        }\n    };\n\n    set_text_if(select_all_checkbox, tr(\"Select all\"));\n    set_text_if(select_highlighted_button, tr(\"Select highlighted\"));\n    set_text_if(bulk_edit_button, tr(\"Edit selected...\"));\n    set_text_if(show_subcategories_checkbox, tr(\"Create subcategory folders\"));\n    set_text_if(dry_run_checkbox, tr(\"Dry run (preview only, do not move files)\"));\n    set_text_if(rename_images_only_checkbox, tr(\"Do not categorize picture files (only rename)\"));\n    set_text_if(rename_documents_only_checkbox, tr(\"Do not categorize document files (only rename)\"));\n    set_text_if(confirm_button, tr(\"Confirm and Process\"));\n    set_text_if(continue_button, tr(\"Continue Later\"));\n    set_text_if(undo_button, tr(\"Undo this change\"));\n    set_text_if(close_button, tr(\"Close\"));\n\n    if (select_highlighted_button) {\n        select_highlighted_button->setToolTip(tr(\"Mark highlighted rows for processing (Ctrl+Space).\"));\n    }\n    if (bulk_edit_button) {\n        bulk_edit_button->setToolTip(tr(\"Apply category/subcategory values to highlighted rows.\"));\n    }\n\n    if (model) {\n        model->setHorizontalHeaderLabels(QStringList{\n            tr(\"Process\"),\n            tr(\"File\"),\n            tr(\"Type\"),\n            tr(\"Suggested filename\"),\n            tr(\"Category\"),\n            tr(\"Subcategory\"),\n            tr(\"Status\"),\n            tr(\"Planned destination\")\n        });\n\n        for (int row = 0; row < model->rowCount(); ++row) {\n            if (auto* type_item = model->item(row, ColumnType)) {\n                update_type_icon(type_item);\n                type_item->setTextAlignment(Qt::AlignCenter);\n            }\n            if (auto* status_item = model->item(row, ColumnStatus)) {\n                apply_status_text(status_item);\n            }\n        }\n    }\n}\n\nvoid CategorizationDialog::apply_status_text(QStandardItem* item) const\n{\n    if (!item) {\n        return;\n    }\n\n    switch (status_from_item(item)) {\n    case RowStatus::Moved:\n        item->setText(tr(\"Moved\"));\n        break;\n    case RowStatus::Renamed:\n        item->setText(tr(\"Renamed\"));\n        break;\n    case RowStatus::RenamedAndMoved:\n        item->setText(tr(\"Renamed & Moved\"));\n        break;\n    case RowStatus::Skipped:\n        item->setText(tr(\"Skipped\"));\n        break;\n    case RowStatus::Preview:\n        item->setText(tr(\"Preview\"));\n        break;\n    case RowStatus::NotSelected:\n        item->setText(tr(\"Not selected\"));\n        break;\n    case RowStatus::None:\n    default:\n        item->setText(QString());\n        break;\n    }\n}\n\nCategorizationDialog::RowStatus CategorizationDialog::status_from_item(const QStandardItem* item) const\n{\n    if (!item) {\n        return RowStatus::None;\n    }\n\n    bool ok = false;\n    const int value = item->data(kStatusRole).toInt(&ok);\n    if (!ok) {\n        return RowStatus::None;\n    }\n\n    const RowStatus status = static_cast<RowStatus>(value);\n    switch (status) {\n    case RowStatus::None:\n    case RowStatus::Moved:\n    case RowStatus::Renamed:\n    case RowStatus::RenamedAndMoved:\n    case RowStatus::Skipped:\n    case RowStatus::NotSelected:\n    case RowStatus::Preview:\n        return status;\n    }\n\n    return RowStatus::None;\n}\n\n\nvoid CategorizationDialog::on_item_changed(QStandardItem* item)\n{\n    if (!item || updating_select_all || suppress_item_changed_) {\n        return;\n    }\n\n    if (item->column() == ColumnSelect) {\n        update_select_all_state();\n    } else if (item->column() == ColumnCategory ||\n               item->column() == ColumnSubcategory ||\n               item->column() == ColumnSuggestedName) {\n        if ((item->column() == ColumnCategory || item->column() == ColumnSubcategory) &&\n            (row_is_supported_image(item->row()) || row_is_supported_document(item->row()))) {\n            const std::string text = item->text().toStdString();\n            if (is_missing_category_label(text)) {\n                ScopedFlag guard(suppress_item_changed_);\n                item->setText(QString());\n            }\n        }\n        update_preview_column(item->row());\n        if (item->column() == ColumnCategory || item->column() == ColumnSubcategory) {\n            update_subcategory_checkbox_state();\n        }\n    }\n    // invalidate preview plan only on user-facing edits (selection/category fields)\n    if (item->column() == ColumnSelect ||\n        item->column() == ColumnCategory ||\n        item->column() == ColumnSubcategory ||\n        item->column() == ColumnSuggestedName) {\n        dry_run_plan_.clear();\n    }\n}\n\n\nvoid CategorizationDialog::update_select_all_state()\n{\n    if (!select_all_checkbox) {\n        return;\n    }\n\n    bool all_checked = true;\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (auto* item = model->item(row, ColumnSelect)) {\n            if (item->checkState() != Qt::Checked) {\n                all_checked = false;\n                break;\n            }\n        }\n    }\n\n    QSignalBlocker blocker(select_all_checkbox);\n    select_all_checkbox->setChecked(all_checked);\n}\n\nvoid CategorizationDialog::changeEvent(QEvent* event)\n{\n    QDialog::changeEvent(event);\n    if (event && event->type() == QEvent::LanguageChange) {\n        retranslate_ui();\n        for (int row = 0; row < model->rowCount(); ++row) {\n            update_preview_column(row);\n        }\n    }\n}\n\n\nvoid CategorizationDialog::closeEvent(QCloseEvent* event)\n{\n    record_categorization_to_db();\n    QDialog::closeEvent(event);\n}\nvoid CategorizationDialog::set_show_subcategory_column(bool enabled)\n{\n    if (show_subcategory_column == enabled) {\n        return;\n    }\n    show_subcategory_column = enabled;\n    if (show_subcategories_checkbox) {\n        QSignalBlocker blocker(show_subcategories_checkbox);\n        show_subcategories_checkbox->setChecked(enabled);\n    }\n    apply_subcategory_visibility();\n    update_subcategory_checkbox_state();\n}\n\nvoid CategorizationDialog::set_show_rename_column(bool enabled)\n{\n    if (show_rename_column == enabled) {\n        return;\n    }\n    show_rename_column = enabled;\n    apply_rename_visibility();\n}\n#ifdef AI_FILE_SORTER_TEST_BUILD\nvoid CategorizationDialog::test_set_entries(const std::vector<CategorizedFile>& files) {\n    categorized_files = files;\n    include_subdirectories_ = false;\n    base_dir_.clear();\n    if (!categorized_files.empty()) {\n        base_dir_ = categorized_files.front().file_path;\n    }\n    ensure_unique_image_suggested_names(categorized_files, base_dir_, show_subcategory_column);\n    set_show_rename_column(std::any_of(categorized_files.begin(),\n                                       categorized_files.end(),\n                                       [](const CategorizedFile& file) {\n                                           return !file.suggested_name.empty();\n                                       }));\n    update_rename_only_checkbox_state();\n    apply_category_visibility();\n    apply_subcategory_visibility();\n    populate_model();\n    on_rename_images_only_toggled(rename_images_only_checkbox && rename_images_only_checkbox->isChecked());\n    on_rename_documents_only_toggled(rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked());\n    update_subcategory_checkbox_state();\n}\n\nvoid CategorizationDialog::test_trigger_confirm() {\n    on_confirm_and_sort_button_clicked();\n}\n\nvoid CategorizationDialog::test_trigger_undo() {\n    on_undo_button_clicked();\n}\n\nbool CategorizationDialog::test_undo_enabled() const {\n    return undo_button && undo_button->isEnabled();\n}\n#endif\n"
  },
  {
    "path": "app/lib/CategorizationProgressDialog.cpp",
    "content": "#include \"CategorizationProgressDialog.hpp\"\n\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n#include \"Logger.hpp\"\n#include \"MainApp.hpp\"\n\n#include <QAbstractItemView>\n#include <QColor>\n#include <QEvent>\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QLabel>\n#include <QPlainTextEdit>\n#include <QPushButton>\n#include <QScrollBar>\n#include <QStyle>\n#include <QTableWidget>\n#include <QTableWidgetItem>\n#include <QTextCursor>\n#include <QTimer>\n#include <QVBoxLayout>\n#include <QString>\n\n#include <algorithm>\n\nCategorizationProgressDialog::CategorizationProgressDialog(QWidget* parent,\n                                                           MainApp* main_app,\n                                                           bool show_subcategory_col)\n    : QDialog(parent),\n      main_app(main_app)\n{\n    resize(900, 650);\n    setup_ui(show_subcategory_col);\n    retranslate_ui();\n}\n\n\nvoid CategorizationProgressDialog::setup_ui(bool /*show_subcategory_col*/)\n{\n    auto* layout = new QVBoxLayout(this);\n    layout->setSpacing(10);\n\n    stage_list_label = new QLabel(this);\n    stage_list_label->setTextFormat(Qt::RichText);\n    layout->addWidget(stage_list_label);\n\n    summary_label = new QLabel(this);\n    layout->addWidget(summary_label);\n\n    status_table = new QTableWidget(this);\n    status_table->setColumnCount(2);\n    status_table->setSelectionMode(QAbstractItemView::NoSelection);\n    status_table->setSelectionBehavior(QAbstractItemView::SelectRows);\n    status_table->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    status_table->setAlternatingRowColors(true);\n    status_table->setShowGrid(false);\n    status_table->verticalHeader()->setVisible(false);\n    layout->addWidget(status_table, 2);\n\n    log_label = new QLabel(this);\n    layout->addWidget(log_label);\n\n    text_view = new QPlainTextEdit(this);\n    text_view->setReadOnly(true);\n    text_view->setLineWrapMode(QPlainTextEdit::WidgetWidth);\n    layout->addWidget(text_view, 1);\n\n    auto* button_layout = new QHBoxLayout();\n    button_layout->addStretch(1);\n\n    stop_button = new QPushButton(this);\n    QIcon stop_icon = QIcon::fromTheme(QStringLiteral(\"process-stop\"));\n    if (stop_icon.isNull()) {\n        stop_icon = QIcon(style()->standardIcon(QStyle::SP_BrowserStop));\n    }\n    stop_button->setIcon(stop_icon);\n    stop_button->setIconSize(QSize(18, 18));\n    button_layout->addWidget(stop_button);\n\n    layout->addLayout(button_layout);\n\n    connect(stop_button, &QPushButton::clicked, this, &CategorizationProgressDialog::request_stop);\n\n    spinner_timer = new QTimer(this);\n    spinner_timer->setInterval(140);\n    connect(spinner_timer, &QTimer::timeout, this, &CategorizationProgressDialog::refresh_spinner);\n}\n\n\nvoid CategorizationProgressDialog::show()\n{\n    QDialog::show();\n    if (text_view) {\n        text_view->moveCursor(QTextCursor::End);\n    }\n}\n\n\nvoid CategorizationProgressDialog::hide()\n{\n    if (spinner_timer) {\n        spinner_timer->stop();\n    }\n    QDialog::hide();\n}\n\n\nvoid CategorizationProgressDialog::append_text(const std::string& text)\n{\n    if (!text_view) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->error(\"Progress dialog text view is null\");\n        }\n        return;\n    }\n\n    QString qt_text = QString::fromStdString(text);\n    if (!qt_text.endsWith('\\n')) {\n        qt_text.append('\\n');\n    }\n    text_view->appendPlainText(qt_text);\n\n    QScrollBar* scroll = text_view->verticalScrollBar();\n    if (scroll) {\n        scroll->setValue(scroll->maximum());\n    }\n}\n\n\nvoid CategorizationProgressDialog::configure_stages(const std::vector<StagePlan>& stages)\n{\n    spinner_frame_index_ = 0;\n    active_stage_order_.clear();\n    active_stage_.reset();\n    item_states_.clear();\n\n    for (auto& stage_state : stage_states_) {\n        stage_state.enabled = false;\n        stage_state.item_keys.clear();\n    }\n\n    if (status_table) {\n        status_table->setRowCount(0);\n    }\n\n    std::unordered_set<StageId> seen_stages;\n    std::unordered_set<std::string> seen_items;\n    std::vector<FileEntry> all_items;\n\n    for (const auto& stage : stages) {\n        if (!seen_stages.contains(stage.id)) {\n            seen_stages.insert(stage.id);\n            active_stage_order_.push_back(stage.id);\n            stage_states_[stage_index(stage.id)].enabled = true;\n        }\n        auto& stage_state = stage_states_[stage_index(stage.id)];\n        for (const auto& entry : stage.items) {\n            const std::string key = make_item_key(entry.full_path, entry.type);\n            stage_state.item_keys.insert(key);\n            if (!seen_items.contains(key)) {\n                seen_items.insert(key);\n                all_items.push_back(entry);\n            }\n        }\n    }\n\n    if (!active_stage_order_.empty()) {\n        active_stage_ = active_stage_order_.front();\n    }\n\n    rebuild_headers();\n\n    for (const auto& entry : all_items) {\n        upsert_item(entry);\n    }\n\n    refresh_stage_overview();\n    refresh_summary();\n\n    if (!has_in_progress_item() && spinner_timer) {\n        spinner_timer->stop();\n    }\n}\n\n\nvoid CategorizationProgressDialog::set_stage_items(StageId stage_id,\n                                                   const std::vector<FileEntry>& items)\n{\n    ensure_stage_enabled(stage_id);\n\n    auto& stage_state = stage_states_[stage_index(stage_id)];\n    stage_state.item_keys.clear();\n\n    for (const auto& entry : items) {\n        const std::string key = make_item_key(entry.full_path, entry.type);\n        stage_state.item_keys.insert(key);\n        upsert_item(entry);\n    }\n\n    const std::size_t idx = stage_index(stage_id);\n    for (auto& [key, state] : item_states_) {\n        if (stage_state.item_keys.contains(key)) {\n            if (state.stage_statuses[idx] == ItemStatus::NotApplicable) {\n                state.stage_statuses[idx] = ItemStatus::Pending;\n            }\n        } else {\n            state.stage_statuses[idx] = ItemStatus::NotApplicable;\n        }\n    }\n\n    for (const auto& [key, state] : item_states_) {\n        (void)key;\n        refresh_row(state.row);\n    }\n\n    refresh_stage_overview();\n    refresh_summary();\n}\n\n\nvoid CategorizationProgressDialog::set_active_stage(StageId stage_id)\n{\n    const auto& stage_state = stage_states_[stage_index(stage_id)];\n    if (!stage_state.enabled) {\n        return;\n    }\n\n    active_stage_ = stage_id;\n    refresh_stage_overview();\n    refresh_summary();\n\n    if (const auto in_progress_row = find_stage_row(stage_id, ItemStatus::InProgress)) {\n        ensure_row_visible(*in_progress_row);\n        return;\n    }\n    if (const auto pending_row = find_stage_row(stage_id, ItemStatus::Pending)) {\n        ensure_row_visible(*pending_row);\n    }\n}\n\n\nvoid CategorizationProgressDialog::mark_stage_item_pending(StageId stage_id,\n                                                           const FileEntry& entry)\n{\n    set_stage_item_status(stage_id, entry, ItemStatus::Pending);\n}\n\n\nvoid CategorizationProgressDialog::mark_stage_item_in_progress(StageId stage_id,\n                                                               const FileEntry& entry)\n{\n    set_stage_item_status(stage_id, entry, ItemStatus::InProgress);\n}\n\n\nvoid CategorizationProgressDialog::mark_stage_item_completed(StageId stage_id,\n                                                             const FileEntry& entry)\n{\n    set_stage_item_status(stage_id, entry, ItemStatus::Completed);\n}\n\n\nvoid CategorizationProgressDialog::request_stop()\n{\n    if (!main_app) {\n        return;\n    }\n    main_app->report_progress(\n        tr(\"[STOP] Analysis will stop after the current item is processed.\")\n            .toUtf8()\n            .toStdString());\n    main_app->request_stop_analysis();\n}\n\n\nstd::string CategorizationProgressDialog::make_item_key(const std::string& full_path,\n                                                        FileType type)\n{\n    return full_path + \"|\" + std::to_string(static_cast<int>(type));\n}\n\n\nstd::size_t CategorizationProgressDialog::stage_index(StageId stage_id)\n{\n    switch (stage_id) {\n        case StageId::ImageAnalysis:\n            return 0;\n        case StageId::DocumentAnalysis:\n            return 1;\n        case StageId::Categorization:\n        default:\n            return 2;\n    }\n}\n\n\nQString CategorizationProgressDialog::stage_label(StageId stage_id) const\n{\n    switch (stage_id) {\n        case StageId::ImageAnalysis:\n            return tr(\"Image analysis\");\n        case StageId::DocumentAnalysis:\n            return tr(\"Document analysis\");\n        case StageId::Categorization:\n        default:\n            return tr(\"Categorization\");\n    }\n}\n\n\nCategorizationProgressDialog::DisplayType CategorizationProgressDialog::classify_display_type(const FileEntry& entry)\n{\n    if (entry.type == FileType::Directory) {\n        return DisplayType::Directory;\n    }\n    if (LlavaImageAnalyzer::is_supported_image(entry.full_path)) {\n        return DisplayType::Image;\n    }\n    if (DocumentTextAnalyzer::is_supported_document(entry.full_path)) {\n        return DisplayType::Document;\n    }\n    return DisplayType::File;\n}\n\n\nQString CategorizationProgressDialog::display_type_label(DisplayType display_type) const\n{\n    switch (display_type) {\n        case DisplayType::Directory:\n            return tr(\"Directory\");\n        case DisplayType::Image:\n            return tr(\"Image\");\n        case DisplayType::Document:\n            return tr(\"Document\");\n        case DisplayType::File:\n        default:\n            return tr(\"File\");\n    }\n}\n\n\nint CategorizationProgressDialog::column_for_stage(StageId stage_id) const\n{\n    for (std::size_t i = 0; i < active_stage_order_.size(); ++i) {\n        if (active_stage_order_[i] == stage_id) {\n            return static_cast<int>(2 + i);\n        }\n    }\n    return -1;\n}\n\n\nvoid CategorizationProgressDialog::ensure_stage_enabled(StageId stage_id)\n{\n    auto& stage_state = stage_states_[stage_index(stage_id)];\n    if (!stage_state.enabled) {\n        stage_state.enabled = true;\n        if (std::find(active_stage_order_.begin(), active_stage_order_.end(), stage_id) == active_stage_order_.end()) {\n            active_stage_order_.push_back(stage_id);\n        }\n    }\n\n    if (!active_stage_.has_value()) {\n        active_stage_ = stage_id;\n    }\n\n    rebuild_headers();\n}\n\n\nvoid CategorizationProgressDialog::upsert_stage_item(StageId stage_id,\n                                                     const FileEntry& entry)\n{\n    ensure_stage_enabled(stage_id);\n\n    const std::string key = make_item_key(entry.full_path, entry.type);\n    auto& stage_state = stage_states_[stage_index(stage_id)];\n    stage_state.item_keys.insert(key);\n\n    upsert_item(entry);\n\n    auto it = item_states_.find(key);\n    if (it == item_states_.end()) {\n        return;\n    }\n\n    const std::size_t idx = stage_index(stage_id);\n    if (it->second.stage_statuses[idx] == ItemStatus::NotApplicable) {\n        it->second.stage_statuses[idx] = ItemStatus::Pending;\n    }\n}\n\n\nvoid CategorizationProgressDialog::upsert_item(const FileEntry& entry)\n{\n    if (!status_table) {\n        return;\n    }\n\n    const std::string key = make_item_key(entry.full_path, entry.type);\n    if (item_states_.contains(key)) {\n        return;\n    }\n\n    const int row = status_table->rowCount();\n    status_table->insertRow(row);\n\n    auto* file_item = new QTableWidgetItem(QString::fromStdString(entry.file_name));\n    file_item->setToolTip(QString::fromStdString(entry.full_path));\n    status_table->setItem(row, 0, file_item);\n\n    auto* type_item = new QTableWidgetItem(display_type_label(classify_display_type(entry)));\n    type_item->setTextAlignment(Qt::AlignCenter);\n    status_table->setItem(row, 1, type_item);\n\n    ItemState state;\n    state.row = row;\n    state.display_type = classify_display_type(entry);\n\n    for (std::size_t i = 0; i < kStageCount; ++i) {\n        const auto& stage_state = stage_states_[i];\n        if (stage_state.enabled && stage_state.item_keys.contains(key)) {\n            state.stage_statuses[i] = ItemStatus::Pending;\n        } else {\n            state.stage_statuses[i] = ItemStatus::NotApplicable;\n        }\n    }\n\n    item_states_.emplace(key, state);\n    refresh_row(row);\n}\n\n\nvoid CategorizationProgressDialog::set_stage_item_status(StageId stage_id,\n                                                         const FileEntry& entry,\n                                                         ItemStatus status)\n{\n    upsert_stage_item(stage_id, entry);\n\n    const std::string key = make_item_key(entry.full_path, entry.type);\n    auto it = item_states_.find(key);\n    if (it == item_states_.end()) {\n        return;\n    }\n\n    ItemState& state = it->second;\n    const std::size_t idx = stage_index(stage_id);\n\n    if (state.stage_statuses[idx] == status) {\n        if (status == ItemStatus::InProgress) {\n            refresh_row(state.row);\n            ensure_row_visible(state.row);\n        }\n        return;\n    }\n\n    state.stage_statuses[idx] = status;\n\n    refresh_row(state.row);\n    refresh_summary();\n\n    if (!spinner_timer) {\n        if (status == ItemStatus::InProgress) {\n            ensure_row_visible(state.row);\n        }\n        return;\n    }\n    if (has_in_progress_item()) {\n        if (!spinner_timer->isActive()) {\n            spinner_timer->start();\n        }\n    } else {\n        spinner_timer->stop();\n    }\n\n    if (status == ItemStatus::InProgress) {\n        ensure_row_visible(state.row);\n    }\n}\n\n\nvoid CategorizationProgressDialog::rebuild_headers()\n{\n    if (!status_table) {\n        return;\n    }\n\n    const int stage_col_count = static_cast<int>(active_stage_order_.size());\n    status_table->setColumnCount(2 + stage_col_count);\n\n    QStringList headers;\n    headers << tr(\"File\") << tr(\"Type\");\n    for (StageId stage_id : active_stage_order_) {\n        headers << stage_label(stage_id);\n    }\n    status_table->setHorizontalHeaderLabels(headers);\n\n    auto* header = status_table->horizontalHeader();\n    if (!header) {\n        return;\n    }\n    header->setStretchLastSection(false);\n    header->setSectionResizeMode(0, QHeaderView::Stretch);\n    header->setSectionResizeMode(1, QHeaderView::ResizeToContents);\n    for (int col = 2; col < status_table->columnCount(); ++col) {\n        header->setSectionResizeMode(col, QHeaderView::ResizeToContents);\n    }\n}\n\n\nvoid CategorizationProgressDialog::refresh_stage_overview()\n{\n    if (!stage_list_label) {\n        return;\n    }\n\n    if (active_stage_order_.empty()) {\n        stage_list_label->setText(QString());\n        return;\n    }\n\n    QStringList lines;\n    for (std::size_t i = 0; i < active_stage_order_.size(); ++i) {\n        const StageId stage_id = active_stage_order_[i];\n        QString line = tr(\"Stage %1: %2\")\n                           .arg(static_cast<int>(i + 1))\n                           .arg(stage_label(stage_id));\n        if (active_stage_.has_value() && active_stage_.value() == stage_id) {\n            line = QStringLiteral(\"<b>%1</b>\").arg(line);\n        }\n        lines << line;\n    }\n    stage_list_label->setText(lines.join(QStringLiteral(\"<br/>\")));\n}\n\n\nCategorizationProgressDialog::ItemStatus CategorizationProgressDialog::stage_status_for_row(\n    const ItemState& state,\n    StageId stage_id) const\n{\n    return state.stage_statuses[stage_index(stage_id)];\n}\n\n\nstd::optional<int> CategorizationProgressDialog::find_stage_row(StageId stage_id,\n                                                                ItemStatus status) const\n{\n    std::optional<int> best_row;\n    const std::size_t idx = stage_index(stage_id);\n\n    for (const auto& [key, item] : item_states_) {\n        (void)key;\n        if (item.stage_statuses[idx] != status) {\n            continue;\n        }\n        if (!best_row.has_value() || item.row < *best_row) {\n            best_row = item.row;\n        }\n    }\n\n    return best_row;\n}\n\n\nvoid CategorizationProgressDialog::ensure_row_visible(int row)\n{\n    if (!status_table || row < 0 || row >= status_table->rowCount()) {\n        return;\n    }\n\n    auto* anchor_item = status_table->item(row, 0);\n    if (!anchor_item) {\n        return;\n    }\n\n    status_table->scrollToItem(anchor_item, QAbstractItemView::EnsureVisible);\n}\n\n\nvoid CategorizationProgressDialog::refresh_row(int row)\n{\n    if (!status_table || row < 0 || row >= status_table->rowCount()) {\n        return;\n    }\n\n    const ItemState* state = nullptr;\n    for (const auto& [key, item] : item_states_) {\n        (void)key;\n        if (item.row == row) {\n            state = &item;\n            break;\n        }\n    }\n    if (!state) {\n        return;\n    }\n\n    auto* type_item = status_table->item(row, 1);\n    if (!type_item) {\n        type_item = new QTableWidgetItem();\n        status_table->setItem(row, 1, type_item);\n    }\n    type_item->setText(display_type_label(state->display_type));\n    type_item->setTextAlignment(Qt::AlignCenter);\n\n    static const QString kSpinnerFrames[] = {\n        QStringLiteral(\"◐\"),\n        QStringLiteral(\"◓\"),\n        QStringLiteral(\"◑\"),\n        QStringLiteral(\"◒\")\n    };\n\n    for (StageId stage_id : active_stage_order_) {\n        const int col = column_for_stage(stage_id);\n        if (col < 0) {\n            continue;\n        }\n\n        auto* stage_item = status_table->item(row, col);\n        if (!stage_item) {\n            stage_item = new QTableWidgetItem();\n            status_table->setItem(row, col, stage_item);\n        }\n\n        const ItemStatus status = stage_status_for_row(*state, stage_id);\n        switch (status) {\n            case ItemStatus::NotApplicable:\n                stage_item->setText(QStringLiteral(\"—\"));\n                stage_item->setForeground(QColor(150, 150, 150));\n                break;\n            case ItemStatus::Pending:\n                stage_item->setText(QStringLiteral(\"○ %1\").arg(tr(\"Pending\")));\n                stage_item->setForeground(QColor(120, 120, 120));\n                break;\n            case ItemStatus::InProgress:\n                stage_item->setText(QStringLiteral(\"%1 %2\")\n                                        .arg(kSpinnerFrames[spinner_frame_index_ % 4], tr(\"In progress\")));\n                stage_item->setForeground(QColor(33, 150, 243));\n                break;\n            case ItemStatus::Completed:\n                stage_item->setText(QStringLiteral(\"✓ %1\").arg(tr(\"Complete\")));\n                stage_item->setForeground(QColor(46, 125, 50));\n                break;\n        }\n\n        stage_item->setTextAlignment(Qt::AlignCenter);\n    }\n}\n\n\nvoid CategorizationProgressDialog::refresh_summary()\n{\n    if (!summary_label) {\n        return;\n    }\n\n    if (!active_stage_.has_value()) {\n        summary_label->setText(tr(\"Processed 0/0  |  In progress: 0  |  Pending: 0\"));\n        return;\n    }\n\n    const StageId current_stage = active_stage_.value();\n    const auto& stage_state = stage_states_[stage_index(current_stage)];\n\n    int processed = 0;\n    int in_progress = 0;\n    int pending = 0;\n\n    for (const auto& key : stage_state.item_keys) {\n        auto it = item_states_.find(key);\n        if (it == item_states_.end()) {\n            continue;\n        }\n\n        const ItemStatus status = it->second.stage_statuses[stage_index(current_stage)];\n        switch (status) {\n            case ItemStatus::Completed:\n                ++processed;\n                break;\n            case ItemStatus::InProgress:\n                ++in_progress;\n                break;\n            case ItemStatus::Pending:\n                ++pending;\n                break;\n            case ItemStatus::NotApplicable:\n            default:\n                break;\n        }\n    }\n\n    const int total = static_cast<int>(stage_state.item_keys.size());\n    summary_label->setText(tr(\"Processed %1/%2  |  In progress: %3  |  Pending: %4\")\n                               .arg(processed)\n                               .arg(total)\n                               .arg(in_progress)\n                               .arg(pending));\n}\n\n\nvoid CategorizationProgressDialog::refresh_spinner()\n{\n    if (!has_in_progress_item()) {\n        if (spinner_timer) {\n            spinner_timer->stop();\n        }\n        return;\n    }\n\n    spinner_frame_index_ = (spinner_frame_index_ + 1) % 4;\n\n    for (const auto& [key, item] : item_states_) {\n        (void)key;\n        for (StageId stage_id : active_stage_order_) {\n            if (item.stage_statuses[stage_index(stage_id)] == ItemStatus::InProgress) {\n                refresh_row(item.row);\n                break;\n            }\n        }\n    }\n}\n\n\nbool CategorizationProgressDialog::has_in_progress_item() const\n{\n    for (const auto& [key, item] : item_states_) {\n        (void)key;\n        for (StageId stage_id : active_stage_order_) {\n            if (item.stage_statuses[stage_index(stage_id)] == ItemStatus::InProgress) {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\n\nvoid CategorizationProgressDialog::changeEvent(QEvent* event)\n{\n    QDialog::changeEvent(event);\n    if (event && event->type() == QEvent::LanguageChange) {\n        retranslate_ui();\n    }\n}\n\n\nvoid CategorizationProgressDialog::retranslate_ui()\n{\n    setWindowTitle(tr(\"Analyzing Files\"));\n    if (stop_button) {\n        stop_button->setText(tr(\"Stop Analysis\"));\n    }\n    if (log_label) {\n        log_label->setText(tr(\"Activity log\"));\n    }\n\n    rebuild_headers();\n    refresh_stage_overview();\n\n    for (const auto& [key, item] : item_states_) {\n        (void)key;\n        refresh_row(item.row);\n    }\n    refresh_summary();\n}\n"
  },
  {
    "path": "app/lib/CategorizationService.cpp",
    "content": "#include \"CategorizationService.hpp\"\n\n#include \"Settings.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"LLMErrors.hpp\"\n#include \"Utils.hpp\"\n\n#if __has_include(<jsoncpp/json/json.h>)\n#include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n#include <json/json.h>\n#else\n#error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <fmt/format.h>\n#include <spdlog/spdlog.h>\n\n#include <algorithm>\n#include <cctype>\n#include <chrono>\n#include <cstdlib>\n#include <future>\n#include <memory>\n#include <sstream>\n#include <thread>\n#include <vector>\n\nnamespace {\nconstexpr const char* kLocalTimeoutEnv = \"AI_FILE_SORTER_LOCAL_LLM_TIMEOUT\";\nconstexpr const char* kRemoteTimeoutEnv = \"AI_FILE_SORTER_REMOTE_LLM_TIMEOUT\";\nconstexpr const char* kCustomTimeoutEnv = \"AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT\";\nconstexpr size_t kMaxConsistencyHints = 5;\nconstexpr size_t kMaxLabelLength = 80;\nstd::string to_lower_copy_str(std::string value);\n\nstd::string trim_copy(std::string value) {\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space));\n    value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end());\n    return value;\n}\n\nstd::string collapse_spaces_copy(std::string value) {\n    std::string collapsed;\n    collapsed.reserve(value.size());\n    bool previous_space = false;\n    for (unsigned char ch : value) {\n        if (std::isspace(ch)) {\n            if (!previous_space) {\n                collapsed.push_back(' ');\n            }\n            previous_space = true;\n            continue;\n        }\n        collapsed.push_back(static_cast<char>(ch));\n        previous_space = false;\n    }\n    return trim_copy(std::move(collapsed));\n}\n\nstd::string strip_wrapping_punctuation(std::string value) {\n    auto is_wrapping = [](unsigned char ch) {\n        switch (ch) {\n            case '\"':\n            case '\\'':\n            case '`':\n            case '(':\n            case ')':\n            case '[':\n            case ']':\n            case '{':\n            case '}':\n            case '<':\n            case '>':\n                return true;\n            default:\n                return false;\n        }\n    };\n\n    while (!value.empty() && (std::isspace(static_cast<unsigned char>(value.front())) ||\n                              is_wrapping(static_cast<unsigned char>(value.front())))) {\n        value.erase(value.begin());\n    }\n    while (!value.empty() && (std::isspace(static_cast<unsigned char>(value.back())) ||\n                              is_wrapping(static_cast<unsigned char>(value.back())) ||\n                              value.back() == '.' || value.back() == ',' ||\n                              value.back() == ':' || value.back() == ';')) {\n        value.pop_back();\n    }\n    return value;\n}\n\nstd::string strip_trailing_parenthetical_gloss(std::string value) {\n    value = trim_copy(std::move(value));\n    while (true) {\n        const auto open = value.rfind(\" (\");\n        if (open == std::string::npos) {\n            break;\n        }\n\n        std::string gloss = trim_copy(value.substr(open + 2));\n        if (!gloss.empty() && gloss.back() == ')') {\n            gloss.pop_back();\n            gloss = trim_copy(std::move(gloss));\n        }\n\n        const bool has_alpha_chars = std::any_of(gloss.begin(), gloss.end(), [](unsigned char ch) {\n            return std::isalpha(ch);\n        });\n        if (!has_alpha_chars) {\n            break;\n        }\n\n        value = trim_copy(value.substr(0, open));\n    }\n    return value;\n}\n\nstd::size_t find_case_insensitive(const std::string& value, std::string_view needle) {\n    const std::string lower_value = to_lower_copy_str(value);\n    std::string lower_needle(needle);\n    std::transform(lower_needle.begin(), lower_needle.end(), lower_needle.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return lower_value.find(lower_needle);\n}\n\nstd::string strip_explanatory_suffix(std::string value) {\n    static const std::vector<std::string_view> markers = {\n        \" (based on\",\n        \" (note\",\n        \" (since\",\n        \" - this \",\n        \" - based on\",\n        \" because \",\n        \" based on \",\n        \" which \",\n        \" since \",\n        \" however \",\n        \" specifically \",\n        \" indicating \",\n        \" indicates \",\n        \" commonly \",\n        \" related to \"\n    };\n\n    std::size_t cut = std::string::npos;\n    for (const std::string_view marker : markers) {\n        const auto pos = find_case_insensitive(value, marker);\n        if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) {\n            cut = pos;\n        }\n    }\n    if (cut != std::string::npos) {\n        value.resize(cut);\n    }\n\n    return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value)));\n}\n\nstd::string extract_category_phrase(std::string value) {\n    struct PhrasePattern {\n        std::string_view prefix;\n        std::string_view suffix;\n    };\n    static const std::vector<PhrasePattern> patterns = {\n        {\"falls under the \", \" category\"},\n        {\"falls under \", \" category\"},\n        {\"belongs to the \", \" category\"},\n        {\"belongs to \", \" category\"},\n        {\"categorized as \", \"\"},\n        {\"classified as \", \"\"},\n        {\"category is \", \"\"},\n        {\"category would be \", \"\"}\n    };\n\n    const std::string lower = to_lower_copy_str(value);\n    for (const auto& pattern : patterns) {\n        const auto start = lower.find(pattern.prefix);\n        if (start == std::string::npos) {\n            continue;\n        }\n        const std::size_t content_start = start + pattern.prefix.size();\n        std::size_t content_end = value.size();\n        if (!pattern.suffix.empty()) {\n            content_end = lower.find(pattern.suffix, content_start);\n            if (content_end == std::string::npos || content_end <= content_start) {\n                continue;\n            }\n        }\n        return value.substr(content_start, content_end - content_start);\n    }\n    return value;\n}\n\nstd::string strip_inline_label_artifacts(std::string value, bool category_label) {\n    const std::vector<std::string_view> markers = category_label\n        ? std::vector<std::string_view>{\n              \", subcategory\",\n              \", sub category\",\n              \" - subcategory\",\n              \" - sub category\",\n              \"; subcategory\",\n              \"; sub category\",\n              \" subcategory:\",\n              \" sub category:\"\n          }\n        : std::vector<std::string_view>{\n              \", category\",\n              \", main category\",\n              \" - category\",\n              \" - main category\",\n              \"; category\",\n              \"; main category\",\n              \" category:\",\n              \" main category:\"\n          };\n\n    std::size_t cut = std::string::npos;\n    for (const std::string_view marker : markers) {\n        const auto pos = find_case_insensitive(value, marker);\n        if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) {\n            cut = pos;\n        }\n    }\n    if (cut != std::string::npos) {\n        value.resize(cut);\n    }\n\n    return trim_copy(std::move(value));\n}\n\nstd::string normalize_candidate_label(std::string value, bool category_label) {\n    value = strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(std::move(value))));\n    if (value.empty()) {\n        return value;\n    }\n    if (category_label) {\n        value = extract_category_phrase(std::move(value));\n    }\n    value = strip_explanatory_suffix(std::move(value));\n    value = strip_trailing_parenthetical_gloss(std::move(value));\n    value = strip_inline_label_artifacts(std::move(value), category_label);\n    return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value)));\n}\n\nstd::string strip_list_prefix(std::string line) {\n    line = trim_copy(std::move(line));\n    if (line.empty()) {\n        return line;\n    }\n\n    if ((line.front() == '-' || line.front() == '*') && line.size() > 1 &&\n        std::isspace(static_cast<unsigned char>(line[1]))) {\n        return trim_copy(line.substr(1));\n    }\n\n    size_t idx = 0;\n    while (idx < line.size() && std::isdigit(static_cast<unsigned char>(line[idx]))) {\n        ++idx;\n    }\n    if (idx > 0 && idx + 1 < line.size() &&\n        (line[idx] == '.' || line[idx] == ')') &&\n        std::isspace(static_cast<unsigned char>(line[idx + 1]))) {\n        return trim_copy(line.substr(idx + 1));\n    }\n\n    return line;\n}\n\nbool has_alpha(const std::string& value) {\n    return std::any_of(value.begin(), value.end(), [](unsigned char ch) {\n        return std::isalpha(ch);\n    });\n}\n\nbool is_heading_like_label(const std::string& value) {\n    const std::string lower = to_lower_copy_str(strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(value))));\n    static const std::vector<std::string> exact_matches = {\n        \"category\",\n        \"main category\",\n        \"subcategory\",\n        \"sub category\",\n        \"categorization\",\n        \"classification\",\n        \"result\",\n        \"answer\",\n        \"note\",\n        \"warning\",\n        \"disclaimer\",\n        \"reason\",\n        \"explanation\",\n        \"full path\",\n        \"file name\",\n        \"directory name\"\n    };\n    if (std::find(exact_matches.begin(), exact_matches.end(), lower) != exact_matches.end()) {\n        return true;\n    }\n    return lower.find(\"categorization\") != std::string::npos ||\n           lower.find(\"classification\") != std::string::npos;\n}\n\nstd::vector<std::string> split_segments(const std::string& line, std::string_view delimiter) {\n    std::vector<std::string> segments;\n    std::size_t start = 0;\n    while (start <= line.size()) {\n        const auto pos = line.find(delimiter, start);\n        const std::string segment = trim_copy(line.substr(start, pos == std::string::npos ? pos : pos - start));\n        if (!segment.empty()) {\n            segments.push_back(segment);\n        }\n        if (pos == std::string::npos) {\n            break;\n        }\n        start = pos + delimiter.size();\n    }\n    return segments;\n}\n\nstd::optional<std::string> extract_labeled_value(const std::string& line,\n                                                 std::initializer_list<std::string_view> labels,\n                                                 bool category_label) {\n    const auto colon = line.find(':');\n    if (colon == std::string::npos) {\n        return std::nullopt;\n    }\n\n    const std::string key = to_lower_copy_str(trim_copy(line.substr(0, colon)));\n    for (const std::string_view label : labels) {\n        if (key == label) {\n            const std::string value = normalize_candidate_label(line.substr(colon + 1), category_label);\n            if (!value.empty()) {\n                return value;\n            }\n            break;\n        }\n    }\n    return std::nullopt;\n}\n\nbool split_inline_pair(const std::string& line, std::string& category, std::string& subcategory) {\n    for (std::string_view delimiter : {std::string_view(\" : \"), std::string_view(\":\")}) {\n        const auto segments = split_segments(line, delimiter);\n        if (segments.size() < 2) {\n            continue;\n        }\n\n        for (std::size_t idx = segments.size() - 1; idx > 0; --idx) {\n            const std::string left = normalize_candidate_label(segments[idx - 1], true);\n            const std::string right = normalize_candidate_label(segments[idx], false);\n            if (left.size() < 2 || right.empty()) {\n                continue;\n            }\n            if (!has_alpha(left) || !has_alpha(right)) {\n                continue;\n            }\n            if (is_heading_like_label(left)) {\n                continue;\n            }\n            category = left;\n            subcategory = right;\n            return true;\n        }\n    }\n    return false;\n}\n\n// Splits common category/subcategory response variants and sanitizes the labels.\nstd::pair<std::string, std::string> split_category_subcategory(const std::string& input) {\n    std::vector<std::string> lines;\n    lines.reserve(4);\n\n    std::istringstream iss(input);\n    std::string line;\n    while (std::getline(iss, line)) {\n        std::string cleaned = strip_list_prefix(std::move(line));\n        if (!cleaned.empty()) {\n            lines.push_back(std::move(cleaned));\n        }\n    }\n\n    if (lines.empty()) {\n        std::string fallback = Utils::sanitize_path_label(trim_copy(input));\n        return {fallback, \"\"};\n    }\n\n    std::string category;\n    std::string subcategory;\n\n    for (const auto& entry : lines) {\n        if (category.empty()) {\n            if (auto value = extract_labeled_value(entry, {\"category\", \"main category\"}, true)) {\n                category = std::move(*value);\n            }\n        }\n        if (subcategory.empty()) {\n            if (auto value = extract_labeled_value(entry, {\"subcategory\", \"sub category\"}, false)) {\n                subcategory = std::move(*value);\n            }\n        }\n    }\n\n    if (category.empty() || subcategory.empty()) {\n        for (auto it = lines.rbegin(); it != lines.rend(); ++it) {\n            std::string parsed_category;\n            std::string parsed_subcategory;\n            if (!split_inline_pair(*it, parsed_category, parsed_subcategory)) {\n                continue;\n            }\n            if (category.empty()) {\n                category = std::move(parsed_category);\n            }\n            if (subcategory.empty()) {\n                subcategory = std::move(parsed_subcategory);\n            }\n            if (!category.empty() && !subcategory.empty()) {\n                break;\n            }\n        }\n    }\n\n    if (category.empty()) {\n        category = lines.front();\n    }\n\n    return {Utils::sanitize_path_label(category), Utils::sanitize_path_label(subcategory)};\n}\n\nstd::optional<std::pair<std::string, std::string>> parse_translated_category_response(const std::string& response) {\n    Json::Value root;\n    Json::CharReaderBuilder reader;\n    std::string errors;\n    std::istringstream stream(response);\n    if (Json::parseFromStream(reader, stream, &root, &errors) && root.isObject()) {\n        const std::string category = normalize_candidate_label(root.get(\"category\", \"\").asString(), true);\n        const std::string subcategory = normalize_candidate_label(root.get(\"subcategory\", \"\").asString(), false);\n        if (!category.empty()) {\n            return std::make_pair(Utils::sanitize_path_label(category),\n                                  Utils::sanitize_path_label(subcategory.empty() ? category : subcategory));\n        }\n    }\n\n    auto [category, subcategory] = split_category_subcategory(response);\n    if (category.empty()) {\n        return std::nullopt;\n    }\n    if (subcategory.empty()) {\n        subcategory = category;\n    }\n    return std::make_pair(category, subcategory);\n}\n\n// Returns a lowercase copy of the input string.\nstd::string to_lower_copy_str(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value;\n}\n\n// Returns true when the label contains only allowed characters.\nbool contains_only_allowed_chars(const std::string& value) {\n    for (unsigned char ch : value) {\n        if (std::iscntrl(ch)) {\n            return false;\n        }\n        static const std::string forbidden = R\"(<>:\"/\\|?*)\";\n        if (forbidden.find(static_cast<char>(ch)) != std::string::npos) {\n            return false;\n        }\n        // Everything else is allowed (including non-ASCII letters and punctuation).\n    }\n    return true;\n}\n\n// Returns true when the label has leading/trailing whitespace.\nbool has_leading_or_trailing_space_or_dot(const std::string& value) {\n    if (value.empty()) {\n        return false;\n    }\n    const unsigned char first = static_cast<unsigned char>(value.front());\n    const unsigned char last = static_cast<unsigned char>(value.back());\n    // Only guard leading/trailing whitespace; dots are allowed.\n    return std::isspace(first) || std::isspace(last);\n}\n\n// Returns true when the label matches a reserved Windows device name.\nbool is_reserved_windows_name(const std::string& value) {\n    static const std::vector<std::string> reserved = {\n        \"con\",\"prn\",\"aux\",\"nul\",\n        \"com1\",\"com2\",\"com3\",\"com4\",\"com5\",\"com6\",\"com7\",\"com8\",\"com9\",\n        \"lpt1\",\"lpt2\",\"lpt3\",\"lpt4\",\"lpt5\",\"lpt6\",\"lpt7\",\"lpt8\",\"lpt9\"\n    };\n    const std::string lower = to_lower_copy_str(value);\n    return std::find(reserved.begin(), reserved.end(), lower) != reserved.end();\n}\n\n// Returns true when the label looks like a file extension.\nbool looks_like_extension_label(const std::string& value) {\n    const auto dot_pos = value.rfind('.');\n    if (dot_pos == std::string::npos || dot_pos == value.size() - 1) {\n        return false;\n    }\n    const std::string ext = value.substr(dot_pos + 1);\n    if (ext.empty() || ext.size() > 5) {\n        return false;\n    }\n    return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); });\n}\n\n// Result for category/subcategory validation.\nstruct LabelValidationResult {\n    bool valid{false};\n    std::string error;\n};\n\n// Validates category/subcategory labels for length and invalid content.\nLabelValidationResult validate_labels(const std::string& category, const std::string& subcategory) {\n    if (category.empty() || subcategory.empty()) {\n        return {false, \"Category or subcategory is empty\"};\n    }\n    if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) {\n        return {false, \"Category or subcategory exceeds max length\"};\n    }\n    if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) {\n        return {false, \"Category or subcategory contains disallowed characters\"};\n    }\n    if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) {\n        return {false, \"Category or subcategory looks like a file extension\"};\n    }\n    if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) {\n        return {false, \"Category or subcategory is a reserved name\"};\n    }\n    if (has_leading_or_trailing_space_or_dot(category) || has_leading_or_trailing_space_or_dot(subcategory)) {\n        return {false, \"Category or subcategory has leading/trailing space or dot\"};\n    }\n    if (to_lower_copy_str(category) == to_lower_copy_str(subcategory)) {\n        return {false, \"Category and subcategory are identical\"};\n    }\n    return {true, {}};\n}\n\n}\n\nCategorizationService::CategorizationService(Settings& settings,\n                                             DatabaseManager& db_manager,\n                                             std::shared_ptr<spdlog::logger> core_logger)\n    : settings(settings),\n      db_manager(db_manager),\n      core_logger(std::move(core_logger)) {}\n\nbool CategorizationService::ensure_remote_credentials(std::string* error_message) const\n{\n    const LLMChoice choice = settings.get_llm_choice();\n    if (!is_remote_choice(choice)) {\n        return true;\n    }\n\n    if (choice == LLMChoice::Remote_Custom) {\n        const auto id = settings.get_active_custom_api_id();\n        const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id);\n        if (is_valid_custom_api_endpoint(endpoint)) {\n            return true;\n        }\n        if (core_logger) {\n            core_logger->error(\"Custom API endpoint selected but is missing required settings.\");\n        }\n        if (error_message) {\n            *error_message = \"Custom API endpoint is missing required settings. Please edit it in the Select LLM dialog.\";\n        }\n        return false;\n    }\n\n    const bool has_key = (choice == LLMChoice::Remote_OpenAI)\n        ? !settings.get_openai_api_key().empty()\n        : !settings.get_gemini_api_key().empty();\n    if (has_key) {\n        return true;\n    }\n\n    const char* provider = choice == LLMChoice::Remote_OpenAI ? \"OpenAI\" : \"Gemini\";\n    if (core_logger) {\n        core_logger->error(\"Remote LLM selected but {} API key is not configured.\", provider);\n    }\n    if (error_message) {\n        *error_message = fmt::format(\"Remote model credentials are missing. Enter your {} API key in the Select LLM dialog.\", provider);\n    }\n    return false;\n}\n\nstd::vector<CategorizedFile> CategorizationService::prune_empty_cached_entries(const std::string& directory_path)\n{\n    return db_manager.remove_empty_categorizations(directory_path);\n}\n\nstd::vector<CategorizedFile> CategorizationService::load_cached_entries(const std::string& directory_path) const\n{\n    auto cached = settings.get_include_subdirectories()\n        ? db_manager.get_categorized_files_recursive(directory_path)\n        : db_manager.get_categorized_files(directory_path);\n\n    const CategoryLanguage language = settings.get_category_language();\n    for (auto& entry : cached) {\n        entry = db_manager.localize_categorized_file(entry, language);\n    }\n    return cached;\n}\n\nstd::vector<CategorizedFile> CategorizationService::categorize_entries(\n    const std::vector<FileEntry>& files,\n    bool is_local_llm,\n    std::atomic<bool>& stop_flag,\n    const ProgressCallback& progress_callback,\n    const QueueCallback& queue_callback,\n    const CompletionCallback& completion_callback,\n    const RecategorizationCallback& recategorization_callback,\n    std::function<std::unique_ptr<ILLMClient>()> llm_factory,\n    const PromptOverrideProvider& prompt_override,\n    const SuggestedNameProvider& suggested_name_provider) const\n{\n    std::vector<CategorizedFile> categorized;\n    if (files.empty()) {\n        return categorized;\n    }\n    if (stop_flag.load()) {\n        return categorized;\n    }\n\n    auto llm = llm_factory ? llm_factory() : nullptr;\n    if (!llm) {\n        throw std::runtime_error(\"Failed to create LLM client.\");\n    }\n\n    categorized.reserve(files.size());\n    SessionHistoryMap session_history;\n\n    for (const auto& entry : files) {\n        if (stop_flag.load()) {\n            break;\n        }\n\n        if (queue_callback) {\n            queue_callback(entry);\n        }\n\n        const std::string suggested_name = suggested_name_provider\n            ? suggested_name_provider(entry)\n            : std::string();\n        const auto override_value = prompt_override ? prompt_override(entry) : std::nullopt;\n        if (auto categorized_entry = categorize_single_entry(*llm,\n                                                             is_local_llm,\n                                                             entry,\n                                                             override_value,\n                                                             suggested_name,\n                                                             stop_flag,\n                                                             progress_callback,\n                                                             recategorization_callback,\n                                                             session_history)) {\n            categorized.push_back(*categorized_entry);\n        }\n\n        if (completion_callback) {\n            completion_callback(entry);\n        }\n    }\n\n    return categorized;\n}\n\nstd::string CategorizationService::build_whitelist_context() const\n{\n    std::ostringstream oss;\n    const auto cats = settings.get_allowed_categories();\n    const auto subs = settings.get_allowed_subcategories();\n    if (!cats.empty()) {\n        oss << \"Allowed main categories (pick exactly one label from the numbered list):\\n\";\n        for (size_t i = 0; i < cats.size(); ++i) {\n            oss << (i + 1) << \") \" << cats[i] << \"\\n\";\n        }\n    }\n    if (!subs.empty()) {\n        oss << \"Allowed subcategories (pick exactly one label from the numbered list):\\n\";\n        for (size_t i = 0; i < subs.size(); ++i) {\n            oss << (i + 1) << \") \" << subs[i] << \"\\n\";\n        }\n    } else {\n        oss << \"Allowed subcategories: any (pick a specific, relevant subcategory; do not repeat the main category).\";\n    }\n    return oss.str();\n}\n\nstd::string CategorizationService::build_category_language_context() const\n{\n    const CategoryLanguage lang = settings.get_category_language();\n    if (lang == CategoryLanguage::English) {\n        return std::string();\n    }\n    const std::string name = categoryLanguageDisplay(lang);\n    return fmt::format(\n        \"Determine the canonical main category and subcategory in English only. \"\n        \"Do not translate, do not add bilingual text, do not use parentheses, and do not explain. \"\n        \"The final labels will be translated to {} later.\",\n        name);\n}\n\nnamespace {\n// Returns true when the value appears in the allowed list (case-insensitive).\nbool is_allowed(const std::string& value, const std::vector<std::string>& allowed) {\n    if (allowed.empty()) {\n        return true;\n    }\n    const std::string norm = to_lower_copy_str(value);\n    for (const auto& item : allowed) {\n        if (to_lower_copy_str(item) == norm) {\n            return true;\n        }\n    }\n    return false;\n}\n\n// Returns the first allowed entry or an empty string when the list is empty.\nstd::string first_allowed_or_blank(const std::vector<std::string>& allowed) {\n    return allowed.empty() ? std::string() : allowed.front();\n}\n} // namespace\n\nstd::optional<DatabaseManager::ResolvedCategory> CategorizationService::try_cached_categorization(\n    const std::string& item_name,\n    const std::string& current_path,\n    const std::string& categorization_path,\n    const std::string& dir_path,\n    FileType file_type,\n    const ProgressCallback& progress_callback) const\n{\n    const auto cached = db_manager.get_categorization_from_db(dir_path, item_name, file_type);\n    if (cached.size() < 2) {\n        return std::nullopt;\n    }\n\n    const std::string sanitized_category = Utils::sanitize_path_label(cached[0]);\n    const std::string sanitized_subcategory = Utils::sanitize_path_label(cached[1]);\n    if (sanitized_category.empty() || sanitized_subcategory.empty()) {\n        if (core_logger) {\n            core_logger->warn(\"Ignoring cached categorization with empty values for '{}'\", item_name);\n        }\n        return std::nullopt;\n    }\n    const auto validation = validate_labels(sanitized_category, sanitized_subcategory);\n    if (!validation.valid) {\n        if (core_logger) {\n            core_logger->warn(\"Ignoring cached categorization for '{}' due to validation error: {} (cat='{}', sub='{}')\",\n                              item_name,\n                              validation.error,\n                              sanitized_category,\n                              sanitized_subcategory);\n        }\n        return std::nullopt;\n    }\n\n    (void)item_name;\n    (void)current_path;\n    (void)categorization_path;\n    (void)progress_callback;\n    return db_manager.resolve_category(sanitized_category, sanitized_subcategory);\n}\n\nbool CategorizationService::ensure_remote_credentials_for_request(\n    const std::string& item_name,\n    const ProgressCallback& progress_callback) const\n{\n    if (!is_remote_choice(settings.get_llm_choice())) {\n        return true;\n    }\n\n    const LLMChoice choice = settings.get_llm_choice();\n    if (choice == LLMChoice::Remote_Custom) {\n        const auto id = settings.get_active_custom_api_id();\n        const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id);\n        if (is_valid_custom_api_endpoint(endpoint)) {\n            return true;\n        }\n        const std::string err_msg = fmt::format(\"[REMOTE] {} (missing custom API settings)\", item_name);\n        if (progress_callback) {\n            progress_callback(err_msg);\n        }\n        if (core_logger) {\n            core_logger->error(\"{}\", err_msg);\n        }\n        return false;\n    }\n\n    const bool has_key = (choice == LLMChoice::Remote_OpenAI)\n        ? !settings.get_openai_api_key().empty()\n        : !settings.get_gemini_api_key().empty();\n    if (has_key) {\n        return true;\n    }\n\n    const std::string provider = choice == LLMChoice::Remote_OpenAI ? \"OpenAI\" : \"Gemini\";\n    const std::string err_msg = fmt::format(\"[REMOTE] {} (missing {} API key)\", item_name, provider);\n    if (progress_callback) {\n        progress_callback(err_msg);\n    }\n    if (core_logger) {\n        core_logger->error(\"{}\", err_msg);\n    }\n    return false;\n}\n\nDatabaseManager::ResolvedCategory CategorizationService::categorize_via_llm(\n    ILLMClient& llm,\n    bool is_local_llm,\n    const std::string& display_name,\n    const std::string& display_path,\n    const std::string& prompt_name,\n    const std::string& prompt_path,\n    FileType file_type,\n    const ProgressCallback& progress_callback,\n    const std::string& consistency_context) const\n{\n    try {\n        const std::string category_subcategory =\n            run_llm_with_timeout(llm, prompt_name, prompt_path, file_type, is_local_llm, consistency_context);\n\n        auto [category, subcategory] = split_category_subcategory(category_subcategory);\n        auto resolved = db_manager.resolve_category(category, subcategory);\n        if (settings.get_use_whitelist()) {\n            const auto allowed_categories = settings.get_allowed_categories();\n            const auto allowed_subcategories = settings.get_allowed_subcategories();\n            if (!is_allowed(resolved.category, allowed_categories)) {\n                resolved.category = first_allowed_or_blank(allowed_categories);\n            }\n            if (!is_allowed(resolved.subcategory, allowed_subcategories)) {\n                resolved.subcategory = first_allowed_or_blank(allowed_subcategories);\n            }\n        }\n        const auto validation = validate_labels(resolved.category, resolved.subcategory);\n        if (!validation.valid) {\n            if (progress_callback) {\n                progress_callback(fmt::format(\"[LLM-ERROR] {} (invalid category/subcategory: {})\",\n                                              display_name,\n                                              validation.error));\n            }\n            if (core_logger) {\n                core_logger->warn(\"Invalid LLM output for '{}': {} (cat='{}', sub='{}')\",\n                                  display_name,\n                                  validation.error,\n                                  resolved.category,\n                                  resolved.subcategory);\n            }\n            return DatabaseManager::ResolvedCategory{-1, \"\", \"\"};\n        }\n        if (resolved.category.empty()) {\n            resolved.category = \"Uncategorized\";\n        }\n        const auto display_resolved = localize_resolved_category(llm, resolved);\n        emit_progress_message(progress_callback, \"AI\", display_name, display_resolved, display_path, prompt_path);\n        return resolved;\n    } catch (const std::exception& ex) {\n        const std::string err_msg = fmt::format(\"[LLM-ERROR] {} ({})\", display_name, ex.what());\n        if (progress_callback) {\n            progress_callback(err_msg);\n        }\n        if (core_logger) {\n            core_logger->error(\"LLM error while categorizing '{}': {}\", display_name, ex.what());\n        }\n        throw;\n    }\n}\n\nvoid CategorizationService::emit_progress_message(const ProgressCallback& progress_callback,\n                                                  std::string_view source,\n                                                  const std::string& item_name,\n                                                  const DatabaseManager::ResolvedCategory& resolved,\n                                                  const std::string& current_path,\n                                                  const std::string& categorization_path) const\n{\n    if (!progress_callback) {\n        return;\n    }\n    const std::string sub = resolved.subcategory.empty() ? \"-\" : resolved.subcategory;\n    const std::string current_path_display = current_path.empty() ? \"-\" : current_path;\n    const std::string categorization_path_display =\n        categorization_path.empty() ? current_path_display : categorization_path;\n\n    progress_callback(fmt::format(\n        \"[{}] {}\\n\"\n        \"    Category            : {}\\n\"\n        \"    Subcat              : {}\\n\"\n        \"    Current Path        : {}\\n\"\n        \"    Categorization Path : {}\",\n        source, item_name, resolved.category, sub, current_path_display, categorization_path_display));\n}\n\nDatabaseManager::ResolvedCategory CategorizationService::categorize_with_cache(\n    ILLMClient& llm,\n    bool is_local_llm,\n    const std::string& display_name,\n    const std::string& display_path,\n    const std::string& dir_path,\n    const std::string& prompt_name,\n    const std::string& prompt_path,\n    FileType file_type,\n    const ProgressCallback& progress_callback,\n    const std::string& consistency_context) const\n{\n    if (auto cached = try_cached_categorization(display_name,\n                                                display_path,\n                                                prompt_path,\n                                                dir_path,\n                                                file_type,\n                                                progress_callback)) {\n        const auto display_resolved = localize_resolved_category(llm, *cached);\n        emit_progress_message(progress_callback, \"CACHE\", display_name, display_resolved, display_path, prompt_path);\n        return *cached;\n    }\n\n    if (!is_local_llm && !ensure_remote_credentials_for_request(display_name, progress_callback)) {\n        return DatabaseManager::ResolvedCategory{-1, \"\", \"\"};\n    }\n\n    return categorize_via_llm(llm,\n                              is_local_llm,\n                              display_name,\n                              display_path,\n                              prompt_name,\n                              prompt_path,\n                              file_type,\n                              progress_callback,\n                              consistency_context);\n}\n\nstd::optional<CategorizedFile> CategorizationService::categorize_single_entry(\n    ILLMClient& llm,\n    bool is_local_llm,\n    const FileEntry& entry,\n    const std::optional<PromptOverride>& prompt_override,\n    const std::string& suggested_name,\n    std::atomic<bool>& stop_flag,\n    const ProgressCallback& progress_callback,\n    const RecategorizationCallback& recategorization_callback,\n    SessionHistoryMap& session_history) const\n{\n    (void)stop_flag;\n\n    const std::filesystem::path entry_path = Utils::utf8_to_path(entry.full_path);\n    const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path());\n    const std::string display_path = Utils::abbreviate_user_path(entry.full_path);\n    const std::string prompt_name = prompt_override ? prompt_override->name : entry.file_name;\n    const std::string prompt_path = prompt_override ? prompt_override->path : entry.full_path;\n    const std::string prompt_path_display = Utils::abbreviate_user_path(prompt_path);\n    const bool use_consistency_hints = settings.get_use_consistency_hints();\n    const std::string extension = extract_extension(entry.file_name);\n    const std::string signature = make_file_signature(entry.type, extension);\n    std::string hint_block;\n    if (use_consistency_hints) {\n        const auto hints = collect_consistency_hints(signature, session_history, extension, entry.type);\n        hint_block = format_hint_block(hints);\n    }\n    const std::string combined_context = build_combined_context(hint_block);\n\n    DatabaseManager::ResolvedCategory resolved;\n    bool retried_after_backoff = false;\n    while (true) {\n        try {\n            resolved = run_categorization_with_cache(llm,\n                                                     is_local_llm,\n                                                     entry,\n                                                     display_path,\n                                                     dir_path,\n                                                     prompt_name,\n                                                     prompt_path_display,\n                                                     progress_callback,\n                                                     combined_context);\n            break;\n        } catch (const BackoffError& backoff) {\n            const int wait_seconds = backoff.retry_after_seconds() > 0 ? backoff.retry_after_seconds() : 60;\n            if (progress_callback) {\n                progress_callback(fmt::format(\n                    \"[REMOTE] Rate limit hit. Waiting {}s before retrying {}...\",\n                    wait_seconds,\n                    entry.file_name));\n            }\n            if (core_logger) {\n                core_logger->warn(\"Rate limit hit for '{}'; retrying in {}s\", entry.file_name, wait_seconds);\n            }\n            for (int remaining = wait_seconds; remaining > 0; --remaining) {\n                if (stop_flag.load()) {\n                    return std::nullopt;\n                }\n                if (progress_callback && (remaining % 10 == 0 || remaining <= 3)) {\n                    progress_callback(fmt::format(\"[REMOTE] Retrying {} in {}s...\", entry.file_name, remaining));\n                }\n                std::this_thread::sleep_for(std::chrono::seconds(1));\n            }\n            if (retried_after_backoff) {\n                throw;\n            }\n            retried_after_backoff = true;\n        }\n    }\n\n    if (auto retry = handle_empty_result(entry,\n                                         dir_path,\n                                         resolved,\n                                         use_consistency_hints,\n                                         is_local_llm,\n                                         recategorization_callback)) {\n        return retry;\n    }\n\n    update_storage_with_result(entry,\n                               dir_path,\n                               resolved,\n                               use_consistency_hints,\n                               suggested_name,\n                               session_history);\n\n    const auto display_resolved = db_manager.localize_category(resolved, settings.get_category_language());\n    CategorizedFile result{dir_path, entry.file_name, entry.type,\n                           display_resolved.category, display_resolved.subcategory, resolved.taxonomy_id};\n    result.used_consistency_hints = use_consistency_hints;\n    result.suggested_name = suggested_name;\n    result.canonical_category = resolved.category;\n    result.canonical_subcategory = resolved.subcategory;\n    return result;\n}\n\nstd::string CategorizationService::build_combined_context(const std::string& hint_block) const\n{\n    std::string combined_context;\n    const std::string whitelist_block = build_whitelist_context();\n    const std::string language_block = build_category_language_context();\n    if (!language_block.empty()) {\n        combined_context += language_block;\n    }\n    if (settings.get_use_whitelist() && !whitelist_block.empty()) {\n        if (core_logger) {\n            core_logger->debug(\"Applying category whitelist ({} cats, {} subs)\",\n                               settings.get_allowed_categories().size(),\n                               settings.get_allowed_subcategories().size());\n        }\n        if (!combined_context.empty()) {\n            combined_context += \"\\n\\n\";\n        }\n        combined_context += whitelist_block;\n    }\n    if (!hint_block.empty()) {\n        if (!combined_context.empty()) {\n            combined_context += \"\\n\\n\";\n        }\n        combined_context += hint_block;\n    }\n    return combined_context;\n}\n\nDatabaseManager::ResolvedCategory CategorizationService::localize_resolved_category(\n    ILLMClient& llm,\n    const DatabaseManager::ResolvedCategory& resolved) const\n{\n    const CategoryLanguage language = settings.get_category_language();\n    if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0) {\n        return resolved;\n    }\n\n    if (!db_manager.get_category_translation(resolved.taxonomy_id, language)) {\n        if (const auto translated = translate_resolved_category(llm, resolved)) {\n            db_manager.upsert_category_translation(resolved.taxonomy_id,\n                                                  language,\n                                                  translated->category,\n                                                  translated->subcategory);\n        }\n    }\n\n    return db_manager.localize_category(resolved, language);\n}\n\nstd::optional<DatabaseManager::ResolvedCategory> CategorizationService::translate_resolved_category(\n    ILLMClient& llm,\n    const DatabaseManager::ResolvedCategory& resolved) const\n{\n    const CategoryLanguage language = settings.get_category_language();\n    if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0 ||\n        resolved.category.empty() || resolved.subcategory.empty()) {\n        return std::nullopt;\n    }\n\n    const std::string language_name = categoryLanguageDisplay(language);\n    const std::string prompt = fmt::format(\n        \"Translate the following taxonomy labels into {}.\\n\"\n        \"Return only JSON in this exact shape: {{\\\"category\\\":\\\"...\\\",\\\"subcategory\\\":\\\"...\\\"}}\\n\"\n        \"Rules:\\n\"\n        \"- Keep the meaning precise.\\n\"\n        \"- No English.\\n\"\n        \"- No parentheses.\\n\"\n        \"- No explanations.\\n\"\n        \"- No trailing periods.\\n\"\n        \"- Keep the main category broad and concise.\\n\"\n        \"- Keep the subcategory specific and concise.\\n\\n\"\n        \"category: {}\\n\"\n        \"subcategory: {}\",\n        language_name,\n        resolved.category,\n        resolved.subcategory);\n\n    try {\n        const std::string response = llm.complete_prompt(prompt, 128);\n        const auto translated = parse_translated_category_response(response);\n        if (!translated) {\n            return std::nullopt;\n        }\n\n        DatabaseManager::ResolvedCategory translated_resolved{\n            resolved.taxonomy_id,\n            translated->first,\n            translated->second\n        };\n        const auto validation = validate_labels(translated_resolved.category, translated_resolved.subcategory);\n        if (!validation.valid) {\n            if (core_logger) {\n                core_logger->warn(\"Ignoring invalid translated category pair for taxonomy {}: {} (cat='{}', sub='{}')\",\n                                  resolved.taxonomy_id,\n                                  validation.error,\n                                  translated_resolved.category,\n                                  translated_resolved.subcategory);\n            }\n            return std::nullopt;\n        }\n        return translated_resolved;\n    } catch (const std::exception& ex) {\n        if (core_logger) {\n            core_logger->warn(\"Category translation failed for taxonomy {} to {}: {}\",\n                              resolved.taxonomy_id,\n                              language_name,\n                              ex.what());\n        }\n        return std::nullopt;\n    }\n}\n\nDatabaseManager::ResolvedCategory CategorizationService::run_categorization_with_cache(\n    ILLMClient& llm,\n    bool is_local_llm,\n    const FileEntry& entry,\n    const std::string& display_path,\n    const std::string& dir_path,\n    const std::string& prompt_name,\n    const std::string& prompt_path,\n    const ProgressCallback& progress_callback,\n    const std::string& combined_context) const\n{\n    return categorize_with_cache(llm,\n                                 is_local_llm,\n                                 entry.file_name,\n                                 display_path,\n                                 dir_path,\n                                 prompt_name,\n                                 prompt_path,\n                                 entry.type,\n                                 progress_callback,\n                                 combined_context);\n}\n\nstd::optional<CategorizedFile> CategorizationService::handle_empty_result(\n    const FileEntry& entry,\n    const std::string& dir_path,\n    const DatabaseManager::ResolvedCategory& resolved,\n    bool used_consistency_hints,\n    bool is_local_llm,\n    const RecategorizationCallback& recategorization_callback) const\n{\n    const bool invalid = resolved.taxonomy_id == -1;\n    if (!resolved.category.empty() && !resolved.subcategory.empty() && !invalid) {\n        return std::nullopt;\n    }\n\n    const std::string reason = invalid\n        ? \"Categorization returned invalid category/subcategory and was skipped.\"\n        : \"Categorization returned no result.\";\n\n    if (core_logger) {\n        core_logger->warn(\"{} for '{}'.\", reason, entry.file_name);\n    }\n\n    db_manager.remove_file_categorization(dir_path, entry.file_name, entry.type);\n\n    if (recategorization_callback) {\n        CategorizedFile retry_entry{dir_path,\n                                    entry.file_name,\n                                    entry.type,\n                                    resolved.category,\n                                    resolved.subcategory,\n                                    resolved.taxonomy_id};\n        retry_entry.used_consistency_hints = used_consistency_hints;\n        recategorization_callback(retry_entry, reason);\n    }\n    return std::nullopt;\n}\n\nvoid CategorizationService::update_storage_with_result(const FileEntry& entry,\n                                                       const std::string& dir_path,\n                                                       const DatabaseManager::ResolvedCategory& resolved,\n                                                       bool used_consistency_hints,\n                                                       const std::string& suggested_name,\n                                                       SessionHistoryMap& session_history) const\n{\n    if (core_logger) {\n        core_logger->info(\"Categorized '{}' as '{} / {}'.\",\n                          entry.file_name,\n                          resolved.category,\n                          resolved.subcategory.empty() ? \"<none>\" : resolved.subcategory);\n    }\n\n    db_manager.insert_or_update_file_with_categorization(\n        entry.file_name,\n        entry.type == FileType::File ? \"F\" : \"D\",\n        dir_path,\n        resolved,\n        used_consistency_hints,\n        suggested_name);\n\n    const std::string signature = make_file_signature(entry.type, extract_extension(entry.file_name));\n    if (!signature.empty()) {\n        record_session_assignment(session_history[signature], {resolved.category, resolved.subcategory});\n    }\n}\n\nstd::string CategorizationService::run_llm_with_timeout(\n    ILLMClient& llm,\n    const std::string& item_name,\n    const std::string& item_path,\n    FileType file_type,\n    bool is_local_llm,\n    const std::string& consistency_context) const\n{\n    const int timeout_seconds = resolve_llm_timeout(is_local_llm);\n\n    auto future = start_llm_future(llm, item_name, item_path, file_type, consistency_context);\n\n    if (future.wait_for(std::chrono::seconds(timeout_seconds)) == std::future_status::timeout) {\n        throw std::runtime_error(\"Timed out waiting for LLM response\");\n    }\n\n    return future.get();\n}\n\nint CategorizationService::resolve_llm_timeout(bool is_local_llm) const\n{\n    int timeout_seconds = is_local_llm ? 60 : 10;\n    const char* timeout_env = std::getenv(is_local_llm ? kLocalTimeoutEnv : kRemoteTimeoutEnv);\n    if (!is_local_llm && settings.get_llm_choice() == LLMChoice::Remote_Custom) {\n        timeout_seconds = 60;\n        timeout_env = std::getenv(kCustomTimeoutEnv);\n    }\n    if (!timeout_env || *timeout_env == '\\0') {\n        return timeout_seconds;\n    }\n\n    try {\n        const int parsed = std::stoi(timeout_env);\n        if (parsed > 0) {\n            timeout_seconds = parsed;\n        } else if (core_logger) {\n            core_logger->warn(\"Ignoring non-positive LLM timeout '{}'\", timeout_env);\n        }\n    } catch (const std::exception& ex) {\n        if (core_logger) {\n            core_logger->warn(\"Failed to parse LLM timeout '{}': {}\", timeout_env, ex.what());\n        }\n    }\n\n    if (core_logger) {\n        core_logger->debug(\"Using {} LLM timeout of {} second(s)\",\n                           is_local_llm ? \"local\" : \"remote\",\n                           timeout_seconds);\n    }\n\n    return timeout_seconds;\n}\n\nstd::future<std::string> CategorizationService::start_llm_future(\n    ILLMClient& llm,\n    const std::string& item_name,\n    const std::string& item_path,\n    FileType file_type,\n    const std::string& consistency_context) const\n{\n    auto promise = std::make_shared<std::promise<std::string>>();\n    std::future<std::string> future = promise->get_future();\n\n    std::thread([&llm, promise, item_name, item_path, file_type, consistency_context]() mutable {\n        try {\n            promise->set_value(llm.categorize_file(item_name, item_path, file_type, consistency_context));\n        } catch (...) {\n            try {\n                promise->set_exception(std::current_exception());\n            } catch (...) {\n                // no-op\n            }\n        }\n    }).detach();\n\n    return future;\n}\n\nstd::vector<CategorizationService::CategoryPair> CategorizationService::collect_consistency_hints(\n    const std::string& signature,\n    const SessionHistoryMap& session_history,\n    const std::string& extension,\n    FileType file_type) const\n{\n    std::vector<CategoryPair> hints;\n    if (signature.empty()) {\n        return hints;\n    }\n\n    if (auto it = session_history.find(signature); it != session_history.end()) {\n        for (const auto& entry : it->second) {\n            if (append_unique_hint(hints, entry) && hints.size() == kMaxConsistencyHints) {\n                return hints;\n            }\n        }\n    }\n\n    if (hints.size() < kMaxConsistencyHints) {\n        const size_t remaining = kMaxConsistencyHints - hints.size();\n        const auto db_hints = db_manager.get_recent_categories_for_extension(extension, file_type, remaining);\n        for (const auto& entry : db_hints) {\n            if (append_unique_hint(hints, entry) && hints.size() == kMaxConsistencyHints) {\n                break;\n            }\n        }\n    }\n\n    return hints;\n}\n\nstd::string CategorizationService::make_file_signature(FileType file_type, const std::string& extension)\n{\n    const std::string type_tag = (file_type == FileType::Directory) ? \"DIR\" : \"FILE\";\n    const std::string normalized_extension = extension.empty() ? std::string(\"<none>\") : extension;\n    return type_tag + \":\" + normalized_extension;\n}\n\nstd::string CategorizationService::extract_extension(const std::string& file_name)\n{\n    const auto pos = file_name.find_last_of('.');\n    if (pos == std::string::npos || pos + 1 >= file_name.size()) {\n        return std::string();\n    }\n    std::string ext = file_name.substr(pos);\n    std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return ext;\n}\n\nbool CategorizationService::append_unique_hint(std::vector<CategoryPair>& target, const CategoryPair& candidate)\n{\n    CategoryPair normalized{Utils::sanitize_path_label(candidate.first), Utils::sanitize_path_label(candidate.second)};\n    if (normalized.first.empty()) {\n        return false;\n    }\n    if (normalized.second.empty()) {\n        normalized.second = normalized.first;\n    }\n    for (const auto& existing : target) {\n        if (existing.first == normalized.first && existing.second == normalized.second) {\n            return false;\n        }\n    }\n    target.push_back(std::move(normalized));\n    return true;\n}\n\nvoid CategorizationService::record_session_assignment(HintHistory& history, const CategoryPair& assignment)\n{\n    CategoryPair normalized{Utils::sanitize_path_label(assignment.first), Utils::sanitize_path_label(assignment.second)};\n    if (normalized.first.empty()) {\n        return;\n    }\n    if (normalized.second.empty()) {\n        normalized.second = normalized.first;\n    }\n\n    history.erase(std::remove(history.begin(), history.end(), normalized), history.end());\n    history.push_front(normalized);\n    if (history.size() > kMaxConsistencyHints) {\n        history.pop_back();\n    }\n}\n\nstd::string CategorizationService::format_hint_block(const std::vector<CategoryPair>& hints) const\n{\n    if (hints.empty()) {\n        return std::string();\n    }\n\n    std::ostringstream oss;\n    oss << \"Recent assignments for similar items:\\n\";\n    for (const auto& hint : hints) {\n        const std::string sub = hint.second.empty() ? hint.first : hint.second;\n        oss << \"- \" << hint.first << \" : \" << sub << \"\\n\";\n    }\n    oss << \"Prefer one of the above when it fits; otherwise, choose the closest consistent alternative.\";\n    return oss.str();\n}\n"
  },
  {
    "path": "app/lib/CategorizationSession.cpp",
    "content": "#include \"CategorizationSession.hpp\"\n\n#include <algorithm>\n#include <utility>\n\n\nCategorizationSession::CategorizationSession(std::string api_key, std::string model, std::string base_url)\n    : key(std::move(api_key)),\n      model(std::move(model)),\n      base_url(std::move(base_url))\n{\n}\n\n\nCategorizationSession::~CategorizationSession()\n{\n    // Securely clear key memory\n    std::fill(key.begin(), key.end(), '\\0');\n}\n\n\nLLMClient CategorizationSession::create_llm_client() const\n{\n    return LLMClient(key, model, base_url);\n}\n"
  },
  {
    "path": "app/lib/ConsistencyPassService.cpp",
    "content": "#include \"ConsistencyPassService.hpp\"\n\n#include \"ILLMClient.hpp\"\n\n#include <fmt/format.h>\n\n#include <spdlog/spdlog.h>\n\n#if __has_include(<jsoncpp/json/json.h>)\n#include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n#include <json/json.h>\n#else\n#error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <algorithm>\n#include <exception>\n#include <filesystem>\n#include <iostream>\n#include <optional>\n#include <sstream>\n#include <unordered_map>\n\nnamespace {\n\nstd::string trim_whitespace(const std::string& value) {\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    const auto start = value.find_first_not_of(whitespace);\n    const auto end = value.find_last_not_of(whitespace);\n    if (start == std::string::npos || end == std::string::npos) {\n        return std::string();\n    }\n    return value.substr(start, end - start + 1);\n}\n\nbool try_parse_harmonized_entry(const std::string& line,\n                                size_t line_number,\n                                const std::string& raw_line,\n                                Json::Value& entry,\n                                const std::shared_ptr<spdlog::logger>& logger)\n{\n    const auto arrow_pos = line.find(\"=>\");\n    if (arrow_pos == std::string::npos) {\n        return false;\n    }\n\n    std::string id = trim_whitespace(line.substr(0, arrow_pos));\n    std::string remainder = trim_whitespace(line.substr(arrow_pos + 2));\n    const auto colon_pos = remainder.find(':');\n    if (colon_pos == std::string::npos) {\n        return false;\n    }\n\n    std::string category = trim_whitespace(remainder.substr(0, colon_pos));\n    std::string subcategory = trim_whitespace(remainder.substr(colon_pos + 1));\n    if (subcategory.empty()) {\n        subcategory = category;\n    }\n\n    if (id.empty() || category.empty()) {\n        if (logger) {\n            logger->warn(\"Consistency pass skipped malformed line {}: '{}'\", line_number, raw_line);\n        }\n        return false;\n    }\n\n    entry = Json::Value(Json::objectValue);\n    entry[\"id\"] = id;\n    entry[\"category\"] = category;\n    entry[\"subcategory\"] = subcategory;\n    return true;\n}\n\nstd::string make_item_key(const CategorizedFile& item) {\n    std::filesystem::path path(item.file_path);\n    path /= item.file_name;\n    return path.generic_string();\n}\n\nstd::string canonical_category_text(const CategorizedFile& item) {\n    return item.canonical_category.empty() ? item.category : item.canonical_category;\n}\n\nstd::string canonical_subcategory_text(const CategorizedFile& item) {\n    return item.canonical_subcategory.empty() ? item.subcategory : item.canonical_subcategory;\n}\n\nstd::unordered_map<std::string, CategorizedFile*> build_items_by_key(std::vector<CategorizedFile>& items) {\n    std::unordered_map<std::string, CategorizedFile*> map;\n    map.reserve(items.size());\n    for (auto& item : items) {\n        map[make_item_key(item)] = &item;\n    }\n    return map;\n}\n\nstd::string build_consistency_prompt(\n    const std::vector<const CategorizedFile*>& chunk,\n    const std::vector<std::pair<std::string, std::string>>& taxonomy)\n{\n    Json::Value taxonomy_json(Json::arrayValue);\n    for (const auto& entry : taxonomy) {\n        Json::Value obj;\n        obj[\"category\"] = entry.first;\n        obj[\"subcategory\"] = entry.second;\n        taxonomy_json.append(obj);\n    }\n\n    std::ostringstream prompt;\n    prompt << \"You are a taxonomy normalization assistant.\\n\";\n    prompt << \"Your task is to review existing (category, subcategory) assignments for files and make them consistent.\\n\";\n    prompt << \"Guidelines:\\n\";\n    prompt << \"1. Prefer using the known taxonomy entries when they closely match.\\n\";\n    prompt << \"2. Merge near-duplicate labels (e.g. 'Docs' vs 'Documents'), but do not collapse distinct concepts.\\n\";\n    prompt << \"3. Preserve the intent of each file. If a category/subcategory already looks appropriate, keep it.\\n\";\n    prompt << \"4. Always provide both category and subcategory strings.\\n\";\n    prompt << \"5. Respond with one line per item using the exact format: <id> => <Category> : <Subcategory>.\\n\";\n    prompt << \"6. The <id> must be copied verbatim from the list below (full path). No other text may appear before it.\\n\";\n    prompt << \"7. Keep the output order identical to the input and finish by writing END on its own line. No other prose.\\n\\n\";\n\n    Json::StreamWriterBuilder builder;\n    builder[\"indentation\"] = \"\";\n    const std::string taxonomy_str = Json::writeString(builder, taxonomy_json);\n    prompt << \"Known taxonomy entries (JSON array): \" << taxonomy_str << \"\\n\\n\";\n\n    prompt << \"Items to harmonize (follow the input order in your response):\\n\";\n    for (const auto* item : chunk) {\n        if (!item) {\n            continue;\n        }\n        prompt << \"- id: \" << make_item_key(*item)\n               << \", file: \" << item->file_name\n               << \", current: \" << canonical_category_text(*item)\n               << \" / \" << canonical_subcategory_text(*item) << \"\\n\";\n    }\n\n    prompt << \"Example response lines:\\n\";\n    prompt << \"/home/user/Downloads/setup.exe => Applications : Installers\\n\";\n    prompt << \"/home/user/Documents/taxes.pdf => Documents : Tax forms\\n\";\n    prompt << \"END\";\n\n    return prompt.str();\n}\n\nbool parse_structured_lines(\n    const std::string& response,\n    Json::Value& root,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    Json::Value harmonized(Json::arrayValue);\n    std::istringstream stream(response);\n    std::string raw_line;\n    size_t line_number = 0;\n\n    while (std::getline(stream, raw_line)) {\n        ++line_number;\n        std::string line = trim_whitespace(raw_line);\n        if (line.empty()) {\n            continue;\n        }\n        if (line == \"END\") {\n            break;\n        }\n\n        Json::Value entry(Json::objectValue);\n        if (try_parse_harmonized_entry(line, line_number, raw_line, entry, logger)) {\n            harmonized.append(entry);\n        }\n    }\n\n    if (harmonized.empty()) {\n        if (logger) {\n            logger->warn(\"Consistency pass parsed zero harmonized entries from line-based response\");\n        }\n        return false;\n    }\n\n    root = harmonized;\n    return true;\n}\n\nconst Json::Value* parse_structured_fallback(\n    const std::string& response,\n    Json::Value& root,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    return parse_structured_lines(response, root, logger) ? &root : nullptr;\n}\n\nconst Json::Value* extract_harmonized_array(Json::Value& root)\n{\n    if (root.isObject() && root.isMember(\"harmonized\")) {\n        const Json::Value& harmonized = root[\"harmonized\"];\n        if (harmonized.isArray()) {\n            return &harmonized;\n        }\n        return nullptr;\n    }\n    if (root.isArray()) {\n        return &root;\n    }\n    return nullptr;\n}\n\nstruct HarmonizedUpdate {\n    std::string id;\n    CategorizedFile* target{nullptr};\n    std::string category;\n    std::string subcategory;\n};\n\nstd::optional<HarmonizedUpdate> extract_harmonized_update(\n    const Json::Value& entry,\n    std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (!entry.isObject()) {\n        return std::nullopt;\n    }\n\n    const std::string id = entry.get(\"id\", \"\").asString();\n    if (id.empty()) {\n        return std::nullopt;\n    }\n\n    auto it = items_by_key.find(id);\n    if (it == items_by_key.end() || !it->second) {\n        if (logger) {\n            logger->warn(\"Consistency pass referenced unknown item id '{}'\", id);\n        }\n        return std::nullopt;\n    }\n\n    CategorizedFile* target = it->second;\n    const auto trim_or_fallback = [](const Json::Value& parent,\n                                     const char* key,\n                                     const std::string& fallback) {\n        if (!parent.isMember(key)) {\n            return fallback;\n        }\n        std::string candidate = parent[key].asString();\n        if (candidate.empty()) {\n            return fallback;\n        }\n        candidate = trim_whitespace(std::move(candidate));\n        return candidate.empty() ? fallback : candidate;\n    };\n\n    std::string category = trim_or_fallback(entry, \"category\", canonical_category_text(*target));\n    if (category.empty()) {\n        category = canonical_category_text(*target);\n    }\n\n    std::string subcategory = trim_or_fallback(entry, \"subcategory\", canonical_subcategory_text(*target));\n    if (!entry.isMember(\"subcategory\") || subcategory.empty()) {\n        subcategory = category;\n    }\n\n    return HarmonizedUpdate{id, target, std::move(category), std::move(subcategory)};\n}\n\nvoid apply_harmonized_update(\n    const HarmonizedUpdate& update,\n    DatabaseManager& db_manager,\n    CategoryLanguage category_language,\n    std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n    const ConsistencyPassService::ProgressCallback& progress_callback,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    DatabaseManager::ResolvedCategory resolved =\n        db_manager.resolve_category(update.category, update.subcategory);\n    const DatabaseManager::ResolvedCategory display_resolved =\n        db_manager.localize_category(resolved, category_language);\n\n    bool changed = (display_resolved.category != update.target->category) ||\n                   (display_resolved.subcategory != update.target->subcategory);\n\n    update.target->category = display_resolved.category;\n    update.target->subcategory = display_resolved.subcategory;\n    update.target->taxonomy_id = resolved.taxonomy_id;\n    update.target->canonical_category = resolved.category;\n    update.target->canonical_subcategory = resolved.subcategory;\n\n    db_manager.insert_or_update_file_with_categorization(\n        update.target->file_name,\n        update.target->type == FileType::File ? \"F\" : \"D\",\n        update.target->file_path,\n        resolved,\n        update.target->used_consistency_hints,\n        update.target->suggested_name,\n        update.target->rename_only);\n\n    if (auto new_it = new_items_by_key.find(update.id); new_it != new_items_by_key.end() && new_it->second) {\n        new_it->second->category = display_resolved.category;\n        new_it->second->subcategory = display_resolved.subcategory;\n        new_it->second->taxonomy_id = resolved.taxonomy_id;\n        new_it->second->canonical_category = resolved.category;\n        new_it->second->canonical_subcategory = resolved.subcategory;\n    }\n\n    if (changed) {\n        const std::string message = fmt::format(\"[CONSISTENCY] {} -> {} / {}\",\n                                                update.target->file_name,\n                                                display_resolved.category,\n                                                display_resolved.subcategory);\n        if (progress_callback) {\n            progress_callback(message);\n        }\n        if (logger) {\n            logger->info(message);\n        }\n    }\n}\n\nconst Json::Value* parse_consistency_response(\n    const std::string& response,\n    Json::Value& root,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    Json::CharReaderBuilder reader;\n    std::string errors;\n    std::istringstream stream(response);\n    if (!Json::parseFromStream(reader, stream, &root, &errors)) {\n        if (logger) {\n            logger->warn(\"Consistency pass JSON parse failed: {}\", errors);\n            logger->warn(\"Consistency pass raw response ({} chars):\\n{}\", response.size(), response);\n        }\n        return parse_structured_fallback(response, root, logger);\n    }\n\n    if (const Json::Value* direct = extract_harmonized_array(root)) {\n        return direct;\n    }\n\n    if (logger) {\n        logger->warn(\"Consistency pass response missing 'harmonized' array\");\n    }\n    return parse_structured_fallback(response, root, logger);\n}\n\nstd::string strip_list_prefix(std::string line) {\n    line = trim_whitespace(line);\n    while (!line.empty() && (line.front() == '-' || line.front() == '*')) {\n        line.erase(line.begin());\n        line = trim_whitespace(line);\n    }\n    return line;\n}\n\nstd::optional<std::pair<std::string, std::string>> split_key_value(const std::string& line) {\n    const auto colon_pos = line.find(':');\n    if (colon_pos == std::string::npos) {\n        return std::nullopt;\n    }\n    std::string lhs = trim_whitespace(line.substr(0, colon_pos));\n    std::string rhs = trim_whitespace(line.substr(colon_pos + 1));\n    const auto arrow_pos = rhs.find(\"=>\");\n    if (arrow_pos != std::string::npos) {\n        rhs = trim_whitespace(rhs.substr(0, arrow_pos));\n    }\n    return std::make_pair(std::move(lhs), std::move(rhs));\n}\n\nstd::pair<std::string, std::string> split_category_subcategory(const std::string& lhs) {\n    const auto slash_pos = lhs.find('/');\n    if (slash_pos != std::string::npos) {\n        return {trim_whitespace(lhs.substr(0, slash_pos)),\n                trim_whitespace(lhs.substr(slash_pos + 1))};\n    }\n    return {lhs, std::string()};\n}\n\nstd::optional<std::pair<std::string, std::string>> parse_ordered_line(\n    std::string line,\n    const std::string& raw_line,\n    size_t line_number,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    line = strip_list_prefix(std::move(line));\n    const auto key_value = split_key_value(line);\n    if (!key_value.has_value()) {\n        return std::nullopt;\n    }\n\n    const auto& [lhs, rhs_raw] = *key_value;\n    auto [category, subcategory] = split_category_subcategory(lhs);\n    std::string rhs = rhs_raw;\n\n    if (subcategory.empty()) {\n        subcategory = rhs;\n    }\n    if (subcategory.empty()) {\n        subcategory = category;\n    }\n\n    if (category.empty()) {\n        if (logger) {\n            logger->warn(\"Consistency pass fallback skipped malformed line {}: '{}'\", line_number, raw_line);\n        }\n        return std::nullopt;\n    }\n\n    return std::make_pair(std::move(category), std::move(subcategory));\n}\n\nstd::vector<std::pair<std::string, std::string>> parse_ordered_category_lines(\n    const std::string& response,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    std::vector<std::pair<std::string, std::string>> ordered;\n    std::istringstream stream(response);\n    std::string raw_line;\n    size_t line_number = 0;\n\n    while (std::getline(stream, raw_line)) {\n        ++line_number;\n        std::string line = trim_whitespace(raw_line);\n        if (line.empty()) {\n            continue;\n        }\n        if (line == \"END\") {\n            break;\n        }\n        if (auto parsed = parse_ordered_line(line, raw_line, line_number, logger)) {\n            ordered.push_back(std::move(*parsed));\n        }\n    }\n\n    if (ordered.empty() && logger) {\n        logger->warn(\"Consistency pass fallback parsing produced no entries\");\n    }\n\n    return ordered;\n}\n\nbool apply_ordered_fallback(\n    const std::string& response,\n    const std::vector<const CategorizedFile*>& chunk,\n    std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n    DatabaseManager& db_manager,\n    CategoryLanguage category_language,\n    std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n    const ConsistencyPassService::ProgressCallback& progress_callback,\n    const std::shared_ptr<spdlog::logger>& logger)\n{\n    const auto ordered = parse_ordered_category_lines(response, logger);\n    if (ordered.empty()) {\n        return false;\n    }\n\n    const size_t limit = std::min(chunk.size(), ordered.size());\n    bool applied = false;\n    for (size_t index = 0; index < limit; ++index) {\n        if (!chunk[index]) {\n            continue;\n        }\n        Json::Value entry(Json::objectValue);\n        entry[\"id\"] = make_item_key(*chunk[index]);\n        entry[\"category\"] = ordered[index].first;\n        entry[\"subcategory\"] = ordered[index].second;\n        if (auto update = extract_harmonized_update(entry, items_by_key, logger)) {\n            apply_harmonized_update(*update, db_manager, category_language, new_items_by_key, progress_callback, logger);\n            applied = true;\n        }\n    }\n\n    return applied;\n}\n\n\n} // namespace\n\nConsistencyPassService::ConsistencyPassService(DatabaseManager& db_manager,\n                                               std::shared_ptr<spdlog::logger> logger)\n    : db_manager(db_manager),\n      logger(std::move(logger))\n{\n}\n\nvoid ConsistencyPassService::set_prompt_logging_enabled(bool enabled)\n{\n    prompt_logging_enabled = enabled;\n}\n\nstd::unique_ptr<ILLMClient> ConsistencyPassService::create_llm(\n    std::function<std::unique_ptr<ILLMClient>()> llm_factory) const\n{\n    if (!llm_factory) {\n        return nullptr;\n    }\n\n    try {\n        return llm_factory();\n    } catch (const std::exception& ex) {\n        if (logger) {\n            logger->warn(\"Failed to create LLM client for consistency pass: {}\", ex.what());\n        }\n        return nullptr;\n    }\n}\n\nvoid ConsistencyPassService::log_chunk_items(const std::vector<const CategorizedFile*>& chunk,\n                                             const char* stage) const\n{\n    if (!logger) {\n        return;\n    }\n    for (const auto* item : chunk) {\n        if (!item) {\n            continue;\n        }\n        logger->info(\"  [{}] {} -> {} / {}\",\n                     stage,\n                     item->file_name,\n                     canonical_category_text(*item),\n                     canonical_subcategory_text(*item));\n    }\n}\n\nbool ConsistencyPassService::apply_harmonized_response(\n    const std::string& response,\n    const std::vector<const CategorizedFile*>& chunk,\n    std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n    std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n    const ProgressCallback& progress_callback,\n    DatabaseManager& db_manager,\n    CategoryLanguage category_language) const\n{\n    Json::Value root;\n    if (const Json::Value* harmonized = parse_consistency_response(response, root, logger)) {\n        for (const auto& entry : *harmonized) {\n            if (auto update = extract_harmonized_update(entry, items_by_key, logger)) {\n                apply_harmonized_update(*update, db_manager, category_language, new_items_by_key, progress_callback, logger);\n            }\n        }\n        return true;\n    }\n\n    if (apply_ordered_fallback(response,\n                               chunk,\n                               items_by_key,\n                               db_manager,\n                               category_language,\n                               new_items_by_key,\n                               progress_callback,\n                               logger)) {\n        return true;\n    }\n\n    if (logger) {\n        logger->warn(\"Consistency pass could not interpret response; skipping chunk\");\n    }\n    return false;\n}\n\nvoid ConsistencyPassService::process_chunk(\n    const std::vector<const CategorizedFile*>& chunk,\n    size_t start_index,\n    size_t end_index,\n    size_t total_items,\n    ILLMClient& llm,\n    const std::vector<std::pair<std::string, std::string>>& taxonomy,\n    std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n    std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n    CategoryLanguage category_language,\n    const ProgressCallback& progress_callback) const\n{\n    if (logger) {\n        logger->info(\"[CONSISTENCY] Processing chunk {}-{} of {}\", start_index + 1, end_index, total_items);\n        log_chunk_items(chunk, \"BEFORE\");\n    }\n\n    const std::string prompt = build_consistency_prompt(chunk, taxonomy);\n    if (prompt_logging_enabled) {\n        std::cout << \"\\n[CONSISTENCY PROMPT]\\n\" << prompt << \"\\n\";\n    }\n\n    try {\n        const std::string response = llm.complete_prompt(prompt, 512);\n        if (prompt_logging_enabled) {\n            std::cout << \"[CONSISTENCY RESPONSE]\\n\" << response << \"\\n\";\n        }\n\n        apply_harmonized_response(response,\n                                  chunk,\n                                  items_by_key,\n                                  new_items_by_key,\n                                  progress_callback,\n                                  db_manager,\n                                  category_language);\n    } catch (const std::exception& ex) {\n        if (logger) {\n            logger->warn(\"Consistency pass chunk failed: {}\", ex.what());\n        }\n    }\n\n    log_chunk_items(chunk, \"AFTER\");\n}\n\nvoid ConsistencyPassService::process_chunks(\n    ILLMClient& llm,\n    const std::vector<std::pair<std::string, std::string>>& taxonomy,\n    std::vector<CategorizedFile>& categorized_files,\n    std::unordered_map<std::string, CategorizedFile*>& items_by_key,\n    std::unordered_map<std::string, CategorizedFile*>& new_items_by_key,\n    std::atomic<bool>& stop_flag,\n    CategoryLanguage category_language,\n    const ProgressCallback& progress_callback) const\n{\n    std::vector<const CategorizedFile*> chunk;\n    chunk.reserve(10);\n\n    for (size_t index = 0; index < categorized_files.size(); ++index) {\n        if (stop_flag.load()) {\n            break;\n        }\n\n        chunk.push_back(&categorized_files[index]);\n        const bool should_flush = chunk.size() == 10 || index + 1 == categorized_files.size();\n        if (!should_flush) {\n            continue;\n        }\n\n        const size_t start_index = index + 1 - chunk.size();\n        const size_t end_index = index + 1;\n        process_chunk(chunk,\n                      start_index,\n                      end_index,\n                      categorized_files.size(),\n                      llm,\n                      taxonomy,\n                      items_by_key,\n                      new_items_by_key,\n                      category_language,\n                      progress_callback);\n        chunk.clear();\n    }\n}\n\nvoid ConsistencyPassService::run(std::vector<CategorizedFile>& categorized_files,\n                                 std::vector<CategorizedFile>& newly_categorized_files,\n                                 std::function<std::unique_ptr<ILLMClient>()> llm_factory,\n                                 std::atomic<bool>& stop_flag,\n                                 CategoryLanguage category_language,\n                                 const ProgressCallback& progress_callback) const\n{\n    if (stop_flag.load() || categorized_files.empty()) {\n        return;\n    }\n\n    auto llm = create_llm(std::move(llm_factory));\n    if (!llm) {\n        return;\n    }\n\n    const auto taxonomy = db_manager.get_taxonomy_snapshot(150);\n\n    auto items_by_key = build_items_by_key(categorized_files);\n    auto new_items_by_key = build_items_by_key(newly_categorized_files);\n\n    process_chunks(*llm,\n                   taxonomy,\n                   categorized_files,\n                   items_by_key,\n                   new_items_by_key,\n                   stop_flag,\n                   category_language,\n                   progress_callback);\n}\n"
  },
  {
    "path": "app/lib/CustomApiDialog.cpp",
    "content": "#include \"CustomApiDialog.hpp\"\n\n#include <QCheckBox>\n#include <QDialogButtonBox>\n#include <QFormLayout>\n#include <QHBoxLayout>\n#include <QLabel>\n#include <QLineEdit>\n#include <QPushButton>\n#include <QTextEdit>\n#include <QVBoxLayout>\n\nCustomApiDialog::CustomApiDialog(QWidget* parent)\n    : QDialog(parent)\n{\n    setup_ui();\n    wire_signals();\n}\n\nCustomApiDialog::CustomApiDialog(QWidget* parent, const CustomApiEndpoint& existing)\n    : QDialog(parent)\n{\n    setup_ui();\n    wire_signals();\n    apply_existing(existing);\n}\n\nvoid CustomApiDialog::setup_ui()\n{\n    setWindowTitle(tr(\"Custom OpenAI-compatible API\"));\n    auto* layout = new QVBoxLayout(this);\n\n    auto* form = new QFormLayout();\n    name_edit = new QLineEdit(this);\n    description_edit = new QTextEdit(this);\n    description_edit->setFixedHeight(70);\n\n    base_url_edit = new QLineEdit(this);\n    base_url_edit->setPlaceholderText(tr(\"e.g. http://localhost:1234/v1\"));\n\n    model_edit = new QLineEdit(this);\n    model_edit->setPlaceholderText(tr(\"e.g. llama-3.1, gpt-4o-mini\"));\n\n    api_key_edit = new QLineEdit(this);\n    api_key_edit->setEchoMode(QLineEdit::Password);\n    api_key_edit->setClearButtonEnabled(true);\n    show_api_key_checkbox = new QCheckBox(tr(\"Show\"), this);\n    auto* api_key_row = new QWidget(this);\n    auto* api_key_layout = new QHBoxLayout(api_key_row);\n    api_key_layout->setContentsMargins(0, 0, 0, 0);\n    api_key_layout->addWidget(api_key_edit, 1);\n    api_key_layout->addWidget(show_api_key_checkbox);\n\n    form->addRow(tr(\"Display name\"), name_edit);\n    form->addRow(tr(\"Description\"), description_edit);\n    form->addRow(tr(\"Base URL or endpoint\"), base_url_edit);\n    form->addRow(tr(\"Model\"), model_edit);\n    form->addRow(tr(\"API key (optional)\"), api_key_row);\n\n    layout->addLayout(form);\n\n    auto* hint = new QLabel(tr(\"Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.\"), this);\n    hint->setWordWrap(true);\n    layout->addWidget(hint);\n\n    auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);\n    ok_button = button_box->button(QDialogButtonBox::Ok);\n    ok_button->setEnabled(false);\n    layout->addWidget(button_box);\n\n    connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);\n    connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);\n}\n\nvoid CustomApiDialog::wire_signals()\n{\n    connect(name_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs);\n    connect(base_url_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs);\n    connect(model_edit, &QLineEdit::textChanged, this, &CustomApiDialog::validate_inputs);\n    if (show_api_key_checkbox) {\n        connect(show_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (api_key_edit) {\n                api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password);\n            }\n        });\n    }\n}\n\nvoid CustomApiDialog::apply_existing(const CustomApiEndpoint& existing)\n{\n    name_edit->setText(QString::fromStdString(existing.name));\n    description_edit->setPlainText(QString::fromStdString(existing.description));\n    base_url_edit->setText(QString::fromStdString(existing.base_url));\n    model_edit->setText(QString::fromStdString(existing.model));\n    api_key_edit->setText(QString::fromStdString(existing.api_key));\n    validate_inputs();\n}\n\nvoid CustomApiDialog::validate_inputs()\n{\n    const bool valid = !name_edit->text().trimmed().isEmpty()\n        && !base_url_edit->text().trimmed().isEmpty()\n        && !model_edit->text().trimmed().isEmpty();\n    if (ok_button) {\n        ok_button->setEnabled(valid);\n    }\n}\n\nCustomApiEndpoint CustomApiDialog::result() const\n{\n    CustomApiEndpoint endpoint;\n    endpoint.name = name_edit->text().trimmed().toStdString();\n    endpoint.description = description_edit->toPlainText().trimmed().toStdString();\n    endpoint.base_url = base_url_edit->text().trimmed().toStdString();\n    endpoint.model = model_edit->text().trimmed().toStdString();\n    endpoint.api_key = api_key_edit->text().trimmed().toStdString();\n    return endpoint;\n}\n"
  },
  {
    "path": "app/lib/CustomLLMDialog.cpp",
    "content": "#include \"CustomLLMDialog.hpp\"\n\n#include <QDialogButtonBox>\n#include <QFileDialog>\n#include <QFormLayout>\n#include <QHBoxLayout>\n#include <QLabel>\n#include <QLineEdit>\n#include <QPushButton>\n#include <QTextEdit>\n#include <QVBoxLayout>\n\n\nCustomLLMDialog::CustomLLMDialog(QWidget* parent)\n    : QDialog(parent)\n{\n    setup_ui();\n    wire_signals();\n}\n\nCustomLLMDialog::CustomLLMDialog(QWidget* parent, const CustomLLM& existing)\n    : QDialog(parent)\n{\n    setup_ui();\n    wire_signals();\n    apply_existing(existing);\n}\n\nvoid CustomLLMDialog::setup_ui()\n{\n    setWindowTitle(tr(\"Custom local LLM\"));\n    auto* layout = new QVBoxLayout(this);\n\n    auto* form = new QFormLayout();\n    name_edit = new QLineEdit(this);\n    description_edit = new QTextEdit(this);\n    description_edit->setFixedHeight(70);\n    path_edit = new QLineEdit(this);\n    browse_button = new QPushButton(tr(\"Browse…\"), this);\n    auto* path_row = new QHBoxLayout();\n    path_row->addWidget(path_edit, 1);\n    path_row->addWidget(browse_button);\n\n    form->addRow(tr(\"Display name\"), name_edit);\n    form->addRow(tr(\"Description\"), description_edit);\n    form->addRow(tr(\"Model file (.gguf)\"), path_row);\n\n    layout->addLayout(form);\n\n    auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);\n    ok_button = button_box->button(QDialogButtonBox::Ok);\n    ok_button->setEnabled(false);\n    layout->addWidget(button_box);\n\n    connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);\n    connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);\n}\n\nvoid CustomLLMDialog::wire_signals()\n{\n    connect(name_edit, &QLineEdit::textChanged, this, &CustomLLMDialog::validate_inputs);\n    connect(path_edit, &QLineEdit::textChanged, this, &CustomLLMDialog::validate_inputs);\n    connect(browse_button, &QPushButton::clicked, this, &CustomLLMDialog::browse_for_file);\n}\n\nvoid CustomLLMDialog::apply_existing(const CustomLLM& existing)\n{\n    name_edit->setText(QString::fromStdString(existing.name));\n    description_edit->setPlainText(QString::fromStdString(existing.description));\n    path_edit->setText(QString::fromStdString(existing.path));\n    validate_inputs();\n}\n\nvoid CustomLLMDialog::validate_inputs()\n{\n    const bool valid = !name_edit->text().trimmed().isEmpty() &&\n                       !path_edit->text().trimmed().isEmpty();\n    if (ok_button) {\n        ok_button->setEnabled(valid);\n    }\n}\n\nvoid CustomLLMDialog::browse_for_file()\n{\n    const QString path = QFileDialog::getOpenFileName(this,\n                                                      tr(\"Select .gguf model\"),\n                                                      QString(),\n                                                      tr(\"GGUF models (*.gguf);;All files (*.*)\"));\n    if (!path.isEmpty()) {\n        path_edit->setText(path);\n    }\n}\n\nCustomLLM CustomLLMDialog::result() const\n{\n    CustomLLM llm;\n    llm.name = name_edit->text().trimmed().toStdString();\n    llm.description = description_edit->toPlainText().trimmed().toStdString();\n    llm.path = path_edit->text().trimmed().toStdString();\n    return llm;\n}\n"
  },
  {
    "path": "app/lib/DatabaseManager.cpp",
    "content": "#include \"DatabaseManager.hpp\"\n#include \"Types.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n\n#include <algorithm>\n#include <cctype>\n#include <cmath>\n#include <cstdio>\n#include <iostream>\n#include <memory>\n#include <optional>\n#include <sstream>\n#include <unordered_set>\n#include <utility>\n#include <vector>\n\n#include <sqlite3.h>\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/fmt.h>\n\nnamespace {\nconstexpr double kSimilarityThreshold = 0.85;\n\ntemplate <typename... Args>\nvoid db_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) {\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nbool is_duplicate_column_error(const char *error_msg) {\n    if (!error_msg) {\n        return false;\n    }\n    std::string message(error_msg);\n    std::transform(message.begin(), message.end(), message.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return message.find(\"duplicate column name\") != std::string::npos;\n}\n\nstd::string to_lower_copy(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value;\n}\n\nstd::string language_storage_key(CategoryLanguage language) {\n    return to_lower_copy(categoryLanguageDisplay(language));\n}\n\nstd::string extract_extension_lower(const std::string& file_name) {\n    const auto pos = file_name.find_last_of('.');\n    if (pos == std::string::npos || pos + 1 >= file_name.size()) {\n        return std::string();\n    }\n    std::string ext = file_name.substr(pos);\n    return to_lower_copy(ext);\n}\n\nstruct StatementDeleter {\n    void operator()(sqlite3_stmt* stmt) const {\n        if (stmt) {\n            sqlite3_finalize(stmt);\n        }\n    }\n};\n\nusing StatementPtr = std::unique_ptr<sqlite3_stmt, StatementDeleter>;\n\nStatementPtr prepare_statement(sqlite3* db, const char* sql) {\n    sqlite3_stmt* raw = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &raw, nullptr) != SQLITE_OK) {\n        return StatementPtr{};\n    }\n    return StatementPtr(raw);\n}\n\nstd::string trim_copy(std::string value) {\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space));\n    value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end());\n    return value;\n}\n\nbool has_label_content(const std::string& value) {\n    return !trim_copy(value).empty();\n}\n\nstd::string escape_like_pattern(const std::string& value) {\n    std::string escaped;\n    escaped.reserve(value.size() * 2);\n    for (char ch : value) {\n        if (ch == '\\\\' || ch == '%' || ch == '_') {\n            escaped.push_back('\\\\');\n        }\n        escaped.push_back(ch);\n    }\n    return escaped;\n}\n\nstd::string build_recursive_dir_pattern(const std::string& directory_path) {\n    std::string escaped = escape_like_pattern(directory_path);\n    if (directory_path.empty()) {\n        return escaped + \"%\";\n    }\n    const char sep = directory_path.find('\\\\') != std::string::npos ? '\\\\' : '/';\n    if (directory_path.back() == sep) {\n        escaped.push_back('%');\n        return escaped;\n    }\n    if (sep == '\\\\' || sep == '%' || sep == '_') {\n        escaped.push_back('\\\\');\n    }\n    escaped.push_back(sep);\n    escaped.push_back('%');\n    return escaped;\n}\n\nstd::optional<CategorizedFile> build_categorized_entry(sqlite3_stmt* stmt) {\n    const char *file_dir_path = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));\n    const char *file_name = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));\n    const char *file_type = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2));\n    const char *category = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3));\n    const char *subcategory = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 4));\n    const char *suggested_name = nullptr;\n    if (sqlite3_column_count(stmt) > 5) {\n        suggested_name = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 5));\n    }\n\n    std::string dir_path = file_dir_path ? file_dir_path : \"\";\n    std::string name = file_name ? file_name : \"\";\n    std::string type_str = file_type ? file_type : \"\";\n    std::string cat = Utils::sanitize_path_label(category ? category : \"\");\n    std::string subcat = Utils::sanitize_path_label(subcategory ? subcategory : \"\");\n    std::string suggested = Utils::sanitize_path_label(suggested_name ? suggested_name : \"\");\n\n    int taxonomy_id = 0;\n    if (sqlite3_column_count(stmt) > 6 && sqlite3_column_type(stmt, 6) != SQLITE_NULL) {\n        taxonomy_id = sqlite3_column_int(stmt, 6);\n    }\n    bool used_consistency = false;\n    if (sqlite3_column_count(stmt) > 7 && sqlite3_column_type(stmt, 7) != SQLITE_NULL) {\n        used_consistency = sqlite3_column_int(stmt, 7) != 0;\n    }\n    bool rename_only = false;\n    if (sqlite3_column_count(stmt) > 8 && sqlite3_column_type(stmt, 8) != SQLITE_NULL) {\n        rename_only = sqlite3_column_int(stmt, 8) != 0;\n    }\n    bool rename_applied = false;\n    if (sqlite3_column_count(stmt) > 9 && sqlite3_column_type(stmt, 9) != SQLITE_NULL) {\n        rename_applied = sqlite3_column_int(stmt, 9) != 0;\n    }\n\n    const bool has_labels = has_label_content(cat) && has_label_content(subcat);\n    const bool has_suggestion = has_label_content(suggested);\n    if (!rename_only && !has_labels && !has_suggestion) {\n        return std::nullopt;\n    }\n\n    FileType file_type_enum = (type_str == \"F\") ? FileType::File : FileType::Directory;\n    CategorizedFile entry{dir_path, name, file_type_enum, cat, subcat, taxonomy_id};\n    entry.from_cache = true;\n    entry.used_consistency_hints = used_consistency;\n    entry.suggested_name = suggested;\n    entry.rename_only = rename_only;\n    entry.rename_applied = rename_applied;\n    entry.canonical_category = cat;\n    entry.canonical_subcategory = subcat;\n    return entry;\n}\n\n} // namespace\n\nDatabaseManager::DatabaseManager(std::string config_dir)\n    : db(nullptr),\n      config_dir(std::move(config_dir)),\n      db_file(this->config_dir + \"/\" +\n              (std::getenv(\"CATEGORIZATION_CACHE_FILE\")\n                   ? std::getenv(\"CATEGORIZATION_CACHE_FILE\")\n                   : \"categorization_results.db\")) {\n    if (db_file.empty()) {\n        db_log(spdlog::level::err, \"Error: Database path is empty\");\n        return;\n    }\n\n    if (sqlite3_open(db_file.c_str(), &db) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Can't open database: {}\", sqlite3_errmsg(db));\n        db = nullptr;\n        return;\n    }\n\n    sqlite3_extended_result_codes(db, 1);\n\n    initialize_schema();\n    initialize_taxonomy_schema();\n    load_taxonomy_cache();\n    load_translation_cache();\n}\n\nDatabaseManager::~DatabaseManager() {\n    if (db) {\n        sqlite3_close(db);\n        db = nullptr;\n    }\n}\n\nvoid DatabaseManager::initialize_schema() {\n    if (!db) return;\n\n    const char *create_table_sql = R\"(\n        CREATE TABLE IF NOT EXISTS file_categorization (\n            id INTEGER PRIMARY KEY AUTOINCREMENT,\n            file_name TEXT NOT NULL,\n            file_type TEXT NOT NULL,\n            dir_path TEXT NOT NULL,\n            category TEXT NOT NULL,\n            subcategory TEXT,\n            suggested_name TEXT,\n            taxonomy_id INTEGER,\n            categorization_style INTEGER DEFAULT 0,\n            rename_only INTEGER DEFAULT 0,\n            rename_applied INTEGER DEFAULT 0,\n            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,\n            UNIQUE(file_name, file_type, dir_path)\n        );\n    )\";\n\n    char *error_msg = nullptr;\n    if (sqlite3_exec(db, create_table_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create file_categorization table: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n\n    const char *add_column_sql = \"ALTER TABLE file_categorization ADD COLUMN taxonomy_id INTEGER;\";\n    if (sqlite3_exec(db, add_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        if (!is_duplicate_column_error(error_msg)) {\n            db_log(spdlog::level::warn, \"Failed to add taxonomy_id column: {}\", error_msg ? error_msg : \"\");\n        }\n        if (error_msg) {\n            sqlite3_free(error_msg);\n        }\n    }\n\n    const char *add_style_column_sql =\n        \"ALTER TABLE file_categorization ADD COLUMN categorization_style INTEGER DEFAULT 0;\";\n    if (sqlite3_exec(db, add_style_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        if (!is_duplicate_column_error(error_msg)) {\n            db_log(spdlog::level::warn, \"Failed to add categorization_style column: {}\", error_msg ? error_msg : \"\");\n        }\n        if (error_msg) {\n            sqlite3_free(error_msg);\n        }\n    }\n\n    const char *add_suggested_name_column_sql =\n        \"ALTER TABLE file_categorization ADD COLUMN suggested_name TEXT;\";\n    if (sqlite3_exec(db, add_suggested_name_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        if (!is_duplicate_column_error(error_msg)) {\n            db_log(spdlog::level::warn, \"Failed to add suggested_name column: {}\", error_msg ? error_msg : \"\");\n        }\n        if (error_msg) {\n            sqlite3_free(error_msg);\n        }\n    }\n\n    const char *add_rename_only_column_sql =\n        \"ALTER TABLE file_categorization ADD COLUMN rename_only INTEGER DEFAULT 0;\";\n    if (sqlite3_exec(db, add_rename_only_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        if (!is_duplicate_column_error(error_msg)) {\n            db_log(spdlog::level::warn, \"Failed to add rename_only column: {}\", error_msg ? error_msg : \"\");\n        }\n        if (error_msg) {\n            sqlite3_free(error_msg);\n        }\n    }\n\n    const char *add_rename_applied_column_sql =\n        \"ALTER TABLE file_categorization ADD COLUMN rename_applied INTEGER DEFAULT 0;\";\n    if (sqlite3_exec(db, add_rename_applied_column_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        if (!is_duplicate_column_error(error_msg)) {\n            db_log(spdlog::level::warn, \"Failed to add rename_applied column: {}\", error_msg ? error_msg : \"\");\n        }\n        if (error_msg) {\n            sqlite3_free(error_msg);\n        }\n    }\n\n    const char *create_index_sql =\n        \"CREATE INDEX IF NOT EXISTS idx_file_categorization_taxonomy ON file_categorization(taxonomy_id);\";\n    if (sqlite3_exec(db, create_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create taxonomy index: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n}\n\nvoid DatabaseManager::initialize_taxonomy_schema() {\n    if (!db) return;\n\n    const char *taxonomy_sql = R\"(\n        CREATE TABLE IF NOT EXISTS category_taxonomy (\n            id INTEGER PRIMARY KEY AUTOINCREMENT,\n            canonical_category TEXT NOT NULL,\n            canonical_subcategory TEXT NOT NULL,\n            normalized_category TEXT NOT NULL,\n            normalized_subcategory TEXT NOT NULL,\n            frequency INTEGER DEFAULT 0,\n            UNIQUE(normalized_category, normalized_subcategory)\n        );\n    )\";\n\n    char *error_msg = nullptr;\n    if (sqlite3_exec(db, taxonomy_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create category_taxonomy table: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n\n    const char *alias_sql = R\"(\n        CREATE TABLE IF NOT EXISTS category_alias (\n            alias_category_norm TEXT NOT NULL,\n            alias_subcategory_norm TEXT NOT NULL,\n            taxonomy_id INTEGER NOT NULL,\n            PRIMARY KEY(alias_category_norm, alias_subcategory_norm),\n            FOREIGN KEY(taxonomy_id) REFERENCES category_taxonomy(id)\n        );\n    )\";\n    if (sqlite3_exec(db, alias_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create category_alias table: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n\n    const char *alias_index_sql =\n        \"CREATE INDEX IF NOT EXISTS idx_category_alias_taxonomy ON category_alias(taxonomy_id);\";\n    if (sqlite3_exec(db, alias_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create alias index: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n\n    const char* translation_sql = R\"(\n        CREATE TABLE IF NOT EXISTS category_translation (\n            taxonomy_id INTEGER NOT NULL,\n            language TEXT NOT NULL,\n            category TEXT NOT NULL,\n            subcategory TEXT NOT NULL,\n            normalized_category TEXT NOT NULL,\n            normalized_subcategory TEXT NOT NULL,\n            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n            PRIMARY KEY(taxonomy_id, language),\n            FOREIGN KEY(taxonomy_id) REFERENCES category_taxonomy(id)\n        );\n    )\";\n    if (sqlite3_exec(db, translation_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create category_translation table: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n\n    const char* translation_lookup_index_sql =\n        \"CREATE INDEX IF NOT EXISTS idx_category_translation_lookup \"\n        \"ON category_translation(language, normalized_category, normalized_subcategory);\";\n    if (sqlite3_exec(db, translation_lookup_index_sql, nullptr, nullptr, &error_msg) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to create translation lookup index: {}\", error_msg);\n        sqlite3_free(error_msg);\n    }\n}\n\nvoid DatabaseManager::load_taxonomy_cache() {\n    taxonomy_entries.clear();\n    canonical_lookup.clear();\n    alias_lookup.clear();\n    taxonomy_index.clear();\n\n    if (!db) return;\n\n    sqlite3_stmt *stmt = nullptr;\n    const char *select_taxonomy =\n        \"SELECT id, canonical_category, canonical_subcategory, \"\n        \"normalized_category, normalized_subcategory, frequency FROM category_taxonomy;\";\n\n    if (sqlite3_prepare_v2(db, select_taxonomy, -1, &stmt, nullptr) == SQLITE_OK) {\n        while (sqlite3_step(stmt) == SQLITE_ROW) {\n            TaxonomyEntry entry;\n            entry.id = sqlite3_column_int(stmt, 0);\n            entry.category = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));\n            entry.subcategory = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2));\n            entry.normalized_category = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3));\n            entry.normalized_subcategory = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 4));\n\n            taxonomy_index[entry.id] = taxonomy_entries.size();\n            taxonomy_entries.push_back(entry);\n            canonical_lookup[make_key(entry.normalized_category, entry.normalized_subcategory)] = entry.id;\n        }\n    } else {\n        db_log(spdlog::level::err, \"Failed to load taxonomy cache: {}\", sqlite3_errmsg(db));\n    }\n    if (stmt) sqlite3_finalize(stmt);\n\n    const char *select_alias =\n        \"SELECT alias_category_norm, alias_subcategory_norm, taxonomy_id FROM category_alias;\";\n    if (sqlite3_prepare_v2(db, select_alias, -1, &stmt, nullptr) == SQLITE_OK) {\n        while (sqlite3_step(stmt) == SQLITE_ROW) {\n            std::string alias_cat = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));\n            std::string alias_subcat = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));\n            int taxonomy_id = sqlite3_column_int(stmt, 2);\n\n            alias_lookup[make_key(alias_cat, alias_subcat)] = taxonomy_id;\n        }\n    } else {\n        db_log(spdlog::level::err, \"Failed to load category aliases: {}\", sqlite3_errmsg(db));\n    }\n    if (stmt) sqlite3_finalize(stmt);\n}\n\nvoid DatabaseManager::load_translation_cache() {\n    translation_entries.clear();\n    translation_lookup.clear();\n\n    if (!db) {\n        return;\n    }\n\n    sqlite3_stmt* stmt = nullptr;\n    const char* select_translation =\n        \"SELECT taxonomy_id, language, category, subcategory, normalized_category, normalized_subcategory \"\n        \"FROM category_translation;\";\n\n    if (sqlite3_prepare_v2(db, select_translation, -1, &stmt, nullptr) == SQLITE_OK) {\n        while (sqlite3_step(stmt) == SQLITE_ROW) {\n            const int taxonomy_id = sqlite3_column_int(stmt, 0);\n            const char* language_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));\n            const char* category_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));\n            const char* subcategory_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));\n            const char* normalized_category = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));\n            const char* normalized_subcategory = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5));\n\n            CategoryLanguage language = categoryLanguageFromString(QString::fromStdString(language_text ? language_text : \"\"));\n            ResolvedCategory translated{\n                taxonomy_id,\n                category_text ? category_text : \"\",\n                subcategory_text ? subcategory_text : \"\"\n            };\n            translation_entries[make_translation_entry_key(taxonomy_id, language)] = translated;\n            translation_lookup[make_translation_lookup_key(language,\n                                                           normalized_category ? normalized_category : \"\",\n                                                           normalized_subcategory ? normalized_subcategory : \"\")] = taxonomy_id;\n        }\n    } else {\n        db_log(spdlog::level::err, \"Failed to load category translations: {}\", sqlite3_errmsg(db));\n    }\n    if (stmt) {\n        sqlite3_finalize(stmt);\n    }\n}\n\nstd::string DatabaseManager::normalize_label(const std::string &input) const {\n    std::string result;\n    result.reserve(input.size());\n\n    bool last_was_space = true;\n    for (unsigned char ch : input) {\n        if (std::isalnum(ch)) {\n            result.push_back(static_cast<char>(std::tolower(ch)));\n            last_was_space = false;\n        } else if (std::isspace(ch)) {\n            if (!last_was_space) {\n                result.push_back(' ');\n                last_was_space = true;\n            }\n        }\n    }\n\n    // Trim leading/trailing space if any\n    while (!result.empty() && result.front() == ' ') {\n        result.erase(result.begin());\n    }\n    while (!result.empty() && result.back() == ' ') {\n        result.pop_back();\n    }\n    return result;\n}\n\nstd::string DatabaseManager::make_translation_entry_key(int taxonomy_id,\n                                                        CategoryLanguage language) {\n    return fmt::format(\"{}|{}\", taxonomy_id, language_storage_key(language));\n}\n\nstd::string DatabaseManager::make_translation_lookup_key(CategoryLanguage language,\n                                                         const std::string& norm_category,\n                                                         const std::string& norm_subcategory) {\n    return fmt::format(\"{}|{}|{}\",\n                       language_storage_key(language),\n                       norm_category,\n                       norm_subcategory);\n}\n\nstatic std::string strip_trailing_stopwords(const std::string& normalized) {\n    if (normalized.empty()) {\n        return normalized;\n    }\n    static const std::unordered_set<std::string> kStopwords = {\n        \"file\", \"files\",\n        \"doc\", \"docs\", \"document\", \"documents\",\n        \"image\", \"images\",\n        \"photo\", \"photos\",\n        \"pic\", \"pics\"\n    };\n\n    std::istringstream iss(normalized);\n    std::vector<std::string> tokens;\n    std::string token;\n    while (iss >> token) {\n        tokens.push_back(token);\n    }\n    if (tokens.size() <= 1) {\n        return normalized;\n    }\n    while (tokens.size() > 1 && kStopwords.contains(tokens.back())) {\n        tokens.pop_back();\n    }\n    if (tokens.empty()) {\n        return normalized;\n    }\n\n    std::string joined;\n    for (size_t index = 0; index < tokens.size(); ++index) {\n        if (index > 0) {\n            joined.push_back(' ');\n        }\n        joined += tokens[index];\n    }\n    return joined;\n}\n\nstruct CanonicalCategoryLabel {\n    std::string normalized;\n    std::string display;\n};\n\nbool is_image_like_label(const std::string& normalized) {\n    if (normalized.empty()) {\n        return false;\n    }\n    static const std::unordered_set<std::string> kImageLike = {\n        \"image\", \"images\",\n        \"image file\", \"image files\",\n        \"photo\", \"photos\",\n        \"graphic\", \"graphics\",\n        \"picture\", \"pictures\",\n        \"pic\", \"pics\",\n        \"screenshot\", \"screenshots\",\n        \"wallpaper\", \"wallpapers\"\n    };\n    if (kImageLike.contains(normalized)) {\n        return true;\n    }\n    return kImageLike.contains(strip_trailing_stopwords(normalized));\n}\n\nCanonicalCategoryLabel canonicalize_category_label(const std::string& normalized_category,\n                                                   const std::string& normalized_subcategory) {\n    static const std::unordered_map<std::string, CanonicalCategoryLabel> kCategorySynonyms = {\n        {\"archive\", {\"archives\", \"Archives\"}},\n        {\"archives\", {\"archives\", \"Archives\"}},\n        {\"backup\", {\"archives\", \"Archives\"}},\n        {\"backups\", {\"archives\", \"Archives\"}},\n        {\"backup file\", {\"archives\", \"Archives\"}},\n        {\"backup files\", {\"archives\", \"Archives\"}},\n\n        {\"document\", {\"documents\", \"Documents\"}},\n        {\"documents\", {\"documents\", \"Documents\"}},\n        {\"doc\", {\"documents\", \"Documents\"}},\n        {\"docs\", {\"documents\", \"Documents\"}},\n        {\"text\", {\"documents\", \"Documents\"}},\n        {\"texts\", {\"documents\", \"Documents\"}},\n        {\"paper\", {\"documents\", \"Documents\"}},\n        {\"papers\", {\"documents\", \"Documents\"}},\n        {\"report\", {\"documents\", \"Documents\"}},\n        {\"reports\", {\"documents\", \"Documents\"}},\n        {\"spreadsheet\", {\"documents\", \"Documents\"}},\n        {\"spreadsheets\", {\"documents\", \"Documents\"}},\n        {\"table\", {\"documents\", \"Documents\"}},\n        {\"tables\", {\"documents\", \"Documents\"}},\n        {\"office file\", {\"documents\", \"Documents\"}},\n        {\"office files\", {\"documents\", \"Documents\"}},\n\n        {\"software\", {\"software\", \"Software\"}},\n        {\"application\", {\"software\", \"Software\"}},\n        {\"applications\", {\"software\", \"Software\"}},\n        {\"app\", {\"software\", \"Software\"}},\n        {\"apps\", {\"software\", \"Software\"}},\n        {\"program\", {\"software\", \"Software\"}},\n        {\"programs\", {\"software\", \"Software\"}},\n        {\"installer\", {\"software\", \"Software\"}},\n        {\"installers\", {\"software\", \"Software\"}},\n        {\"installation\", {\"software\", \"Software\"}},\n        {\"installations\", {\"software\", \"Software\"}},\n        {\"installation file\", {\"software\", \"Software\"}},\n        {\"installation files\", {\"software\", \"Software\"}},\n        {\"software installation\", {\"software\", \"Software\"}},\n        {\"software installations\", {\"software\", \"Software\"}},\n        {\"software installation file\", {\"software\", \"Software\"}},\n        {\"software installation files\", {\"software\", \"Software\"}},\n        {\"setup\", {\"software\", \"Software\"}},\n        {\"setups\", {\"software\", \"Software\"}},\n        {\"setup file\", {\"software\", \"Software\"}},\n        {\"setup files\", {\"software\", \"Software\"}},\n        {\"update\", {\"software\", \"Software\"}},\n        {\"updates\", {\"software\", \"Software\"}},\n        {\"software update\", {\"software\", \"Software\"}},\n        {\"software updates\", {\"software\", \"Software\"}},\n        {\"patch\", {\"software\", \"Software\"}},\n        {\"patches\", {\"software\", \"Software\"}},\n        {\"upgrade\", {\"software\", \"Software\"}},\n        {\"upgrades\", {\"software\", \"Software\"}},\n        {\"updater\", {\"software\", \"Software\"}},\n        {\"updaters\", {\"software\", \"Software\"}},\n\n        {\"image\", {\"images\", \"Images\"}},\n        {\"images\", {\"images\", \"Images\"}},\n        {\"image file\", {\"images\", \"Images\"}},\n        {\"image files\", {\"images\", \"Images\"}},\n        {\"photo\", {\"images\", \"Images\"}},\n        {\"photos\", {\"images\", \"Images\"}},\n        {\"graphic\", {\"images\", \"Images\"}},\n        {\"graphics\", {\"images\", \"Images\"}},\n        {\"picture\", {\"images\", \"Images\"}},\n        {\"pictures\", {\"images\", \"Images\"}},\n        {\"pic\", {\"images\", \"Images\"}},\n        {\"pics\", {\"images\", \"Images\"}},\n        {\"screenshot\", {\"images\", \"Images\"}},\n        {\"screenshots\", {\"images\", \"Images\"}},\n        {\"wallpaper\", {\"images\", \"Images\"}},\n        {\"wallpapers\", {\"images\", \"Images\"}}\n    };\n\n    if (auto it = kCategorySynonyms.find(normalized_category); it != kCategorySynonyms.end()) {\n        return it->second;\n    }\n\n    const std::string stripped_category = strip_trailing_stopwords(normalized_category);\n    if (auto it = kCategorySynonyms.find(stripped_category); it != kCategorySynonyms.end()) {\n        return it->second;\n    }\n\n    // \"Media\" can be broader than images, so only collapse when the paired subcategory is image-like.\n    if ((normalized_category == \"media\" || stripped_category == \"media\") &&\n        is_image_like_label(normalized_subcategory)) {\n        return {\"images\", \"Images\"};\n    }\n\n    return {normalized_category, \"\"};\n}\n\ndouble DatabaseManager::string_similarity(const std::string &a, const std::string &b) {\n    if (a == b) {\n        return 1.0;\n    }\n    if (a.empty() || b.empty()) {\n        return 0.0;\n    }\n\n    const size_t m = a.size();\n    const size_t n = b.size();\n    std::vector<size_t> prev(n + 1), curr(n + 1);\n\n    for (size_t j = 0; j <= n; ++j) {\n        prev[j] = j;\n    }\n\n    for (size_t i = 1; i <= m; ++i) {\n        curr[0] = i;\n        for (size_t j = 1; j <= n; ++j) {\n            size_t cost = (a[i - 1] == b[j - 1]) ? 0 : 1;\n            curr[j] = std::min({prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost});\n        }\n        std::swap(prev, curr);\n    }\n\n    const double dist = static_cast<double>(prev[n]);\n    const double max_len = static_cast<double>(std::max(m, n));\n    return 1.0 - (dist / max_len);\n}\n\nstd::string DatabaseManager::make_key(const std::string &norm_category,\n                                      const std::string &norm_subcategory) {\n    return norm_category + \"::\" + norm_subcategory;\n}\n\nint DatabaseManager::create_taxonomy_entry(const std::string &category,\n                                           const std::string &subcategory,\n                                           const std::string &norm_category,\n                                           const std::string &norm_subcategory) {\n    if (!db) return -1;\n\n    const char *sql = R\"(\n        INSERT INTO category_taxonomy\n            (canonical_category, canonical_subcategory, normalized_category, normalized_subcategory, frequency)\n        VALUES (?, ?, ?, ?, 0);\n    )\";\n\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare taxonomy insert: {}\", sqlite3_errmsg(db));\n        return -1;\n    }\n\n    sqlite3_bind_text(stmt, 1, category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, subcategory.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 3, norm_category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 4, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT);\n\n    int step_rc = sqlite3_step(stmt);\n    int extended_rc = sqlite3_extended_errcode(db);\n    sqlite3_finalize(stmt);\n\n    if (step_rc != SQLITE_DONE) {\n        if (extended_rc == SQLITE_CONSTRAINT_UNIQUE ||\n            extended_rc == SQLITE_CONSTRAINT_PRIMARYKEY ||\n            extended_rc == SQLITE_CONSTRAINT) {\n            return find_existing_taxonomy_id(norm_category, norm_subcategory);\n        }\n\n        db_log(spdlog::level::err, \"Failed to insert taxonomy entry: {}\", sqlite3_errmsg(db));\n        return -1;\n    }\n\n    int new_id = static_cast<int>(sqlite3_last_insert_rowid(db));\n    TaxonomyEntry entry{new_id, category, subcategory, norm_category, norm_subcategory};\n    taxonomy_index[new_id] = taxonomy_entries.size();\n    taxonomy_entries.push_back(entry);\n    canonical_lookup[make_key(norm_category, norm_subcategory)] = new_id;\n    return new_id;\n}\n\nint DatabaseManager::find_existing_taxonomy_id(const std::string &norm_category,\n                                               const std::string &norm_subcategory) const {\n    if (!db) return -1;\n\n    const char *select_sql =\n        \"SELECT id FROM category_taxonomy WHERE normalized_category = ? AND normalized_subcategory = ? LIMIT 1;\";\n    sqlite3_stmt *stmt = nullptr;\n    int existing_id = -1;\n\n    if (sqlite3_prepare_v2(db, select_sql, -1, &stmt, nullptr) == SQLITE_OK) {\n        sqlite3_bind_text(stmt, 1, norm_category.c_str(), -1, SQLITE_TRANSIENT);\n        sqlite3_bind_text(stmt, 2, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT);\n        if (sqlite3_step(stmt) == SQLITE_ROW) {\n            existing_id = sqlite3_column_int(stmt, 0);\n        }\n    }\n\n    if (stmt) {\n        sqlite3_finalize(stmt);\n    }\n    return existing_id;\n}\n\nvoid DatabaseManager::ensure_alias_mapping(int taxonomy_id,\n                                           const std::string &norm_category,\n                                           const std::string &norm_subcategory) {\n    if (!db) return;\n\n    std::string key = make_key(norm_category, norm_subcategory);\n\n    auto canonical_it = canonical_lookup.find(key);\n    if (canonical_it != canonical_lookup.end() && canonical_it->second == taxonomy_id) {\n        return; // Already canonical form\n    }\n\n    if (alias_lookup.find(key) != alias_lookup.end()) {\n        return;\n    }\n\n    const char *sql = R\"(\n        INSERT OR IGNORE INTO category_alias (alias_category_norm, alias_subcategory_norm, taxonomy_id)\n        VALUES (?, ?, ?);\n    )\";\n\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare alias insert: {}\", sqlite3_errmsg(db));\n        return;\n    }\n\n    sqlite3_bind_text(stmt, 1, norm_category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, norm_subcategory.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_int(stmt, 3, taxonomy_id);\n\n    if (sqlite3_step(stmt) != SQLITE_DONE) {\n        db_log(spdlog::level::err, \"Failed to insert alias: {}\", sqlite3_errmsg(db));\n        sqlite3_finalize(stmt);\n        return;\n    }\n\n    sqlite3_finalize(stmt);\n    alias_lookup[key] = taxonomy_id;\n}\n\nconst DatabaseManager::TaxonomyEntry *DatabaseManager::find_taxonomy_entry(int taxonomy_id) const {\n    auto it = taxonomy_index.find(taxonomy_id);\n    if (it == taxonomy_index.end()) {\n        return nullptr;\n    }\n    size_t idx = it->second;\n    if (idx >= taxonomy_entries.size()) {\n        return nullptr;\n    }\n    return &taxonomy_entries[idx];\n}\n\nstd::pair<int, double> DatabaseManager::find_fuzzy_match(\n    const std::string& norm_category,\n    const std::string& norm_subcategory) const {\n    if (taxonomy_entries.empty()) {\n        return {-1, 0.0};\n    }\n\n    double best_score = 0.0;\n    int best_id = -1;\n    for (const auto &entry : taxonomy_entries) {\n        double category_score = string_similarity(norm_category, entry.normalized_category);\n        double subcategory_score =\n            string_similarity(norm_subcategory, entry.normalized_subcategory);\n        double combined = (category_score + subcategory_score) / 2.0;\n        if (combined > best_score) {\n            best_score = combined;\n            best_id = entry.id;\n        }\n    }\n\n    if (best_id != -1 && best_score >= kSimilarityThreshold) {\n        return {best_id, best_score};\n    }\n    return {-1, best_score};\n}\n\nint DatabaseManager::resolve_existing_taxonomy(const std::string& key,\n                                               const std::string& norm_category,\n                                               const std::string& norm_subcategory) const {\n    auto alias_it = alias_lookup.find(key);\n    if (alias_it != alias_lookup.end()) {\n        return alias_it->second;\n    }\n\n    auto canonical_it = canonical_lookup.find(key);\n    if (canonical_it != canonical_lookup.end()) {\n        return canonical_it->second;\n    }\n\n    auto [best_id, score] = find_fuzzy_match(norm_category, norm_subcategory);\n    return best_id;\n}\n\nDatabaseManager::ResolvedCategory DatabaseManager::build_resolved_category(\n    int taxonomy_id,\n    const std::string& fallback_category,\n    const std::string& fallback_subcategory,\n    const std::string& norm_category,\n    const std::string& norm_subcategory) {\n\n    ResolvedCategory result{-1, fallback_category, fallback_subcategory};\n\n    if (taxonomy_id == -1) {\n        taxonomy_id = create_taxonomy_entry(fallback_category, fallback_subcategory,\n                                            norm_category, norm_subcategory);\n    }\n\n    if (taxonomy_id != -1) {\n        ensure_alias_mapping(taxonomy_id, norm_category, norm_subcategory);\n        if (const auto *entry = find_taxonomy_entry(taxonomy_id)) {\n            result.taxonomy_id = entry->id;\n            result.category = entry->category;\n            result.subcategory = entry->subcategory;\n        } else {\n            result.taxonomy_id = taxonomy_id;\n        }\n    } else {\n        result.category = fallback_category;\n        result.subcategory = fallback_subcategory;\n    }\n\n    return result;\n}\n\nDatabaseManager::ResolvedCategory\nDatabaseManager::resolve_category(const std::string &category,\n                                  const std::string &subcategory) {\n    ResolvedCategory result{-1, category, subcategory};\n    if (!db) {\n        return result;\n    }\n\n    auto trim_copy = [](std::string value) {\n        auto is_space = [](unsigned char ch) { return std::isspace(ch); };\n        value.erase(value.begin(), std::find_if(value.begin(), value.end(),\n                                                [&](unsigned char ch) { return !is_space(ch); }));\n        value.erase(std::find_if(value.rbegin(), value.rend(),\n                                 [&](unsigned char ch) { return !is_space(ch); }).base(),\n                    value.end());\n        return value;\n    };\n\n    std::string trimmed_category = trim_copy(category);\n    std::string trimmed_subcategory = trim_copy(subcategory);\n\n    if (trimmed_category.empty()) {\n        trimmed_category = \"Uncategorized\";\n    }\n    if (trimmed_subcategory.empty()) {\n        trimmed_subcategory = \"General\";\n    }\n\n    std::string norm_category = normalize_label(trimmed_category);\n    std::string norm_subcategory = normalize_label(trimmed_subcategory);\n    const CanonicalCategoryLabel canonical_category = canonicalize_category_label(norm_category, norm_subcategory);\n    norm_category = canonical_category.normalized;\n    if (!canonical_category.display.empty()) {\n        trimmed_category = canonical_category.display;\n    }\n    const std::string match_subcategory = strip_trailing_stopwords(norm_subcategory);\n    std::string key = make_key(norm_category, match_subcategory);\n\n    int taxonomy_id = resolve_existing_taxonomy(key, norm_category, match_subcategory);\n    if (taxonomy_id == -1 && match_subcategory != norm_subcategory) {\n        const std::string raw_key = make_key(norm_category, norm_subcategory);\n        taxonomy_id = resolve_existing_taxonomy(raw_key, norm_category, norm_subcategory);\n    }\n    return build_resolved_category(taxonomy_id,\n                                   trimmed_category,\n                                   trimmed_subcategory,\n                                   norm_category,\n                                   match_subcategory);\n}\n\nDatabaseManager::ResolvedCategory\nDatabaseManager::resolve_category_for_language(const std::string& category,\n                                               const std::string& subcategory,\n                                               CategoryLanguage language) {\n    if (language == CategoryLanguage::English || !db) {\n        return resolve_category(category, subcategory);\n    }\n\n    auto trim_copy = [](std::string value) {\n        auto is_space = [](unsigned char ch) { return std::isspace(ch); };\n        value.erase(value.begin(), std::find_if(value.begin(), value.end(),\n                                                [&](unsigned char ch) { return !is_space(ch); }));\n        value.erase(std::find_if(value.rbegin(), value.rend(),\n                                 [&](unsigned char ch) { return !is_space(ch); }).base(),\n                    value.end());\n        return value;\n    };\n\n    std::string trimmed_category = trim_copy(category);\n    std::string trimmed_subcategory = trim_copy(subcategory);\n    if (trimmed_category.empty()) {\n        return resolve_category(category, subcategory);\n    }\n    if (trimmed_subcategory.empty()) {\n        trimmed_subcategory = \"General\";\n    }\n\n    const std::string normalized_category = normalize_label(trimmed_category);\n    const std::string normalized_subcategory = normalize_label(trimmed_subcategory);\n    const std::string stripped_subcategory = strip_trailing_stopwords(normalized_subcategory);\n\n    const auto lookup_translation = [&](const std::string& norm_subcategory) -> int {\n        const auto it = translation_lookup.find(make_translation_lookup_key(language,\n                                                                            normalized_category,\n                                                                            norm_subcategory));\n        return it != translation_lookup.end() ? it->second : -1;\n    };\n\n    int taxonomy_id = lookup_translation(stripped_subcategory);\n    if (taxonomy_id == -1 && stripped_subcategory != normalized_subcategory) {\n        taxonomy_id = lookup_translation(normalized_subcategory);\n    }\n    if (taxonomy_id != -1) {\n        if (const auto* entry = find_taxonomy_entry(taxonomy_id)) {\n            return ResolvedCategory{entry->id, entry->category, entry->subcategory};\n        }\n        return ResolvedCategory{taxonomy_id, trimmed_category, trimmed_subcategory};\n    }\n\n    return resolve_category(category, subcategory);\n}\n\nstd::optional<DatabaseManager::ResolvedCategory>\nDatabaseManager::get_category_translation(int taxonomy_id,\n                                          CategoryLanguage language) const {\n    if (language == CategoryLanguage::English || taxonomy_id <= 0) {\n        return std::nullopt;\n    }\n    const auto it = translation_entries.find(make_translation_entry_key(taxonomy_id, language));\n    if (it == translation_entries.end()) {\n        return std::nullopt;\n    }\n    return it->second;\n}\n\nDatabaseManager::ResolvedCategory\nDatabaseManager::localize_category(const ResolvedCategory& resolved,\n                                   CategoryLanguage language) const {\n    if (language == CategoryLanguage::English || resolved.taxonomy_id <= 0) {\n        return resolved;\n    }\n    if (const auto translated = get_category_translation(resolved.taxonomy_id, language)) {\n        return *translated;\n    }\n    if (const auto* entry = find_taxonomy_entry(resolved.taxonomy_id)) {\n        return ResolvedCategory{entry->id, entry->category, entry->subcategory};\n    }\n    return resolved;\n}\n\nCategorizedFile DatabaseManager::localize_categorized_file(const CategorizedFile& entry,\n                                                           CategoryLanguage language) const {\n    CategorizedFile localized = entry;\n    if (localized.canonical_category.empty()) {\n        localized.canonical_category = entry.category;\n    }\n    if (localized.canonical_subcategory.empty()) {\n        localized.canonical_subcategory = entry.subcategory;\n    }\n    if (const auto translated = get_category_translation(entry.taxonomy_id, language)) {\n        localized.category = translated->category;\n        localized.subcategory = translated->subcategory;\n    }\n    return localized;\n}\n\nbool DatabaseManager::upsert_category_translation(int taxonomy_id,\n                                                  CategoryLanguage language,\n                                                  const std::string& category,\n                                                  const std::string& subcategory) {\n    if (!db || taxonomy_id <= 0 || language == CategoryLanguage::English) {\n        return false;\n    }\n\n    const std::string sanitized_category = Utils::sanitize_path_label(category);\n    const std::string sanitized_subcategory = Utils::sanitize_path_label(subcategory);\n    if (sanitized_category.empty() || sanitized_subcategory.empty()) {\n        return false;\n    }\n\n    const std::string normalized_category = normalize_label(sanitized_category);\n    const std::string normalized_subcategory = normalize_label(sanitized_subcategory);\n    const std::string language_key = language_storage_key(language);\n\n    const char* sql = R\"(\n        INSERT INTO category_translation\n            (taxonomy_id, language, category, subcategory, normalized_category, normalized_subcategory, updated_at)\n        VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)\n        ON CONFLICT(taxonomy_id, language)\n        DO UPDATE SET\n            category = excluded.category,\n            subcategory = excluded.subcategory,\n            normalized_category = excluded.normalized_category,\n            normalized_subcategory = excluded.normalized_subcategory,\n            updated_at = CURRENT_TIMESTAMP;\n    )\";\n\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare translation upsert: {}\", sqlite3_errmsg(db));\n        return false;\n    }\n\n    sqlite3_bind_int(stmt, 1, taxonomy_id);\n    sqlite3_bind_text(stmt, 2, language_key.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 3, sanitized_category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 4, sanitized_subcategory.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 5, normalized_category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 6, normalized_subcategory.c_str(), -1, SQLITE_TRANSIENT);\n\n    const bool success = sqlite3_step(stmt) == SQLITE_DONE;\n    if (!success) {\n        db_log(spdlog::level::err, \"Failed to upsert category translation: {}\", sqlite3_errmsg(db));\n    }\n    sqlite3_finalize(stmt);\n    if (!success) {\n        return false;\n    }\n\n    const ResolvedCategory translated{taxonomy_id, sanitized_category, sanitized_subcategory};\n    translation_entries[make_translation_entry_key(taxonomy_id, language)] = translated;\n    translation_lookup[make_translation_lookup_key(language,\n                                                   normalized_category,\n                                                   normalized_subcategory)] = taxonomy_id;\n    return true;\n}\n\nbool DatabaseManager::insert_or_update_file_with_categorization(\n    const std::string &file_name,\n    const std::string &file_type,\n    const std::string &dir_path,\n    const ResolvedCategory &resolved,\n    bool used_consistency_hints,\n    const std::string &suggested_name,\n    bool rename_only,\n    bool rename_applied) {\n    if (!db) return false;\n\n    const char *sql = R\"(\n        INSERT INTO file_categorization\n            (file_name, file_type, dir_path, category, subcategory, suggested_name,\n             taxonomy_id, categorization_style, rename_only, rename_applied)\n        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n        ON CONFLICT(file_name, file_type, dir_path)\n        DO UPDATE SET\n            category = excluded.category,\n            subcategory = excluded.subcategory,\n            suggested_name = excluded.suggested_name,\n            taxonomy_id = excluded.taxonomy_id,\n            categorization_style = excluded.categorization_style,\n            rename_only = excluded.rename_only,\n            rename_applied = CASE\n                WHEN excluded.rename_applied = 1 THEN 1\n                ELSE rename_applied\n            END;\n    )\";\n\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"SQL prepare error: {}\", sqlite3_errmsg(db));\n        return false;\n    }\n\n    sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, file_type.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 3, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 4, resolved.category.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 5, resolved.subcategory.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 6, suggested_name.c_str(), -1, SQLITE_TRANSIENT);\n\n    if (resolved.taxonomy_id > 0) {\n        sqlite3_bind_int(stmt, 7, resolved.taxonomy_id);\n    } else {\n        sqlite3_bind_null(stmt, 7);\n    }\n    sqlite3_bind_int(stmt, 8, used_consistency_hints ? 1 : 0);\n    sqlite3_bind_int(stmt, 9, rename_only ? 1 : 0);\n    sqlite3_bind_int(stmt, 10, rename_applied ? 1 : 0);\n\n    bool success = true;\n    if (sqlite3_step(stmt) != SQLITE_DONE) {\n        db_log(spdlog::level::err, \"SQL error during insert/update: {}\", sqlite3_errmsg(db));\n        success = false;\n    }\n\n    sqlite3_finalize(stmt);\n\n    if (success && resolved.taxonomy_id > 0) {\n        increment_taxonomy_frequency(resolved.taxonomy_id);\n    }\n\n    return success;\n}\n\nbool DatabaseManager::remove_file_categorization(const std::string& dir_path,\n                                                 const std::string& file_name,\n                                                 const FileType file_type) {\n    if (!db) {\n        return false;\n    }\n\n    const char* sql =\n        \"DELETE FROM file_categorization WHERE dir_path = ? AND file_name = ? AND file_type = ?;\";\n\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare delete categorization statement: {}\", sqlite3_errmsg(db));\n        return false;\n    }\n\n    const std::string type_str = (file_type == FileType::File) ? \"F\" : \"D\";\n\n    sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, file_name.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 3, type_str.c_str(), -1, SQLITE_TRANSIENT);\n\n    const bool success = sqlite3_step(stmt) == SQLITE_DONE;\n    if (!success) {\n        db_log(spdlog::level::err, \"Failed to delete cached categorization for '{}': {}\", file_name, sqlite3_errmsg(db));\n    }\n\n    sqlite3_finalize(stmt);\n    return success;\n}\n\nbool DatabaseManager::clear_directory_categorizations(const std::string& dir_path,\n                                                      bool recursive) {\n    if (!db) {\n        return false;\n    }\n\n    const char* sql = recursive\n        ? \"DELETE FROM file_categorization WHERE dir_path = ? OR dir_path LIKE ? ESCAPE '\\\\';\"\n        : \"DELETE FROM file_categorization WHERE dir_path = ?;\";\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare directory cache clear statement: {}\", sqlite3_errmsg(db));\n        return false;\n    }\n\n    sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n    if (recursive) {\n        const std::string pattern = build_recursive_dir_pattern(dir_path);\n        sqlite3_bind_text(stmt, 2, pattern.c_str(), -1, SQLITE_TRANSIENT);\n    }\n    const bool success = sqlite3_step(stmt) == SQLITE_DONE;\n    if (!success) {\n        db_log(spdlog::level::err, \"Failed to clear cached categorizations for '{}': {}\", dir_path, sqlite3_errmsg(db));\n    }\n    sqlite3_finalize(stmt);\n    cached_results.clear();\n    return success;\n}\n\nbool DatabaseManager::has_categorization_style_conflict(const std::string& dir_path,\n                                                        bool desired_style,\n                                                        bool recursive) const {\n    if (!db) {\n        return false;\n    }\n\n    const char* sql = recursive\n        ? \"SELECT 1 FROM file_categorization \"\n          \"WHERE (dir_path = ? OR dir_path LIKE ? ESCAPE '\\\\') \"\n          \"AND IFNULL(categorization_style, 0) != ? \"\n          \"LIMIT 1;\"\n        : \"SELECT 1 FROM file_categorization \"\n          \"WHERE dir_path = ? AND IFNULL(categorization_style, 0) != ? \"\n          \"LIMIT 1;\";\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::warn, \"Failed to prepare cached style conflict query: {}\", sqlite3_errmsg(db));\n        return false;\n    }\n\n    sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n    int bind_index = 2;\n    if (recursive) {\n        const std::string pattern = build_recursive_dir_pattern(dir_path);\n        sqlite3_bind_text(stmt, bind_index++, pattern.c_str(), -1, SQLITE_TRANSIENT);\n    }\n    sqlite3_bind_int(stmt, bind_index, desired_style ? 1 : 0);\n\n    const bool conflict = sqlite3_step(stmt) == SQLITE_ROW;\n    sqlite3_finalize(stmt);\n    return conflict;\n}\n\nstd::optional<bool> DatabaseManager::get_directory_categorization_style(const std::string& dir_path) const {\n    if (!db) {\n        return std::nullopt;\n    }\n\n    const char* sql =\n        \"SELECT categorization_style FROM file_categorization WHERE dir_path = ? LIMIT 1;\";\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::warn, \"Failed to prepare cached style query: {}\", sqlite3_errmsg(db));\n        return std::nullopt;\n    }\n    sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n\n    std::optional<bool> result;\n    if (sqlite3_step(stmt) == SQLITE_ROW) {\n        // If the column exists but is NULL (older rows), treat as \"false\" (refined) to compare\n        // against the user's current preference.\n        result = (sqlite3_column_type(stmt, 0) != SQLITE_NULL)\n                     ? (sqlite3_column_int(stmt, 0) != 0)\n                     : false;\n    }\n    sqlite3_finalize(stmt);\n    return result;\n}\n\nstd::vector<CategorizedFile>\nDatabaseManager::remove_empty_categorizations(const std::string& dir_path) {\n    std::vector<CategorizedFile> removed;\n    if (!db) {\n        return removed;\n    }\n\n    const char* sql = R\"(\n        SELECT file_name, file_type, IFNULL(category, ''), IFNULL(subcategory, ''), taxonomy_id\n        FROM file_categorization\n        WHERE dir_path = ?\n          AND (category IS NULL OR TRIM(category) = '' OR subcategory IS NULL OR TRIM(subcategory) = '')\n          AND (suggested_name IS NULL OR TRIM(suggested_name) = '')\n          AND IFNULL(rename_only, 0) = 0;\n    )\";\n\n    sqlite3_stmt* stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare empty categorization query: {}\", sqlite3_errmsg(db));\n        return removed;\n    }\n\n    if (sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to bind directory path for empty categorization query: {}\", sqlite3_errmsg(db));\n        sqlite3_finalize(stmt);\n        return removed;\n    }\n\n    while (sqlite3_step(stmt) == SQLITE_ROW) {\n        const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));\n        const char* type = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));\n        const char* category = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));\n        const char* subcategory = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));\n\n        std::string file_name = name ? name : \"\";\n        std::string type_str = type ? type : \"\";\n        FileType entry_type = (type_str == \"D\") ? FileType::Directory : FileType::File;\n\n        int taxonomy_id = 0;\n        if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) {\n            taxonomy_id = sqlite3_column_int(stmt, 4);\n        }\n\n        removed.push_back({dir_path,\n                           file_name,\n                           entry_type,\n                           category ? category : \"\",\n                           subcategory ? subcategory : \"\",\n                           taxonomy_id});\n    }\n\n    sqlite3_finalize(stmt);\n    for (const auto& entry : removed) {\n        remove_file_categorization(entry.file_path, entry.file_name, entry.type);\n    }\n    return removed;\n}\n\nvoid DatabaseManager::increment_taxonomy_frequency(int taxonomy_id) {\n    if (!db || taxonomy_id <= 0) return;\n\n    const char *sql =\n        \"UPDATE category_taxonomy \"\n        \"SET frequency = (SELECT COUNT(*) FROM file_categorization WHERE taxonomy_id = ?) \"\n        \"WHERE id = ?;\";\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to prepare frequency update: {}\", sqlite3_errmsg(db));\n        return;\n    }\n\n    sqlite3_bind_int(stmt, 1, taxonomy_id);\n    sqlite3_bind_int(stmt, 2, taxonomy_id);\n    if (sqlite3_step(stmt) != SQLITE_DONE) {\n        db_log(spdlog::level::err, \"Failed to increment taxonomy frequency: {}\", sqlite3_errmsg(db));\n    }\n    sqlite3_finalize(stmt);\n}\n\nstd::vector<CategorizedFile>\nDatabaseManager::get_categorized_files(const std::string &directory_path) {\n    std::vector<CategorizedFile> categorized_files;\n    if (!db) return categorized_files;\n\n    const char *sql =\n        \"SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, \"\n        \"categorization_style, rename_only, rename_applied \"\n        \"FROM file_categorization WHERE dir_path = ?;\";\n    StatementPtr stmt = prepare_statement(db, sql);\n    if (!stmt) {\n        return categorized_files;\n    }\n\n    if (sqlite3_bind_text(stmt.get(), 1, directory_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to bind directory_path: {}\", sqlite3_errmsg(db));\n        return categorized_files;\n    }\n\n    while (sqlite3_step(stmt.get()) == SQLITE_ROW) {\n        if (auto entry = build_categorized_entry(stmt.get())) {\n            categorized_files.push_back(std::move(*entry));\n        }\n    }\n\n    return categorized_files;\n}\n\nstd::vector<CategorizedFile>\nDatabaseManager::get_categorized_files_recursive(const std::string& directory_path) {\n    std::vector<CategorizedFile> categorized_files;\n    if (!db) {\n        return categorized_files;\n    }\n\n    const char* sql =\n        \"SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, \"\n        \"categorization_style, rename_only, rename_applied \"\n        \"FROM file_categorization \"\n        \"WHERE dir_path = ? OR dir_path LIKE ? ESCAPE '\\\\';\";\n    StatementPtr stmt = prepare_statement(db, sql);\n    if (!stmt) {\n        return categorized_files;\n    }\n\n    if (sqlite3_bind_text(stmt.get(), 1, directory_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to bind directory_path: {}\", sqlite3_errmsg(db));\n        return categorized_files;\n    }\n\n    const std::string pattern = build_recursive_dir_pattern(directory_path);\n    if (sqlite3_bind_text(stmt.get(), 2, pattern.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        db_log(spdlog::level::err, \"Failed to bind recursive directory pattern: {}\", sqlite3_errmsg(db));\n        return categorized_files;\n    }\n\n    while (sqlite3_step(stmt.get()) == SQLITE_ROW) {\n        if (auto entry = build_categorized_entry(stmt.get())) {\n            categorized_files.push_back(std::move(*entry));\n        }\n    }\n\n    return categorized_files;\n}\n\nstd::optional<CategorizedFile>\nDatabaseManager::get_categorized_file(const std::string& dir_path,\n                                      const std::string& file_name,\n                                      FileType file_type) {\n    if (!db) {\n        return std::nullopt;\n    }\n\n    const char *sql =\n        \"SELECT dir_path, file_name, file_type, category, subcategory, suggested_name, taxonomy_id, \"\n        \"categorization_style, rename_only, rename_applied \"\n        \"FROM file_categorization \"\n        \"WHERE dir_path = ? AND file_name = ? AND file_type = ? \"\n        \"LIMIT 1;\";\n    StatementPtr stmt = prepare_statement(db, sql);\n    if (!stmt) {\n        return std::nullopt;\n    }\n\n    if (sqlite3_bind_text(stmt.get(), 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        return std::nullopt;\n    }\n    if (sqlite3_bind_text(stmt.get(), 2, file_name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        return std::nullopt;\n    }\n    const std::string type_str = (file_type == FileType::File) ? \"F\" : \"D\";\n    if (sqlite3_bind_text(stmt.get(), 3, type_str.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        return std::nullopt;\n    }\n\n    if (sqlite3_step(stmt.get()) == SQLITE_ROW) {\n        return build_categorized_entry(stmt.get());\n    }\n\n    return std::nullopt;\n}\n\nstd::vector<std::string>\nDatabaseManager::get_categorization_from_db(const std::string& dir_path,\n                                            const std::string& file_name,\n                                            FileType file_type) {\n    std::vector<std::string> categorization;\n    if (!db) return categorization;\n\n    const char *sql =\n        \"SELECT category, subcategory FROM file_categorization \"\n        \"WHERE dir_path = ? AND file_name = ? AND file_type = ?;\";\n    sqlite3_stmt *stmtcat = nullptr;\n\n    if (sqlite3_prepare_v2(db, sql, -1, &stmtcat, nullptr) != SQLITE_OK) {\n        return categorization;\n    }\n\n    if (sqlite3_bind_text(stmtcat, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        sqlite3_finalize(stmtcat);\n        return categorization;\n    }\n\n    std::string file_type_str = (file_type == FileType::File) ? \"F\" : \"D\";\n    if (sqlite3_bind_text(stmtcat, 2, file_name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        sqlite3_finalize(stmtcat);\n        return categorization;\n    }\n    if (sqlite3_bind_text(stmtcat, 3, file_type_str.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) {\n        sqlite3_finalize(stmtcat);\n        return categorization;\n    }\n\n    if (sqlite3_step(stmtcat) == SQLITE_ROW) {\n        const char *category = reinterpret_cast<const char *>(sqlite3_column_text(stmtcat, 0));\n        const char *subcategory = reinterpret_cast<const char *>(sqlite3_column_text(stmtcat, 1));\n        categorization.emplace_back(category ? category : \"\");\n        categorization.emplace_back(subcategory ? subcategory : \"\");\n    }\n\n    sqlite3_finalize(stmtcat);\n    return categorization;\n}\n\nbool DatabaseManager::is_file_already_categorized(const std::string &file_name) {\n    if (!db) return false;\n\n    const char *sql = \"SELECT 1 FROM file_categorization WHERE file_name = ? LIMIT 1;\";\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        return false;\n    }\n\n    sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT);\n    bool exists = sqlite3_step(stmt) == SQLITE_ROW;\n    sqlite3_finalize(stmt);\n    return exists;\n}\n\nstd::vector<std::string> DatabaseManager::get_dir_contents_from_db(const std::string &dir_path) {\n    std::vector<std::string> results;\n    if (!db) return results;\n\n    const char *sql = \"SELECT file_name FROM file_categorization WHERE dir_path = ?;\";\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        return results;\n    }\n\n    sqlite3_bind_text(stmt, 1, dir_path.c_str(), -1, SQLITE_TRANSIENT);\n    while (sqlite3_step(stmt) == SQLITE_ROW) {\n        const char *name = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));\n        results.emplace_back(name ? name : \"\");\n    }\n    sqlite3_finalize(stmt);\n    return results;\n}\n\nstd::vector<std::pair<std::string, std::string>> DatabaseManager::get_taxonomy_snapshot(\n    std::size_t max_entries,\n    CategoryLanguage language) const\n{\n    std::vector<std::pair<std::string, std::string>> snapshot;\n    if (max_entries == 0) {\n        max_entries = taxonomy_entries.size();\n    }\n    snapshot.reserve(std::min(max_entries, taxonomy_entries.size()));\n    for (const auto& entry : taxonomy_entries) {\n        if (snapshot.size() >= max_entries) {\n            break;\n        }\n        ResolvedCategory resolved{entry.id, entry.category, entry.subcategory};\n        const ResolvedCategory localized = localize_category(resolved, language);\n        snapshot.emplace_back(localized.category, localized.subcategory);\n    }\n    return snapshot;\n}\n\nbool DatabaseManager::is_duplicate_category(\n    const std::vector<std::pair<std::string, std::string>>& results,\n    const std::pair<std::string, std::string>& candidate)\n{\n    return std::any_of(results.begin(), results.end(), [&candidate](const auto& existing) {\n        return existing.first == candidate.first && existing.second == candidate.second;\n    });\n}\n\nstd::optional<std::pair<std::string, std::string>> DatabaseManager::build_recent_category_candidate(\n    const char* file_name_text,\n    const char* category_text,\n    const char* subcategory_text,\n    const std::string& normalized_extension,\n    bool has_extension) const\n{\n    std::string file_name = file_name_text ? file_name_text : \"\";\n    if (file_name.empty()) {\n        return std::nullopt;\n    }\n\n    const std::string candidate_extension = extract_extension_lower(file_name);\n    if (has_extension) {\n        if (candidate_extension != normalized_extension) {\n            return std::nullopt;\n        }\n    } else if (!candidate_extension.empty()) {\n        return std::nullopt;\n    }\n\n    std::string category = category_text ? category_text : \"\";\n    if (category.empty()) {\n        return std::nullopt;\n    }\n\n    std::string subcategory = subcategory_text ? subcategory_text : \"\";\n    return std::make_pair(std::move(category), std::move(subcategory));\n}\n\nstd::vector<std::pair<std::string, std::string>>\nDatabaseManager::get_recent_categories_for_extension(const std::string& extension,\n                                                     FileType file_type,\n                                                     std::size_t limit) const\n{\n    std::vector<std::pair<std::string, std::string>> results;\n    if (!db || limit == 0) {\n        return results;\n    }\n\n    sqlite3_stmt* stmt = nullptr;\n    const char* sql =\n        \"SELECT file_name, category, subcategory FROM file_categorization \"\n        \"WHERE file_type = ? ORDER BY timestamp DESC LIMIT ?\";\n\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        db_log(spdlog::level::warn,\n               \"Failed to prepare recent category lookup: {}\",\n               sqlite3_errmsg(db));\n        return results;\n    }\n\n    const std::string type_code(1, file_type == FileType::File ? 'F' : 'D');\n    sqlite3_bind_text(stmt, 1, type_code.c_str(), -1, SQLITE_TRANSIENT);\n    const std::size_t fetch_limit = std::max<std::size_t>(limit * 5, limit);\n    sqlite3_bind_int(stmt, 2, static_cast<int>(fetch_limit));\n\n    const std::string normalized_extension = to_lower_copy(extension);\n    const bool has_extension = !normalized_extension.empty();\n\n    while (sqlite3_step(stmt) == SQLITE_ROW) {\n        const char* file_name_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));\n        const char* category_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));\n        const char* subcategory_text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));\n\n        const auto candidate = build_recent_category_candidate(file_name_text,\n                                                               category_text,\n                                                               subcategory_text,\n                                                               normalized_extension,\n                                                               has_extension);\n        if (!candidate.has_value()) {\n            continue;\n        }\n        if (is_duplicate_category(results, *candidate)) {\n            continue;\n        }\n\n        results.push_back(*candidate);\n        if (results.size() >= limit) {\n            break;\n        }\n    }\n\n    sqlite3_finalize(stmt);\n    return results;\n}\n\nstd::string DatabaseManager::get_cached_category(const std::string &file_name) {\n    auto iter = cached_results.find(file_name);\n    if (iter != cached_results.end()) {\n        return iter->second;\n    }\n    return {};\n}\n\nvoid DatabaseManager::load_cache() {\n    cached_results.clear();\n}\n\nbool DatabaseManager::file_exists_in_db(const std::string &file_name, const std::string &file_path) {\n    if (!db) return false;\n\n    const char *sql =\n        \"SELECT 1 FROM file_categorization WHERE file_name = ? AND dir_path = ? LIMIT 1;\";\n    sqlite3_stmt *stmt = nullptr;\n    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        return false;\n    }\n\n    sqlite3_bind_text(stmt, 1, file_name.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, file_path.c_str(), -1, SQLITE_TRANSIENT);\n    bool exists = sqlite3_step(stmt) == SQLITE_ROW;\n    sqlite3_finalize(stmt);\n    return exists;\n}\n"
  },
  {
    "path": "app/lib/DialogUtils.cpp",
    "content": "#include \"DialogUtils.hpp\"\n\n#include <QMessageBox>\n#include <QObject>\n#include <QString>\n\nvoid DialogUtils::show_error_dialog(QWidget* parent, const std::string& message)\n{\n    QMessageBox::critical(parent, QObject::tr(\"Error\"), QString::fromStdString(message));\n}\n"
  },
  {
    "path": "app/lib/DocumentTextAnalyzer.cpp",
    "content": "#include \"DocumentTextAnalyzer.hpp\"\n\n#include \"ILLMClient.hpp\"\n\n#include <QProcess>\n#include <QStandardPaths>\n#include <QStringList>\n\n#if defined(AI_FILE_SORTER_USE_PDFIUM)\n#include \"fpdf_doc.h\"\n#include \"fpdf_text.h\"\n#include \"fpdfview.h\"\n#endif\n#if defined(AI_FILE_SORTER_USE_LIBZIP)\n#include <zip.h>\n#endif\n#if defined(AI_FILE_SORTER_USE_PUGIXML)\n#include <pugixml.hpp>\n#endif\n\n#if __has_include(<jsoncpp/json/json.h>)\n#include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n#include <json/json.h>\n#else\n#error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <array>\n#include <algorithm>\n#include <cctype>\n#include <fstream>\n#include <initializer_list>\n#include <regex>\n#include <sstream>\n#include <stdexcept>\n#include <string_view>\n#include <unordered_set>\n#include <vector>\n\nnamespace {\nconstexpr size_t kDefaultMaxChars = 8000;\nconstexpr int kDefaultMaxTokens = 256;\nconstexpr size_t kMaxProcessOutput = 200000;\n\nstd::string to_lower_copy(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nstd::string trim_copy(const std::string& value) {\n    auto result = value;\n    const auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space));\n    result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end());\n    return result;\n}\n\nstd::string collapse_whitespace(const std::string& value) {\n    std::string collapsed;\n    collapsed.reserve(value.size());\n    bool last_space = false;\n    for (unsigned char ch : value) {\n        if (std::isspace(ch)) {\n            if (!last_space) {\n                collapsed.push_back(' ');\n                last_space = true;\n            }\n        } else {\n            collapsed.push_back(static_cast<char>(ch));\n            last_space = false;\n        }\n    }\n    return trim_copy(collapsed);\n}\n\nQString sanitize_utf8_text(const std::string& value) {\n    QString cleaned = QString::fromUtf8(value.c_str());\n    cleaned.remove(QChar::ReplacementCharacter);\n    return cleaned.normalized(QString::NormalizationForm_C);\n}\n\nstd::vector<std::string> split_words(const QString& value) {\n    std::vector<std::string> words;\n    QString current;\n    for (const QChar ch : value) {\n        if (ch.isLetterOrNumber()) {\n            current.append(ch.toLower());\n        } else if (!current.isEmpty()) {\n            words.emplace_back(current.toUtf8().toStdString());\n            current.clear();\n        }\n    }\n    if (!current.isEmpty()) {\n        words.emplace_back(current.toUtf8().toStdString());\n    }\n    return words;\n}\n\nstd::string strip_xml_tags(const std::string& xml) {\n    std::string output;\n    output.reserve(xml.size());\n    bool in_tag = false;\n    for (char ch : xml) {\n        if (ch == '<') {\n            in_tag = true;\n            continue;\n        }\n        if (ch == '>') {\n            in_tag = false;\n            continue;\n        }\n        if (!in_tag) {\n            output.push_back(ch);\n        }\n    }\n    return output;\n}\n\nvoid replace_all(std::string& value, std::string_view from, std::string_view to) {\n    if (from.empty()) {\n        return;\n    }\n    size_t pos = 0;\n    while ((pos = value.find(from.data(), pos, from.size())) != std::string::npos) {\n        value.replace(pos, from.size(), to.data(), to.size());\n        pos += to.size();\n    }\n}\n\nstd::string decode_basic_entities(std::string value) {\n    replace_all(value, \"&amp;\", \"&\");\n    replace_all(value, \"&lt;\", \"<\");\n    replace_all(value, \"&gt;\", \">\");\n    replace_all(value, \"&quot;\", \"\\\"\");\n    replace_all(value, \"&apos;\", \"'\");\n    return value;\n}\n\n#if defined(AI_FILE_SORTER_USE_PUGIXML)\nvoid append_node_text(const pugi::xml_node& node, std::string& out) {\n    if (node.type() == pugi::node_pcdata || node.type() == pugi::node_cdata) {\n        out.append(node.value());\n        out.push_back(' ');\n    }\n    for (const auto& child : node.children()) {\n        append_node_text(child, out);\n    }\n}\n#endif\n\nstd::string extract_xml_text(const std::string& xml) {\n#if defined(AI_FILE_SORTER_USE_PUGIXML)\n    pugi::xml_document doc;\n    pugi::xml_parse_result result = doc.load_string(xml.c_str(), pugi::parse_default | pugi::parse_ws_pcdata);\n    if (result) {\n        std::string out;\n        out.reserve(xml.size());\n        append_node_text(doc, out);\n        return out;\n    }\n#endif\n    return strip_xml_tags(xml);\n}\n\nstd::optional<std::string> run_process(const QString& program,\n                                       const QStringList& args,\n                                       int timeout_ms) {\n    QProcess process;\n    process.start(program, args);\n    if (!process.waitForStarted()) {\n        return std::nullopt;\n    }\n    if (!process.waitForFinished(timeout_ms)) {\n        process.kill();\n        process.waitForFinished();\n        return std::nullopt;\n    }\n    if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {\n        return std::nullopt;\n    }\n    const QByteArray output = process.readAllStandardOutput();\n    std::string result(output.constData(), static_cast<size_t>(output.size()));\n    if (result.size() > kMaxProcessOutput) {\n        result.resize(kMaxProcessOutput);\n    }\n    return result;\n}\n\nstd::optional<QString> find_executable(const QString& name) {\n    const QString exe = QStandardPaths::findExecutable(name);\n    if (exe.isEmpty()) {\n        return std::nullopt;\n    }\n    return exe;\n}\n\n#if defined(AI_FILE_SORTER_USE_LIBZIP)\nstd::optional<std::string> extract_zip_member_libzip(const std::filesystem::path& path,\n                                                     std::initializer_list<QString> members) {\n    int error_code = 0;\n    zip_t* archive = zip_open(path.string().c_str(), ZIP_RDONLY, &error_code);\n    if (!archive) {\n        return std::nullopt;\n    }\n    for (const auto& member : members) {\n        const QByteArray member_name = member.toUtf8();\n        zip_file_t* file = zip_fopen(archive, member_name.constData(), 0);\n        if (!file) {\n            continue;\n        }\n        std::string output;\n        output.reserve(kMaxProcessOutput);\n        std::array<char, 4096> buffer{};\n        zip_int64_t read = 0;\n        while ((read = zip_fread(file, buffer.data(), buffer.size())) > 0) {\n            output.append(buffer.data(), static_cast<size_t>(read));\n            if (output.size() >= kMaxProcessOutput) {\n                output.resize(kMaxProcessOutput);\n                break;\n            }\n        }\n        zip_fclose(file);\n        if (!output.empty()) {\n            zip_close(archive);\n            return output;\n        }\n    }\n    zip_close(archive);\n    return std::nullopt;\n}\n#endif\n\nstd::optional<std::string> extract_zip_member(const std::filesystem::path& path,\n                                              std::initializer_list<QString> members,\n                                              int timeout_ms)\n{\n#if defined(AI_FILE_SORTER_USE_LIBZIP)\n    if (auto output = extract_zip_member_libzip(path, members)) {\n        return output;\n    }\n#endif\n    const auto unzip = find_executable(QStringLiteral(\"unzip\"));\n    if (!unzip) {\n        return std::nullopt;\n    }\n    const QString file_path = QString::fromStdString(path.string());\n    for (const auto& member : members) {\n        if (auto output = run_process(*unzip, {QStringLiteral(\"-p\"), file_path, member}, timeout_ms)) {\n            if (!output->empty()) {\n                return output;\n            }\n        }\n    }\n    return std::nullopt;\n}\n\nstd::string read_file_prefix(const std::filesystem::path& path, size_t max_chars) {\n    std::ifstream file(path, std::ios::binary);\n    if (!file) {\n        return {};\n    }\n    std::string buffer;\n    buffer.resize(max_chars);\n    file.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));\n    buffer.resize(static_cast<size_t>(file.gcount()));\n    buffer.erase(std::remove(buffer.begin(), buffer.end(), '\\0'), buffer.end());\n    return buffer;\n}\n\nstd::string truncate_excerpt(const std::string& text, size_t max_chars) {\n    if (text.size() <= max_chars) {\n        return text;\n    }\n    const size_t head = max_chars * 3 / 4;\n    const size_t tail = max_chars - head;\n    return text.substr(0, head) + \"\\n...\\n\" + text.substr(text.size() - tail);\n}\n\nstd::optional<std::string> normalize_date(const std::string& input) {\n    std::smatch match;\n    static const std::regex kIsoDate(R\"((\\d{4})-(\\d{2})-(\\d{2}))\");\n    if (std::regex_search(input, match, kIsoDate)) {\n        return match.str(1) + \"-\" + match.str(2);\n    }\n    static const std::regex kPdfDate(R\"(D:(\\d{4})(\\d{2})(\\d{2}))\");\n    if (std::regex_search(input, match, kPdfDate)) {\n        return match.str(1) + \"-\" + match.str(2);\n    }\n    static const std::regex kCompact(R\"(\\b(\\d{4})(\\d{2})(\\d{2})\\b)\");\n    if (std::regex_search(input, match, kCompact)) {\n        return match.str(1) + \"-\" + match.str(2);\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> extract_docx_date(const std::filesystem::path& path) {\n    auto xml = extract_zip_member(path, {QStringLiteral(\"docProps/core.xml\")}, 5000);\n    if (!xml) {\n        return std::nullopt;\n    }\n    static const std::regex kCreatedTag(R\"(<dcterms:created[^>]*>([^<]+)</dcterms:created>)\");\n    std::smatch match;\n    if (std::regex_search(*xml, match, kCreatedTag)) {\n        return normalize_date(match.str(1));\n    }\n    static const std::regex kAltCreatedTag(R\"(<cp:created[^>]*>([^<]+)</cp:created>)\");\n    if (std::regex_search(*xml, match, kAltCreatedTag)) {\n        return normalize_date(match.str(1));\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> extract_pdf_date(const std::filesystem::path& path) {\n    const QString file_path = QString::fromStdString(path.string());\n    if (const auto pdfinfo = find_executable(QStringLiteral(\"pdfinfo\"))) {\n        if (auto output = run_process(*pdfinfo, {file_path}, 4000)) {\n            std::istringstream iss(*output);\n            std::string line;\n            while (std::getline(iss, line)) {\n                if (line.rfind(\"CreationDate\", 0) == 0 || line.rfind(\"Creation Date\", 0) == 0) {\n                    if (auto parsed = normalize_date(line)) {\n                        return parsed;\n                    }\n                }\n            }\n        }\n    }\n\n    std::string raw = read_file_prefix(path, 200000);\n    if (raw.empty()) {\n        return std::nullopt;\n    }\n    static const std::regex kCreation(R\"(/CreationDate\\s*\\(([^\\)]*)\\))\");\n    std::smatch match;\n    if (std::regex_search(raw, match, kCreation)) {\n        return normalize_date(match.str(1));\n    }\n    return std::nullopt;\n}\n\n#if defined(AI_FILE_SORTER_USE_PDFIUM)\nclass PdfiumLibraryGuard {\npublic:\n    PdfiumLibraryGuard() { FPDF_InitLibrary(); }\n    ~PdfiumLibraryGuard() { FPDF_DestroyLibrary(); }\n};\n\nPdfiumLibraryGuard& pdfium_library() {\n    static PdfiumLibraryGuard guard;\n    return guard;\n}\n\nstd::string extract_pdf_text_pdfium(const std::filesystem::path& path, size_t max_chars) {\n    pdfium_library();\n    const std::string pdf_path = path.string();\n    FPDF_DOCUMENT doc = FPDF_LoadDocument(pdf_path.c_str(), nullptr);\n    if (!doc) {\n        return {};\n    }\n    const int page_count = FPDF_GetPageCount(doc);\n    std::string result;\n    for (int i = 0; i < page_count && result.size() < max_chars; ++i) {\n        FPDF_PAGE page = FPDF_LoadPage(doc, i);\n        if (!page) {\n            continue;\n        }\n        FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);\n        if (!text_page) {\n            FPDF_ClosePage(page);\n            continue;\n        }\n        const int total_chars = FPDFText_CountChars(text_page);\n        const int chunk = 4096;\n        int offset = 0;\n        while (offset < total_chars && result.size() < max_chars) {\n            const int take = std::min(chunk, total_chars - offset);\n            std::vector<unsigned short> buffer(static_cast<size_t>(take + 1));\n            const int extracted = FPDFText_GetText(text_page, offset, take, buffer.data());\n            if (extracted <= 0) {\n                break;\n            }\n            const int count = std::max(0, extracted - 1);\n            QString text = QString::fromUtf16(reinterpret_cast<const char16_t*>(buffer.data()), count);\n            result.append(text.toStdString());\n            if (result.size() >= max_chars) {\n                result.resize(max_chars);\n                break;\n            }\n            offset += take;\n        }\n        FPDFText_ClosePage(text_page);\n        FPDF_ClosePage(page);\n    }\n    FPDF_CloseDocument(doc);\n    return result;\n}\n#endif\n\nconst std::unordered_set<std::string> kDocumentExtensions = {\n    \".txt\", \".md\", \".markdown\", \".rtf\", \".csv\", \".tsv\", \".log\", \".json\", \".xml\", \".yml\", \".yaml\",\n    \".ini\", \".cfg\", \".conf\", \".html\", \".htm\", \".tex\", \".rst\", \".pdf\", \".docx\", \".xlsx\", \".pptx\",\n    \".odt\", \".ods\", \".odp\"\n};\n\nconst std::unordered_set<std::string> kTextExtensions = {\n    \".txt\", \".md\", \".markdown\", \".rtf\", \".csv\", \".tsv\", \".log\", \".json\", \".xml\", \".yml\", \".yaml\",\n    \".ini\", \".cfg\", \".conf\", \".html\", \".htm\", \".tex\", \".rst\"\n};\n\nconst std::unordered_set<std::string> kStopwords = {\n    \"a\", \"an\", \"and\", \"are\", \"as\", \"at\", \"based\", \"be\", \"by\", \"category\", \"chapter\",\n    \"description\", \"details\", \"document\", \"documents\", \"file\", \"files\", \"filename\", \"for\",\n    \"from\", \"has\", \"in\", \"is\", \"it\", \"of\", \"on\", \"only\", \"page\", \"pages\", \"pdf\", \"doc\",\n    \"docx\", \"rtf\", \"text\", \"this\", \"to\", \"txt\", \"with\", \"report\", \"notes\", \"note\", \"summary\",\n    \"overview\", \"information\", \"data\", \"untitled\", \"ppt\", \"pptx\", \"xls\", \"xlsx\", \"odt\", \"ods\",\n    \"odp\", \"presentation\", \"slides\", \"spreadsheet\"\n};\n\nstruct ParsedAnalysis {\n    std::string summary;\n    std::string filename;\n};\n\nstd::optional<ParsedAnalysis> parse_analysis_json(const std::string& response) {\n    Json::CharReaderBuilder reader;\n    Json::Value root;\n    std::string errors;\n\n    auto try_parse = [&](const std::string& payload) -> bool {\n        std::istringstream stream(payload);\n        return Json::parseFromStream(reader, stream, &root, &errors);\n    };\n\n    if (!try_parse(response)) {\n        const auto first = response.find('{');\n        const auto last = response.rfind('}');\n        if (first == std::string::npos || last == std::string::npos || last <= first) {\n            return std::nullopt;\n        }\n        if (!try_parse(response.substr(first, last - first + 1))) {\n            return std::nullopt;\n        }\n    }\n\n    if (!root.isObject()) {\n        return std::nullopt;\n    }\n\n    ParsedAnalysis parsed;\n    if (root.isMember(\"summary\")) {\n        parsed.summary = root[\"summary\"].asString();\n    } else if (root.isMember(\"description\")) {\n        parsed.summary = root[\"description\"].asString();\n    }\n\n    if (root.isMember(\"filename\")) {\n        parsed.filename = root[\"filename\"].asString();\n    } else if (root.isMember(\"name\")) {\n        parsed.filename = root[\"name\"].asString();\n    } else if (root.isMember(\"suggested_name\")) {\n        parsed.filename = root[\"suggested_name\"].asString();\n    }\n\n    return parsed;\n}\n\nstd::string first_words(const std::string& text, size_t max_words) {\n    std::istringstream iss(text);\n    std::string word;\n    std::string result;\n    size_t count = 0;\n    while (iss >> word) {\n        if (!result.empty()) {\n            result.push_back(' ');\n        }\n        result += word;\n        if (++count >= max_words) {\n            break;\n        }\n    }\n    return result;\n}\n\n} // namespace\n\nDocumentTextAnalyzer::DocumentTextAnalyzer()\n    : DocumentTextAnalyzer(Settings{})\n{}\n\nDocumentTextAnalyzer::DocumentTextAnalyzer(Settings settings)\n    : settings_(settings) {\n    if (settings_.max_characters == 0) {\n        settings_.max_characters = kDefaultMaxChars;\n    }\n    if (settings_.max_tokens <= 0) {\n        settings_.max_tokens = kDefaultMaxTokens;\n    }\n    if (settings_.max_filename_words == 0) {\n        settings_.max_filename_words = 3;\n    }\n    if (settings_.max_filename_length == 0) {\n        settings_.max_filename_length = 50;\n    }\n}\n\nDocumentAnalysisResult DocumentTextAnalyzer::analyze(const std::filesystem::path& document_path,\n                                                     ILLMClient& llm) const\n{\n    DocumentAnalysisResult result;\n    const std::string raw_text = extract_text(document_path);\n    if (raw_text.empty()) {\n        throw std::runtime_error(\"No extractable text\");\n    }\n\n    const std::string excerpt = truncate_excerpt(raw_text, settings_.max_characters);\n    const std::string prompt = build_prompt(excerpt, document_path.filename().string());\n    const std::string response = llm.complete_prompt(prompt, settings_.max_tokens);\n\n    std::string summary;\n    std::string filename;\n    if (auto parsed = parse_analysis_json(response)) {\n        summary = trim(parsed->summary);\n        filename = trim(parsed->filename);\n    }\n\n    if (summary.empty()) {\n        summary = trim(first_words(excerpt, 120));\n    }\n\n    std::string sanitized = sanitize_filename(filename, settings_.max_filename_words, settings_.max_filename_length);\n    if (sanitized.empty()) {\n        sanitized = sanitize_filename(summary, settings_.max_filename_words, settings_.max_filename_length);\n    }\n    if (sanitized.empty()) {\n        sanitized = \"document_\" + slugify(document_path.stem().string());\n    }\n\n    result.summary = summary;\n    result.suggested_name = normalize_filename(sanitized, document_path);\n    return result;\n}\n\nbool DocumentTextAnalyzer::is_supported_document(const std::filesystem::path& path) {\n    if (!path.has_extension()) {\n        return false;\n    }\n    const std::string ext = to_lower_copy(path.extension().string());\n    return kDocumentExtensions.find(ext) != kDocumentExtensions.end();\n}\n\nstd::optional<std::string> DocumentTextAnalyzer::extract_creation_date(const std::filesystem::path& path) {\n    if (!path.has_extension()) {\n        return std::nullopt;\n    }\n    const std::string ext = to_lower_copy(path.extension().string());\n    if (ext == \".pdf\") {\n        return extract_pdf_date(path);\n    }\n    if (ext == \".docx\") {\n        return extract_docx_date(path);\n    }\n    return std::nullopt;\n}\n\nstd::string DocumentTextAnalyzer::extract_text(const std::filesystem::path& path) const {\n    if (!path.has_extension()) {\n        return {};\n    }\n    const std::string ext = to_lower_copy(path.extension().string());\n\n    if (kTextExtensions.find(ext) != kTextExtensions.end()) {\n        std::string text = read_file_prefix(path, settings_.max_characters);\n        return collapse_whitespace(text);\n    }\n\n    if (ext == \".pdf\") {\n#if defined(AI_FILE_SORTER_USE_PDFIUM)\n        if (auto output = extract_pdf_text_pdfium(path, settings_.max_characters); !output.empty()) {\n            return collapse_whitespace(output);\n        }\n#endif\n        const auto pdftotext = find_executable(QStringLiteral(\"pdftotext\"));\n        if (!pdftotext) {\n            return {};\n        }\n        const QString file_path = QString::fromStdString(path.string());\n        auto output = run_process(*pdftotext,\n                                  {QStringLiteral(\"-layout\"), QStringLiteral(\"-q\"), file_path, QStringLiteral(\"-\")},\n                                  15000);\n        if (!output) {\n            return {};\n        }\n        if (output->size() > settings_.max_characters) {\n            output->resize(settings_.max_characters);\n        }\n        return collapse_whitespace(*output);\n    }\n\n    if (ext == \".docx\") {\n        auto xml = extract_zip_member(path, {QStringLiteral(\"word/document.xml\")}, 7000);\n        if (!xml) {\n            return {};\n        }\n        std::string text = extract_xml_text(*xml);\n        text = decode_basic_entities(text);\n        if (text.size() > settings_.max_characters) {\n            text.resize(settings_.max_characters);\n        }\n        return collapse_whitespace(text);\n    }\n\n    if (ext == \".xlsx\") {\n        auto xml = extract_zip_member(\n            path,\n            {QStringLiteral(\"xl/sharedStrings.xml\"),\n             QStringLiteral(\"xl/worksheets/sheet1.xml\"),\n             QStringLiteral(\"xl/worksheets/sheet2.xml\")},\n            7000);\n        if (!xml) {\n            return {};\n        }\n        std::string text = extract_xml_text(*xml);\n        text = decode_basic_entities(text);\n        if (text.size() > settings_.max_characters) {\n            text.resize(settings_.max_characters);\n        }\n        return collapse_whitespace(text);\n    }\n\n    if (ext == \".pptx\") {\n        auto xml = extract_zip_member(\n            path,\n            {QStringLiteral(\"ppt/slides/slide1.xml\"),\n             QStringLiteral(\"ppt/slides/slide2.xml\")},\n            7000);\n        if (!xml) {\n            return {};\n        }\n        std::string text = extract_xml_text(*xml);\n        text = decode_basic_entities(text);\n        if (text.size() > settings_.max_characters) {\n            text.resize(settings_.max_characters);\n        }\n        return collapse_whitespace(text);\n    }\n\n    if (ext == \".odt\" || ext == \".ods\" || ext == \".odp\") {\n        auto xml = extract_zip_member(path, {QStringLiteral(\"content.xml\")}, 7000);\n        if (!xml) {\n            return {};\n        }\n        std::string text = extract_xml_text(*xml);\n        text = decode_basic_entities(text);\n        if (text.size() > settings_.max_characters) {\n            text.resize(settings_.max_characters);\n        }\n        return collapse_whitespace(text);\n    }\n\n    return {};\n}\n\nstd::string DocumentTextAnalyzer::build_prompt(const std::string& excerpt,\n                                               const std::string& file_name) const {\n    std::ostringstream oss;\n    oss << \"Summarize the document excerpt below in at most 120 words. \"\n        << \"Then propose a short descriptive filename (max 3 words, nouns only). \"\n        << \"Use underscores between words, avoid generic words like 'document', 'file', or extensions. \"\n        << \"Return JSON only in the format: {\\\"summary\\\":\\\"...\\\",\\\"filename\\\":\\\"...\\\"}.\\n\\n\";\n    oss << \"Document filename: \" << file_name << \"\\n\";\n    oss << \"Document excerpt:\\n\" << excerpt << \"\\n\\n\";\n    oss << \"JSON:\";\n    return oss.str();\n}\n\nstd::string DocumentTextAnalyzer::sanitize_filename(const std::string& value,\n                                                    size_t max_words,\n                                                    size_t max_length) const {\n    QString cleaned = sanitize_utf8_text(value).trimmed();\n    const QString prefix = QStringLiteral(\"filename:\");\n    if (cleaned.startsWith(prefix, Qt::CaseInsensitive)) {\n        cleaned = cleaned.mid(prefix.size()).trimmed();\n    }\n    const int newline = cleaned.indexOf('\\n');\n    if (newline != -1) {\n        cleaned = cleaned.left(newline);\n    }\n    const int carriage = cleaned.indexOf('\\r');\n    if (carriage != -1) {\n        cleaned = cleaned.left(carriage);\n    }\n    if (cleaned.size() >= 2) {\n        const QChar first = cleaned.front();\n        const QChar last = cleaned.back();\n        if ((first == '\"' && last == '\"') || (first == '\\'' && last == '\\'')) {\n            cleaned = cleaned.mid(1, cleaned.size() - 2);\n        }\n    }\n\n    auto words = split_words(cleaned);\n    std::vector<std::string> filtered;\n    filtered.reserve(words.size());\n    std::unordered_set<std::string> seen;\n    for (const auto& word : words) {\n        if (word.empty()) {\n            continue;\n        }\n        if (kStopwords.find(word) != kStopwords.end()) {\n            continue;\n        }\n        if (seen.insert(word).second) {\n            filtered.push_back(word);\n        }\n        if (filtered.size() >= max_words) {\n            break;\n        }\n    }\n\n    if (filtered.empty()) {\n        return std::string();\n    }\n\n    QString joined;\n    for (size_t i = 0; i < filtered.size(); ++i) {\n        if (i > 0) {\n            joined.append('_');\n        }\n        joined.append(QString::fromUtf8(filtered[i].c_str()));\n    }\n\n    if (joined.size() > static_cast<int>(max_length)) {\n        joined = joined.left(static_cast<int>(max_length));\n    }\n    while (!joined.isEmpty() && joined.endsWith('_')) {\n        joined.chop(1);\n    }\n\n    return joined.toUtf8().toStdString();\n}\n\nstd::string DocumentTextAnalyzer::trim(std::string value) {\n    return trim_copy(value);\n}\n\nstd::string DocumentTextAnalyzer::slugify(const std::string& value) {\n    const QString input = sanitize_utf8_text(value);\n    QString slug;\n    slug.reserve(input.size());\n    bool last_sep = false;\n    for (const QChar ch : input) {\n        if (ch.isLetterOrNumber()) {\n            slug.append(ch.toLower());\n            last_sep = false;\n        } else if (!last_sep && !slug.isEmpty()) {\n            slug.append('_');\n            last_sep = true;\n        }\n    }\n    if (!slug.isEmpty() && slug.endsWith('_')) {\n        slug.chop(1);\n    }\n    if (slug.isEmpty()) {\n        slug = QStringLiteral(\"document\");\n    }\n    return slug.toUtf8().toStdString();\n}\n\nstd::string DocumentTextAnalyzer::normalize_filename(const std::string& base,\n                                                     const std::filesystem::path& original_path) {\n    const std::string ext = original_path.extension().string();\n    if (base.empty()) {\n        return original_path.filename().string();\n    }\n    return ext.empty() ? base : base + ext;\n}\n"
  },
  {
    "path": "app/lib/DryRunPreviewDialog.cpp",
    "content": "#include \"DryRunPreviewDialog.hpp\"\n\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QPushButton>\n#include <QVBoxLayout>\n#include <QLabel>\n\nDryRunPreviewDialog::DryRunPreviewDialog(const std::vector<Entry>& entries, QWidget* parent)\n    : QDialog(parent)\n{\n    setWindowTitle(tr(\"Dry run preview\"));\n    resize(900, 480);\n    setup_ui(entries);\n}\n\nvoid DryRunPreviewDialog::setup_ui(const std::vector<Entry>& entries)\n{\n    auto* layout = new QVBoxLayout(this);\n\n    table_ = new QTableWidget(this);\n    table_->setColumnCount(3);\n    table_->setHorizontalHeaderLabels(QStringList{tr(\"From\"), tr(\"\"), tr(\"To\")});\n    table_->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);\n    table_->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);\n    table_->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);\n    table_->verticalHeader()->setVisible(false);\n    table_->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    table_->setSelectionMode(QAbstractItemView::NoSelection);\n    table_->setAlternatingRowColors(true);\n\n    table_->setRowCount(static_cast<int>(entries.size()));\n    int row = 0;\n    for (const auto& entry : entries) {\n        auto* from_item = new QTableWidgetItem(QString::fromStdString(entry.from_label));\n        from_item->setToolTip(QString::fromStdString(entry.source_tooltip));\n        auto* arrow_item = new QTableWidgetItem(QStringLiteral(\"→\"));\n        auto* to_item = new QTableWidgetItem(QString::fromStdString(entry.to_label));\n        to_item->setToolTip(QString::fromStdString(entry.destination_tooltip));\n        table_->setItem(row, 0, from_item);\n        table_->setItem(row, 1, arrow_item);\n        table_->setItem(row, 2, to_item);\n        ++row;\n    }\n\n    layout->addWidget(table_, 1);\n\n    auto* button_layout = new QHBoxLayout();\n    button_layout->addStretch(1);\n    auto* close_button = new QPushButton(tr(\"Close\"), this);\n    connect(close_button, &QPushButton::clicked, this, &QDialog::accept);\n    button_layout->addWidget(close_button);\n    layout->addLayout(button_layout);\n}\n"
  },
  {
    "path": "app/lib/EmbeddedEnv.cpp",
    "content": "#include \"EmbeddedEnv.hpp\"\n#include \"Logger.hpp\"\n\n#include <QFile>\n#include <QIODevice>\n#include <QByteArray>\n#include <QString>\n\n#include <sstream>\n#include <cstdlib>\n#include <stdexcept>\n\n\nEmbeddedEnv::EmbeddedEnv(const std::string& resource_path)\n    : resource_path_(resource_path)\n{\n}\n\n\nvoid EmbeddedEnv::load_env() {\n    auto logger = Logger::get_logger(\"core_logger\");\n    if (logger) {\n        // logger->debug(\"Loading embedded environment from {}\", resource_path_);\n    }\n\n    std::string env_content = extract_env_content();\n    parse_env(env_content);\n\n    if (logger) {\n        // logger->info(\"Embedded environment loaded from {}\", resource_path_);\n    }\n}\n\n\nstd::string EmbeddedEnv::extract_env_content()\n{\n    QFile file(QString::fromStdString(resource_path_));\n    if (!file.open(QIODevice::ReadOnly)) {\n        const std::string error_message =\n            \"Failed to load embedded .env file from resource: \" + resource_path_;\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->error(\"{}\", error_message);\n        }\n        throw std::runtime_error(error_message);\n    }\n\n    const QByteArray data = file.readAll();\n    return std::string(data.constData(), static_cast<std::size_t>(data.size()));\n}\n\n\nvoid EmbeddedEnv::parse_env(const std::string& env_content) {\n    std::istringstream stream(env_content);\n    std::string line;\n    size_t loaded_entries = 0;\n\n    while (std::getline(stream, line)) {\n        if (line.empty() || line[0] == '#') {\n            continue;\n        }\n\n        std::size_t equal_pos = line.find('=');\n        if (equal_pos == std::string::npos) {\n            std::string message = \"Invalid .env line: \" + line;\n            if (auto logger = Logger::get_logger(\"core_logger\")) {\n                logger->warn(\"{}\", message);\n            }\n            throw std::runtime_error(message);\n        }\n\n        std::string key = line.substr(0, equal_pos);\n        std::string value = line.substr(equal_pos + 1);\n\n        key = trim(key);\n        value = trim(value);\n\n        // Set the environment variable\n#if defined(_WIN32)\n        _putenv_s(key.c_str(), value.c_str());  // Windows-specific\n#else\n        setenv(key.c_str(), value.c_str(), 1);  // POSIX-compliant\n#endif\n        ++loaded_entries;\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            // logger->debug(\"Loaded env key '{}'\", key);\n        }\n    }\n\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->info(\"Loaded {} environment variable(s) from embedded resource\", loaded_entries);\n    }\n}\n\n\nstd::string EmbeddedEnv::trim(const std::string& str) {\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    std::size_t start = str.find_first_not_of(whitespace);\n    std::size_t end = str.find_last_not_of(whitespace);\n\n    if (start == std::string::npos || end == std::string::npos) {\n        return \"\";\n    }\n\n    return str.substr(start, end - start + 1);\n}\n"
  },
  {
    "path": "app/lib/FileScanner.cpp",
    "content": "#include \"FileScanner.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include <algorithm>\n#include <iostream>\n#include <filesystem>\n#include <optional>\n#include <unordered_set>\n\n#ifdef _WIN32\n#include <windows.h>\n#endif\n\nnamespace fs = std::filesystem;\n\nnamespace {\n\nconstexpr fs::directory_options kIteratorOptions =\n    fs::directory_options::skip_permission_denied;\n\n} // namespace\n\nstruct FileScanner::ScanContext {\n    bool include_files{false};\n    bool include_directories{false};\n    bool include_hidden{false};\n    std::shared_ptr<spdlog::logger> logger;\n};\n\nstd::vector<FileEntry>\nFileScanner::get_directory_entries(const std::string &directory_path,\n                                   FileScanOptions options)\n{\n    std::vector<FileEntry> file_paths_and_names;\n    auto logger = Logger::get_logger(\"core_logger\");\n\n    if (logger) {\n        logger->debug(\"Scanning directory '{}' with options mask {}\", directory_path, static_cast<int>(options));\n    }\n\n    ScanContext context;\n    context.include_files = has_flag(options, FileScanOptions::Files);\n    context.include_directories = has_flag(options, FileScanOptions::Directories);\n    context.include_hidden = has_flag(options, FileScanOptions::HiddenFiles);\n    context.logger = logger;\n    const bool recursive = has_flag(options, FileScanOptions::Recursive);\n\n    try {\n        const fs::path scan_path = Utils::utf8_to_path(directory_path);\n        if (!recursive) {\n            scan_non_recursive(scan_path, context, file_paths_and_names);\n        } else {\n            scan_recursive(scan_path, context, file_paths_and_names);\n        }\n    } catch (const fs::filesystem_error& ex) {\n        if (logger) {\n            logger->warn(\"Error while scanning '{}': {}\", directory_path, ex.what());\n        }\n        throw;\n    }\n\n    if (logger) {\n        logger->info(\"Directory scan complete for '{}': {} item(s) queued\", directory_path,\n                     file_paths_and_names.size());\n    }\n\n    return file_paths_and_names;\n}\n\nvoid FileScanner::scan_non_recursive(const fs::path& scan_path,\n                                     const ScanContext& context,\n                                     std::vector<FileEntry>& results)\n{\n    std::error_code ec;\n    fs::directory_iterator it(scan_path, kIteratorOptions, ec);\n    if (ec) {\n        throw fs::filesystem_error(\"directory_iterator\", scan_path, ec);\n    }\n\n    const fs::directory_iterator end;\n    while (it != end) {\n        fs::directory_entry entry = *it;\n\n        std::error_code increment_ec;\n        it.increment(increment_ec);\n\n        if (auto entry_info = build_entry(entry, context)) {\n            results.push_back(std::move(*entry_info));\n        }\n\n        if (increment_ec) {\n            log_scan_warning(context, scan_path, increment_ec,\n                             \"Stopping scan of directory after filesystem error\");\n            break;\n        }\n    }\n}\n\nvoid FileScanner::scan_recursive(const fs::path& scan_path,\n                                 const ScanContext& context,\n                                 std::vector<FileEntry>& results)\n{\n    std::vector<fs::path> pending_dirs;\n    pending_dirs.push_back(scan_path);\n\n    while (!pending_dirs.empty()) {\n        const fs::path current_dir = pending_dirs.back();\n        pending_dirs.pop_back();\n\n        std::error_code open_ec;\n        fs::directory_iterator it(current_dir, kIteratorOptions, open_ec);\n        if (open_ec) {\n            if (current_dir == scan_path) {\n                throw fs::filesystem_error(\"directory_iterator\", current_dir, open_ec);\n            }\n            log_scan_warning(context, current_dir, open_ec,\n                             \"Skipping directory after filesystem error\");\n            continue;\n        }\n\n        const fs::directory_iterator end;\n        while (it != end) {\n            fs::directory_entry entry = *it;\n            const fs::path entry_path = entry.path();\n            const std::string full_path = Utils::path_to_utf8(entry_path);\n            const std::string file_name = Utils::path_to_utf8(entry_path.filename());\n\n            std::error_code dir_ec;\n            const bool is_directory = entry.is_directory(dir_ec);\n            if (dir_ec) {\n                log_scan_warning(context, entry_path, dir_ec,\n                                 \"Skipping entry after filesystem error\");\n            } else {\n                const bool bundle = is_file_bundle(entry_path, is_directory);\n                const bool skip_entry = should_skip_entry(entry_path, file_name, context, full_path);\n                if (!skip_entry) {\n                    if (auto type = classify_entry(entry, bundle, is_directory, context)) {\n                        results.push_back(FileEntry{full_path, file_name, *type});\n                    }\n                }\n                if (is_directory && !bundle && !skip_entry) {\n                    pending_dirs.push_back(entry_path);\n                }\n            }\n\n            std::error_code increment_ec;\n            it.increment(increment_ec);\n            if (increment_ec) {\n                log_scan_warning(context, current_dir, increment_ec,\n                                 \"Stopping scan of directory after filesystem error\");\n                break;\n            }\n        }\n    }\n}\n\nvoid FileScanner::log_scan_warning(const ScanContext& context,\n                                   const fs::path& path,\n                                   const std::error_code& error,\n                                   const char* action) const\n{\n    if (!context.logger) {\n        return;\n    }\n    context.logger->warn(\"{} '{}': {}\", action, Utils::path_to_utf8(path), error.message());\n}\n\n\nbool FileScanner::is_file_hidden(const fs::path &path) const {\n#ifdef _WIN32\n    DWORD attrs = GetFileAttributesW(path.c_str());\n    return (attrs != INVALID_FILE_ATTRIBUTES) &&\n           (attrs & FILE_ATTRIBUTE_HIDDEN);\n#else\n    return path.filename().string().starts_with(\".\");\n#endif\n}\n\n\nbool FileScanner::is_junk_file(const std::string& name) const {\n    static const std::unordered_set<std::string> junk = {\n        \".DS_Store\", \"Thumbs.db\", \"desktop.ini\"\n    };\n    return junk.contains(name);\n}\n\n\nbool FileScanner::is_file_bundle(const fs::path& path, bool is_directory) const {\n    static const std::unordered_set<std::string> bundle_extensions = {\n        \".app\", \".utm\", \".vmwarevm\", \".pvm\", \".vbox\", \".pkg\", \".mpkg\",\n        \".prefPane\", \".plugin\", \".framework\", \".kext\", \".qlgenerator\",\n        \".mdimporter\", \".wdgt\", \".scptd\", \".nib\", \".xib\"\n    };\n    if (!is_directory) {\n        return false;\n    }\n\n    std::string ext = Utils::path_to_utf8(path.extension());\n    std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);\n\n    return bundle_extensions.contains(ext);\n}\n\nstd::optional<FileEntry> FileScanner::build_entry(const fs::directory_entry& entry,\n                                                  const ScanContext& context)\n{\n    const fs::path& entry_path = entry.path();\n    std::string full_path = Utils::path_to_utf8(entry_path);\n    std::string file_name = Utils::path_to_utf8(entry_path.filename());\n\n    if (should_skip_entry(entry_path, file_name, context, full_path)) {\n        return std::nullopt;\n    }\n\n    std::error_code dir_ec;\n    const bool is_directory = entry.is_directory(dir_ec);\n    if (dir_ec) {\n        log_scan_warning(context, entry_path, dir_ec,\n                         \"Skipping entry after filesystem error\");\n        return std::nullopt;\n    }\n\n    const bool bundle = is_file_bundle(entry_path, is_directory);\n    if (auto type = classify_entry(entry, bundle, is_directory, context)) {\n        return FileEntry{std::move(full_path), std::move(file_name), *type};\n    }\n    return std::nullopt;\n}\n\nbool FileScanner::should_skip_entry(const fs::path& entry_path,\n                                    const std::string& file_name,\n                                    const ScanContext& context,\n                                    const std::string& full_path) const\n{\n    if (is_junk_file(file_name)) {\n        return true;\n    }\n\n    if (is_file_hidden(entry_path) && !context.include_hidden) {\n        if (context.logger) {\n            context.logger->trace(\"Skipping hidden entry '{}'\", full_path);\n        }\n        return true;\n    }\n\n    return false;\n}\n\nstd::optional<FileType> FileScanner::classify_entry(const fs::directory_entry& entry,\n                                                    bool bundle,\n                                                    bool is_directory,\n                                                    const ScanContext& context) const\n{\n    std::error_code regular_file_ec;\n    const bool is_regular_file = entry.is_regular_file(regular_file_ec);\n    if (regular_file_ec) {\n        log_scan_warning(context, entry.path(), regular_file_ec,\n                         \"Skipping entry after filesystem error\");\n        return std::nullopt;\n    }\n\n    const bool is_file = bundle || is_regular_file;\n    if (context.include_files && is_file) {\n        return FileType::File;\n    }\n\n    if (context.include_directories && !bundle && is_directory) {\n        return FileType::Directory;\n    }\n\n    return std::nullopt;\n}\n"
  },
  {
    "path": "app/lib/GeminiClient.cpp",
    "content": "#include \"GeminiClient.hpp\"\n\n#include \"Logger.hpp\"\n#include \"LLMErrors.hpp\"\n#include \"Utils.hpp\"\n\n#include <curl/curl.h>\n\n#if __has_include(<jsoncpp/json/json.h>)\n    #include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n    #include <json/json.h>\n#else\n    #error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <spdlog/spdlog.h>\n\n#include <cmath>\n#include <iostream>\n#include <sstream>\n#include <regex>\n#include <stdexcept>\n#include <string>\n#include <utility>\n\nnamespace {\n\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response)\n{\n    const size_t total_size = size * nmemb;\n    response->append(static_cast<const char*>(contents), total_size);\n    return total_size;\n}\n\nstd::string escape_json(const std::string& input) {\n    std::string out;\n    out.reserve(input.size() * 2);\n    for (char c : input) {\n        switch (c) {\n            case '\"': out += \"\\\\\\\"\"; break;\n            case '\\\\': out += \"\\\\\\\\\"; break;\n            case '\\n': out += \"\\\\n\"; break;\n            case '\\r': out += \"\\\\r\"; break;\n            case '\\t': out += \"\\\\t\"; break;\n            default:\n                out += c;\n        }\n    }\n    return out;\n}\n\nstruct CurlRequest {\n    CURL* handle{nullptr};\n    curl_slist* headers{nullptr};\n\n    CurlRequest() = default;\n    CurlRequest(const CurlRequest&) = delete;\n    CurlRequest& operator=(const CurlRequest&) = delete;\n\n    CurlRequest(CurlRequest&& other) noexcept\n        : handle(other.handle),\n          headers(other.headers)\n    {\n        other.handle = nullptr;\n        other.headers = nullptr;\n    }\n\n    CurlRequest& operator=(CurlRequest&& other) noexcept\n    {\n        if (this != &other) {\n            cleanup();\n            handle = other.handle;\n            headers = other.headers;\n            other.handle = nullptr;\n            other.headers = nullptr;\n        }\n        return *this;\n    }\n\n    ~CurlRequest() {\n        cleanup();\n    }\n\nprivate:\n    void cleanup()\n    {\n        if (handle) {\n            curl_easy_cleanup(handle);\n            handle = nullptr;\n        }\n        if (headers) {\n            curl_slist_free_all(headers);\n            headers = nullptr;\n        }\n    }\n};\n\nCurlRequest create_curl_request(const std::shared_ptr<spdlog::logger>& logger)\n{\n    CurlRequest request;\n    request.handle = curl_easy_init();\n    if (!request.handle) {\n        if (logger) {\n            logger->critical(\"Failed to initialize cURL handle for Gemini request\");\n        }\n        throw std::runtime_error(\"Initialization Error: Failed to initialize cURL.\");\n    }\n\n#ifdef _WIN32\n    try {\n        const auto cert_path = Utils::ensure_ca_bundle();\n        curl_easy_setopt(request.handle, CURLOPT_CAINFO, cert_path.string().c_str());\n    } catch (const std::exception& ex) {\n        throw std::runtime_error(std::string(\"Failed to stage CA bundle: \") + ex.what());\n    }\n#endif\n    return request;\n}\n\nvoid configure_request_payload(CurlRequest& request,\n                               const std::string& api_url,\n                               const std::string& payload,\n                               std::string& response_buffer)\n{\n    curl_easy_setopt(request.handle, CURLOPT_URL, api_url.c_str());\n    curl_easy_setopt(request.handle, CURLOPT_POST, 1L);\n    curl_easy_setopt(request.handle, CURLOPT_TIMEOUT, 5L);\n\n    request.headers = curl_slist_append(request.headers, \"Content-Type: application/json\");\n    curl_easy_setopt(request.handle, CURLOPT_HTTPHEADER, request.headers);\n\n    curl_easy_setopt(request.handle, CURLOPT_POSTFIELDS, payload.c_str());\n    curl_easy_setopt(request.handle, CURLOPT_WRITEFUNCTION, WriteCallback);\n    curl_easy_setopt(request.handle, CURLOPT_WRITEDATA, &response_buffer);\n}\n\nlong perform_request(CurlRequest& request, const std::shared_ptr<spdlog::logger>& logger)\n{\n    const CURLcode res = curl_easy_perform(request.handle);\n    if (res != CURLE_OK) {\n        if (logger) {\n            logger->error(\"cURL request failed: {}\", curl_easy_strerror(res));\n        }\n        throw std::runtime_error(\"Network Error: \" + std::string(curl_easy_strerror(res)));\n    }\n\n    long http_code = 0;\n    curl_easy_getinfo(request.handle, CURLINFO_RESPONSE_CODE, &http_code);\n    return http_code;\n}\n\nstd::string parse_text_response(const std::string& payload,\n                                long http_code,\n                                const std::shared_ptr<spdlog::logger>& logger)\n{\n    Json::CharReaderBuilder reader_builder;\n    Json::Value root;\n    std::istringstream response_stream(payload);\n    std::string errors;\n\n    if (!Json::parseFromStream(reader_builder, response_stream, &root, &errors)) {\n        if (logger) {\n            logger->error(\"Failed to parse JSON response: {}\", errors);\n        }\n        throw std::runtime_error(\"Response Error: Failed to parse JSON response. \" + errors);\n    }\n\n    if (http_code == 401) {\n        throw std::runtime_error(\"Authentication Error: Invalid or missing Gemini API key.\");\n    }\n    if (http_code == 403) {\n        throw std::runtime_error(\"Authorization Error: Gemini API key does not have sufficient permissions.\");\n    }\n    if (http_code >= 400) {\n        const auto& error_obj = root[\"error\"];\n        const std::string message = error_obj.isObject() ? error_obj[\"message\"].asString()\n                                                         : std::string();\n        const std::string status = error_obj.isObject() ? error_obj[\"status\"].asString()\n                                                        : std::string();\n        if (status == \"RESOURCE_EXHAUSTED\") {\n            int retry_secs = 0;\n            if (!message.empty()) {\n                std::regex retry_regex(R\"(retry in ([0-9]+(?:\\.[0-9]+)?)s)\", std::regex::icase);\n                std::smatch match;\n                if (std::regex_search(message, match, retry_regex) && match.size() > 1) {\n                    try {\n                        retry_secs = static_cast<int>(std::ceil(std::stod(match[1].str())));\n                    } catch (...) {\n                        retry_secs = 0;\n                    }\n                }\n            }\n            throw BackoffError(message.empty()\n                ? \"Gemini quota reached\"\n                : \"Gemini quota reached: \" + message, retry_secs);\n        }\n\n        std::ostringstream oss;\n        oss << \"Gemini API error\";\n        if (!status.empty()) {\n            oss << \" (\" << status << \")\";\n        }\n        if (!message.empty()) {\n            oss << \": \" << message;\n        } else {\n            oss << \" (HTTP \" << http_code << \")\";\n        }\n        throw std::runtime_error(oss.str());\n    }\n\n    const auto& candidates = root[\"candidates\"];\n    if (!candidates.isArray() || candidates.empty()) {\n        throw std::runtime_error(\"Response Error: Gemini response contained no candidates.\");\n    }\n    const auto& parts = candidates[0][\"content\"][\"parts\"];\n    if (!parts.isArray() || parts.empty()) {\n        throw std::runtime_error(\"Response Error: Gemini response missing content parts.\");\n    }\n\n    return parts[0][\"text\"].asString();\n}\n\n} // namespace\n\n\nGeminiClient::GeminiClient(std::string api_key, std::string model)\n    : api_key_(std::move(api_key)),\n      model_(std::move(model))\n{\n}\n\nvoid GeminiClient::set_prompt_logging_enabled(bool enabled)\n{\n    prompt_logging_enabled_ = enabled;\n}\n\nstd::string GeminiClient::send_api_request(const std::string& json_payload)\n{\n    if (api_key_.empty()) {\n        throw std::runtime_error(\"Missing Gemini API key.\");\n    }\n\n    const std::string model_path = effective_model().starts_with(\"models/\") ? effective_model()\n                                                                            : \"models/\" + effective_model();\n    const std::vector<std::string> api_versions = {\"v1\", \"v1beta\"};\n    std::string last_error;\n\n    for (size_t i = 0; i < api_versions.size(); ++i) {\n        std::string response_string;\n        const std::string base_url = \"https://generativelanguage.googleapis.com/\"\n            + api_versions[i]\n            + \"/\"\n            + model_path\n            + \":generateContent\";\n        const std::string api_url = base_url + \"?key=\" + api_key_;\n        auto logger = Logger::get_logger(\"core_logger\");\n\n        if (logger) {\n            logger->debug(\"Dispatching remote LLM request to {}\", base_url);\n        }\n\n        try {\n            CurlRequest request = create_curl_request(logger);\n            configure_request_payload(request, api_url, json_payload, response_string);\n            const long http_code = perform_request(request, logger);\n            if (http_code == 404 && i + 1 < api_versions.size()) {\n                // Fallback to next version (e.g., v1beta) on 404.\n                last_error = \"HTTP 404 on \" + api_versions[i];\n                continue;\n            }\n            return parse_text_response(response_string, http_code, logger);\n        } catch (const std::exception& ex) {\n            last_error = ex.what();\n            if (i + 1 < api_versions.size()) {\n                continue;\n            }\n            throw;\n        }\n    }\n\n    throw std::runtime_error(last_error.empty() ? \"Gemini request failed\" : last_error);\n}\n\nstd::string GeminiClient::effective_model() const\n{\n    return model_.empty() ? \"gemini-2.5-flash-lite\" : model_;\n}\n\nstd::string GeminiClient::categorize_file(const std::string& file_name,\n                                          const std::string& file_path,\n                                          FileType file_type,\n                                          const std::string& consistency_context)\n{\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        if (!file_path.empty()) {\n            logger->debug(\"Requesting Gemini categorization for '{}' ({}) at '{}'\",\n                          file_name, to_string(file_type), file_path);\n        } else {\n            logger->debug(\"Requesting Gemini categorization for '{}' ({})\", file_name, to_string(file_type));\n        }\n    }\n\n    std::string json_payload = make_categorization_payload(file_name, file_path, file_type, consistency_context);\n\n    if (prompt_logging_enabled_ && !last_prompt_.empty()) {\n        std::cout << \"\\n[DEV][PROMPT] Categorization request\\n\" << last_prompt_ << \"\\n\";\n    }\n\n    std::string category = send_api_request(json_payload);\n\n    if (prompt_logging_enabled_) {\n        std::cout << \"[DEV][RESPONSE] Categorization reply\\n\" << category << \"\\n\";\n    }\n\n    return category;\n}\n\nstd::string GeminiClient::make_categorization_payload(const std::string& file_name,\n                                                      const std::string& file_path,\n                                                      FileType file_type,\n                                                      const std::string& consistency_context)\n{\n    std::string prompt;\n    std::string sanitized_path = file_path;\n\n    if (!sanitized_path.empty()) {\n        prompt = \"Categorize the item with full path: \" + sanitized_path + \"\\n\";\n        prompt += \"File name: \" + file_name;\n    } else {\n        prompt = \"Categorize file: \" + file_name;\n    }\n\n    if (file_type == FileType::Directory) {\n        if (!sanitized_path.empty()) {\n            prompt = \"Categorize the directory with full path: \" + sanitized_path + \"\\nDirectory name: \" + file_name;\n        } else {\n            prompt = \"Categorize directory: \" + file_name;\n        }\n    }\n\n    if (!consistency_context.empty()) {\n        prompt += \"\\n\\n\" + consistency_context;\n    }\n\n    last_prompt_ = prompt;\n    const std::string system_prompt =\n        \"You are a file categorization assistant. If it's an installer, describe the type of software it installs. \"\n        \"Consider the filename, extension, and any directory context provided. Always reply with one line in the \"\n        \"format <Main category> : <Subcategory>. Main category must be broad (one or two words, plural). Subcategory \"\n        \"must be specific, relevant, and must not repeat the main category.\";\n\n    std::ostringstream payload;\n    const std::string merged_prompt = system_prompt + \"\\n\\n\" + prompt;\n\n    payload << \"{\";\n    payload << \"\\\"contents\\\":[\";\n    payload << \"{\\\"role\\\":\\\"user\\\",\\\"parts\\\":[{\\\"text\\\":\\\"\" << escape_json(merged_prompt) << \"\\\"}]}\";\n    payload << \"]\";\n    payload << \"}\";\n\n    return payload.str();\n}\n\nstd::string GeminiClient::make_generic_payload(const std::string& system_prompt,\n                                               const std::string& user_prompt,\n                                               int max_tokens) const\n{\n    const std::string merged_prompt = system_prompt + \"\\n\\n\" + user_prompt;\n\n    std::ostringstream payload;\n    payload << \"{\";\n    payload << \"\\\"contents\\\":[\";\n    payload << \"{\\\"role\\\":\\\"user\\\",\\\"parts\\\":[{\\\"text\\\":\\\"\" << escape_json(merged_prompt) << \"\\\"}]}\";\n    payload << \"]\";\n    if (max_tokens > 0) {\n        payload << \",\\\"generationConfig\\\":{\\\"maxOutputTokens\\\":\" << max_tokens << \"}\";\n    }\n    payload << \"}\";\n    return payload.str();\n}\n\nstd::string GeminiClient::complete_prompt(const std::string& prompt,\n                                          int max_tokens)\n{\n    static const std::string kSystem =\n        \"You are a precise assistant that returns well-formed JSON responses.\";\n    std::string json_payload = make_generic_payload(kSystem, prompt, max_tokens);\n    return send_api_request(json_payload);\n}\n"
  },
  {
    "path": "app/lib/GgmlRuntimePaths.cpp",
    "content": "#include \"GgmlRuntimePaths.hpp\"\n\n#include <algorithm>\n#include <array>\n\nnamespace GgmlRuntimePaths {\n\nnamespace {\n\nbool ends_with(const std::string& value, const std::string& suffix) {\n    if (suffix.size() > value.size()) {\n        return false;\n    }\n    return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());\n}\n\n} // namespace\n\nbool has_payload(const std::filesystem::path& dir) {\n    std::error_code ec;\n    if (!std::filesystem::exists(dir, ec) || !std::filesystem::is_directory(dir, ec)) {\n        return false;\n    }\n\n    for (const auto& entry : std::filesystem::directory_iterator(\n             dir,\n             std::filesystem::directory_options::skip_permission_denied,\n             ec)) {\n        if (ec || !entry.is_regular_file()) {\n            continue;\n        }\n        const std::string filename = entry.path().filename().string();\n        if (filename.rfind(\"libggml-\", 0) != 0) {\n            continue;\n        }\n        if (ends_with(filename, \".so\") || ends_with(filename, \".dylib\")) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstd::vector<std::filesystem::path> macos_candidate_dirs(\n    const std::filesystem::path& exe_path,\n    std::string_view ggml_subdir) {\n    if (exe_path.empty()) {\n        return {};\n    }\n\n    const std::filesystem::path exe_dir = exe_path.parent_path();\n    const std::filesystem::path subdir(ggml_subdir);\n\n    return {\n        exe_dir / \"../lib\" / \"precompiled-m1\",\n        exe_dir / \"../lib\" / \"precompiled-m2\",\n        exe_dir / \"../lib\" / \"precompiled-intel\",\n        exe_dir / \"../lib\" / subdir,\n        exe_dir / \"../../lib\" / subdir,\n        exe_dir / \"../lib\" / \"aifilesorter\",\n        exe_dir / \"../../lib\" / \"aifilesorter\",\n        exe_dir / \"../lib\",\n        exe_dir / \"../../lib\",\n    };\n}\n\nstd::optional<std::filesystem::path> resolve_macos_backend_dir(\n    const std::optional<std::filesystem::path>& current_dir,\n    const std::filesystem::path& exe_path,\n    std::string_view ggml_subdir) {\n    if (current_dir && has_payload(*current_dir)) {\n        return current_dir->lexically_normal();\n    }\n\n    for (const auto& candidate : macos_candidate_dirs(exe_path, ggml_subdir)) {\n        if (has_payload(candidate)) {\n            return candidate.lexically_normal();\n        }\n    }\n\n    return std::nullopt;\n}\n\n} // namespace GgmlRuntimePaths\n"
  },
  {
    "path": "app/lib/ImageRenameMetadataService.cpp",
    "content": "#include \"ImageRenameMetadataService.hpp\"\n\n#include \"Utils.hpp\"\n\n#include <curl/curl.h>\n\n#if __has_include(<jsoncpp/json/json.h>)\n#include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n#include <json/json.h>\n#else\n#error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <sqlite3.h>\n\n#include <algorithm>\n#include <array>\n#include <chrono>\n#include <cctype>\n#include <cmath>\n#include <cstdio>\n#include <cstring>\n#include <filesystem>\n#include <fstream>\n#include <iomanip>\n#include <initializer_list>\n#include <optional>\n#include <regex>\n#include <sstream>\n#include <string>\n#include <thread>\n#include <vector>\n\nnamespace {\n\nconstexpr char kExifPrefix[] = \"Exif\\0\\0\";\nconstexpr char kDefaultNominatimUrl[] = \"https://nominatim.openstreetmap.org/reverse\";\nconstexpr std::chrono::seconds kMinReverseInterval{1};\nconstexpr std::array<uint8_t, 8> kPngSignature = {\n    0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A\n};\nconstexpr size_t kHeifProbeOutputLimit = 256 * 1024;\n\nconstexpr uint16_t kTagDateTime = 0x0132;\nconstexpr uint16_t kTagExifIfd = 0x8769;\nconstexpr uint16_t kTagGpsIfd = 0x8825;\nconstexpr uint16_t kTagDateTimeOriginal = 0x9003;\nconstexpr uint16_t kTagCreateDate = 0x9004;\nconstexpr uint16_t kTagGpsLatitudeRef = 0x0001;\nconstexpr uint16_t kTagGpsLatitude = 0x0002;\nconstexpr uint16_t kTagGpsLongitudeRef = 0x0003;\nconstexpr uint16_t kTagGpsLongitude = 0x0004;\n\nstruct TiffEntry {\n    uint16_t tag{0};\n    uint16_t type{0};\n    uint32_t count{0};\n    uint32_t value_or_offset{0};\n    size_t raw_offset{0};\n};\n\nstruct ParsedExifMetadata {\n    std::optional<std::string> capture_date;\n    std::optional<double> latitude;\n    std::optional<double> longitude;\n};\n\nsize_t write_callback(void* contents, size_t size, size_t nmemb, void* userp)\n{\n    const size_t total = size * nmemb;\n    auto* output = static_cast<std::string*>(userp);\n    output->append(static_cast<const char*>(contents), total);\n    return total;\n}\n\nvoid configure_tls(CURL* curl)\n{\n#if defined(_WIN32)\n    const auto cert_path = Utils::ensure_ca_bundle();\n    curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str());\n#else\n    (void)curl;\n#endif\n}\n\nbool read_byte(std::ifstream& in, uint8_t& value)\n{\n    char ch = 0;\n    if (!in.get(ch)) {\n        return false;\n    }\n    value = static_cast<uint8_t>(static_cast<unsigned char>(ch));\n    return true;\n}\n\nbool read_exact(std::ifstream& in, uint8_t* data, size_t size)\n{\n    if (size == 0) {\n        return true;\n    }\n    in.read(reinterpret_cast<char*>(data), static_cast<std::streamsize>(size));\n    return in.good();\n}\n\nstd::optional<std::vector<uint8_t>> read_jpeg_exif_payload(const std::filesystem::path& image_path)\n{\n    std::ifstream in(image_path, std::ios::binary);\n    if (!in) {\n        return std::nullopt;\n    }\n\n    uint8_t soi[2] = {0, 0};\n    if (!read_exact(in, soi, sizeof(soi)) || soi[0] != 0xFF || soi[1] != 0xD8) {\n        return std::nullopt;\n    }\n\n    while (true) {\n        uint8_t prefix = 0;\n        if (!read_byte(in, prefix)) {\n            break;\n        }\n        if (prefix != 0xFF) {\n            continue;\n        }\n\n        uint8_t marker = 0;\n        do {\n            if (!read_byte(in, marker)) {\n                return std::nullopt;\n            }\n        } while (marker == 0xFF);\n\n        if (marker == 0x00) {\n            continue;\n        }\n\n        if (marker == 0xD9 || marker == 0xDA) {\n            break;\n        }\n\n        if (marker == 0x01 || (marker >= 0xD0 && marker <= 0xD7)) {\n            continue;\n        }\n\n        uint8_t length_bytes[2] = {0, 0};\n        if (!read_exact(in, length_bytes, sizeof(length_bytes))) {\n            break;\n        }\n\n        const uint16_t segment_length =\n            static_cast<uint16_t>((static_cast<uint16_t>(length_bytes[0]) << 8) | length_bytes[1]);\n        if (segment_length < 2) {\n            break;\n        }\n\n        const size_t payload_size = static_cast<size_t>(segment_length - 2);\n        if (marker == 0xE1) {\n            std::vector<uint8_t> payload(payload_size);\n            if (!read_exact(in, payload.data(), payload.size())) {\n                break;\n            }\n\n            if (payload.size() >= sizeof(kExifPrefix) - 1 &&\n                std::memcmp(payload.data(), kExifPrefix, sizeof(kExifPrefix) - 1) == 0) {\n                return std::vector<uint8_t>(payload.begin() + static_cast<std::ptrdiff_t>(sizeof(kExifPrefix) - 1),\n                                            payload.end());\n            }\n            continue;\n        }\n\n        in.seekg(static_cast<std::streamoff>(payload_size), std::ios::cur);\n        if (!in) {\n            break;\n        }\n    }\n\n    return std::nullopt;\n}\n\nstd::optional<std::vector<uint8_t>> read_file_bytes(const std::filesystem::path& path)\n{\n    std::ifstream in(path, std::ios::binary | std::ios::ate);\n    if (!in) {\n        return std::nullopt;\n    }\n\n    const std::streamoff size = in.tellg();\n    if (size < 0) {\n        return std::nullopt;\n    }\n\n    std::vector<uint8_t> bytes(static_cast<size_t>(size));\n    in.seekg(0, std::ios::beg);\n    if (!read_exact(in, bytes.data(), bytes.size())) {\n        return std::nullopt;\n    }\n\n    return bytes;\n}\n\nbool starts_with_bytes(const std::vector<uint8_t>& data, const char* prefix, size_t prefix_size)\n{\n    if (data.size() < prefix_size) {\n        return false;\n    }\n    return std::memcmp(data.data(), prefix, prefix_size) == 0;\n}\n\nbool looks_like_tiff_payload(const std::vector<uint8_t>& data)\n{\n    if (data.size() < 4) {\n        return false;\n    }\n\n    const bool little_endian = (data[0] == 'I' && data[1] == 'I');\n    const bool big_endian = (data[0] == 'M' && data[1] == 'M');\n    if (!little_endian && !big_endian) {\n        return false;\n    }\n\n    if (little_endian) {\n        return data[2] == 42 && data[3] == 0;\n    }\n    return data[2] == 0 && data[3] == 42;\n}\n\nstd::optional<std::vector<uint8_t>> read_tiff_exif_payload(const std::filesystem::path& image_path)\n{\n    const auto bytes = read_file_bytes(image_path);\n    if (!bytes || bytes->size() < 8) {\n        return std::nullopt;\n    }\n\n    if (looks_like_tiff_payload(*bytes)) {\n        return bytes;\n    }\n\n    if (starts_with_bytes(*bytes, kExifPrefix, sizeof(kExifPrefix) - 1)) {\n        std::vector<uint8_t> payload(bytes->begin() + static_cast<std::ptrdiff_t>(sizeof(kExifPrefix) - 1),\n                                     bytes->end());\n        if (looks_like_tiff_payload(payload)) {\n            return payload;\n        }\n    }\n\n    return std::nullopt;\n}\n\nstd::optional<std::vector<uint8_t>> read_png_exif_payload(const std::filesystem::path& image_path)\n{\n    std::ifstream in(image_path, std::ios::binary);\n    if (!in) {\n        return std::nullopt;\n    }\n\n    std::array<uint8_t, 8> signature{};\n    if (!read_exact(in, signature.data(), signature.size()) || signature != kPngSignature) {\n        return std::nullopt;\n    }\n\n    while (true) {\n        uint8_t chunk_header[8] = {0};\n        if (!read_exact(in, chunk_header, sizeof(chunk_header))) {\n            return std::nullopt;\n        }\n\n        const uint32_t chunk_length =\n            (static_cast<uint32_t>(chunk_header[0]) << 24) |\n            (static_cast<uint32_t>(chunk_header[1]) << 16) |\n            (static_cast<uint32_t>(chunk_header[2]) << 8) |\n            static_cast<uint32_t>(chunk_header[3]);\n\n        const std::array<char, 4> chunk_type = {\n            static_cast<char>(chunk_header[4]),\n            static_cast<char>(chunk_header[5]),\n            static_cast<char>(chunk_header[6]),\n            static_cast<char>(chunk_header[7])\n        };\n\n        std::vector<uint8_t> chunk_data(chunk_length);\n        if (!read_exact(in, chunk_data.data(), chunk_data.size())) {\n            return std::nullopt;\n        }\n\n        uint8_t crc[4] = {0};\n        if (!read_exact(in, crc, sizeof(crc))) {\n            return std::nullopt;\n        }\n\n        if (chunk_type == std::array<char, 4>{'e', 'X', 'I', 'f'}) {\n            if (starts_with_bytes(chunk_data, kExifPrefix, sizeof(kExifPrefix) - 1)) {\n                return std::vector<uint8_t>(chunk_data.begin() +\n                                                static_cast<std::ptrdiff_t>(sizeof(kExifPrefix) - 1),\n                                            chunk_data.end());\n            }\n            return chunk_data;\n        }\n\n        if (chunk_type == std::array<char, 4>{'I', 'E', 'N', 'D'}) {\n            break;\n        }\n    }\n\n    return std::nullopt;\n}\n\nstd::string to_lower_ascii(std::string value)\n{\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nstd::string file_extension_lower(const std::filesystem::path& path)\n{\n    return to_lower_ascii(Utils::path_to_utf8(path.extension()));\n}\n\nbool has_extension(const std::string& extension, std::initializer_list<const char*> choices)\n{\n    for (const char* choice : choices) {\n        if (extension == choice) {\n            return true;\n        }\n    }\n    return false;\n}\n\nsize_t tiff_type_size(uint16_t type)\n{\n    switch (type) {\n        case 1:  return 1; // BYTE\n        case 2:  return 1; // ASCII\n        case 3:  return 2; // SHORT\n        case 4:  return 4; // LONG\n        case 5:  return 8; // RATIONAL\n        default: return 0;\n    }\n}\n\nstd::optional<uint16_t> read_u16(const std::vector<uint8_t>& data,\n                                 size_t offset,\n                                 bool little_endian)\n{\n    if (offset + 2 > data.size()) {\n        return std::nullopt;\n    }\n    const uint16_t b0 = data[offset];\n    const uint16_t b1 = data[offset + 1];\n    if (little_endian) {\n        return static_cast<uint16_t>((b1 << 8) | b0);\n    }\n    return static_cast<uint16_t>((b0 << 8) | b1);\n}\n\nstd::optional<uint32_t> read_u32(const std::vector<uint8_t>& data,\n                                 size_t offset,\n                                 bool little_endian)\n{\n    if (offset + 4 > data.size()) {\n        return std::nullopt;\n    }\n\n    const uint32_t b0 = data[offset];\n    const uint32_t b1 = data[offset + 1];\n    const uint32_t b2 = data[offset + 2];\n    const uint32_t b3 = data[offset + 3];\n\n    if (little_endian) {\n        return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;\n    }\n    return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;\n}\n\nbool parse_ifd_entries(const std::vector<uint8_t>& tiff,\n                       bool little_endian,\n                       uint32_t ifd_offset,\n                       std::vector<TiffEntry>& entries)\n{\n    entries.clear();\n    if (ifd_offset + 2 > tiff.size()) {\n        return false;\n    }\n\n    const auto count_opt = read_u16(tiff, ifd_offset, little_endian);\n    if (!count_opt.has_value()) {\n        return false;\n    }\n\n    const size_t entry_count = *count_opt;\n    size_t cursor = static_cast<size_t>(ifd_offset + 2);\n    if (cursor + entry_count * 12 > tiff.size()) {\n        return false;\n    }\n\n    entries.reserve(entry_count);\n    for (size_t i = 0; i < entry_count; ++i) {\n        const size_t entry_offset = cursor + i * 12;\n\n        const auto tag_opt = read_u16(tiff, entry_offset, little_endian);\n        const auto type_opt = read_u16(tiff, entry_offset + 2, little_endian);\n        const auto count_value_opt = read_u32(tiff, entry_offset + 4, little_endian);\n        const auto value_opt = read_u32(tiff, entry_offset + 8, little_endian);\n\n        if (!tag_opt || !type_opt || !count_value_opt || !value_opt) {\n            return false;\n        }\n\n        entries.push_back(TiffEntry{*tag_opt, *type_opt, *count_value_opt, *value_opt, entry_offset});\n    }\n\n    return true;\n}\n\nconst TiffEntry* find_entry(const std::vector<TiffEntry>& entries, uint16_t tag)\n{\n    for (const auto& entry : entries) {\n        if (entry.tag == tag) {\n            return &entry;\n        }\n    }\n    return nullptr;\n}\n\nstd::optional<size_t> value_data_offset(const std::vector<uint8_t>& tiff,\n                                        const TiffEntry& entry)\n{\n    const size_t unit = tiff_type_size(entry.type);\n    if (unit == 0) {\n        return std::nullopt;\n    }\n\n    const size_t value_size = static_cast<size_t>(entry.count) * unit;\n    if (value_size == 0) {\n        return std::nullopt;\n    }\n\n    if (value_size <= 4) {\n        const size_t inline_offset = entry.raw_offset + 8;\n        if (inline_offset + value_size > tiff.size()) {\n            return std::nullopt;\n        }\n        return inline_offset;\n    }\n\n    const size_t data_offset = static_cast<size_t>(entry.value_or_offset);\n    if (data_offset + value_size > tiff.size()) {\n        return std::nullopt;\n    }\n    return data_offset;\n}\n\nstd::string trim_copy(std::string value)\n{\n    const auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space));\n    value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end());\n    return value;\n}\n\nstd::optional<std::string> read_ascii_value(const std::vector<uint8_t>& tiff,\n                                            const TiffEntry& entry)\n{\n    if (entry.type != 2 || entry.count == 0) {\n        return std::nullopt;\n    }\n\n    const auto data_offset = value_data_offset(tiff, entry);\n    if (!data_offset) {\n        return std::nullopt;\n    }\n\n    size_t length = static_cast<size_t>(entry.count);\n    if (length == 0) {\n        return std::nullopt;\n    }\n\n    const char* begin = reinterpret_cast<const char*>(tiff.data() + *data_offset);\n    const char* end = begin + length;\n\n    const char* first_null = std::find(begin, end, '\\0');\n    std::string value(begin, first_null);\n    value = trim_copy(value);\n    if (value.empty()) {\n        return std::nullopt;\n    }\n    return value;\n}\n\nstd::optional<std::array<double, 3>> read_rational_triplet(const std::vector<uint8_t>& tiff,\n                                                            const TiffEntry& entry,\n                                                            bool little_endian)\n{\n    if (entry.type != 5 || entry.count < 3) {\n        return std::nullopt;\n    }\n\n    const auto data_offset = value_data_offset(tiff, entry);\n    if (!data_offset) {\n        return std::nullopt;\n    }\n\n    std::array<double, 3> values{};\n    for (size_t i = 0; i < 3; ++i) {\n        const size_t pair_offset = *data_offset + i * 8;\n        const auto numerator = read_u32(tiff, pair_offset, little_endian);\n        const auto denominator = read_u32(tiff, pair_offset + 4, little_endian);\n        if (!numerator || !denominator || *denominator == 0) {\n            return std::nullopt;\n        }\n        values[i] = static_cast<double>(*numerator) / static_cast<double>(*denominator);\n    }\n\n    return values;\n}\n\nstd::optional<double> decode_gps_coordinate(const std::array<double, 3>& dms,\n                                            char hemisphere)\n{\n    const double degrees = dms[0];\n    const double minutes = dms[1];\n    const double seconds = dms[2];\n\n    if (!std::isfinite(degrees) || !std::isfinite(minutes) || !std::isfinite(seconds)) {\n        return std::nullopt;\n    }\n\n    double value = degrees + (minutes / 60.0) + (seconds / 3600.0);\n    if (hemisphere == 'S' || hemisphere == 'W') {\n        value = -value;\n    }\n\n    if (!std::isfinite(value)) {\n        return std::nullopt;\n    }\n    return value;\n}\n\nstd::optional<std::string> normalize_exif_date_value(const std::string& value)\n{\n    static const std::regex kDatePattern(R\"((\\d{4})[:\\-](\\d{2})[:\\-](\\d{2}))\");\n    std::smatch match;\n    if (!std::regex_search(value, match, kDatePattern)) {\n        return std::nullopt;\n    }\n\n    const std::string year = match.str(1);\n    const std::string month = match.str(2);\n    const std::string day = match.str(3);\n\n    if (year.size() != 4 || month.size() != 2 || day.size() != 2) {\n        return std::nullopt;\n    }\n\n    return year + \"-\" + month + \"-\" + day;\n}\n\nParsedExifMetadata parse_tiff_metadata(const std::vector<uint8_t>& tiff)\n{\n    ParsedExifMetadata metadata;\n    if (tiff.size() < 8) {\n        return metadata;\n    }\n\n    bool little_endian = false;\n    if (tiff[0] == 'I' && tiff[1] == 'I') {\n        little_endian = true;\n    } else if (tiff[0] == 'M' && tiff[1] == 'M') {\n        little_endian = false;\n    } else {\n        return metadata;\n    }\n\n    const auto magic = read_u16(tiff, 2, little_endian);\n    if (!magic || *magic != 42) {\n        return metadata;\n    }\n\n    const auto ifd0_offset = read_u32(tiff, 4, little_endian);\n    if (!ifd0_offset) {\n        return metadata;\n    }\n\n    std::vector<TiffEntry> ifd0_entries;\n    if (!parse_ifd_entries(tiff, little_endian, *ifd0_offset, ifd0_entries)) {\n        return metadata;\n    }\n\n    if (const TiffEntry* dt = find_entry(ifd0_entries, kTagDateTime)) {\n        if (const auto parsed = read_ascii_value(tiff, *dt)) {\n            metadata.capture_date = normalize_exif_date_value(*parsed);\n        }\n    }\n\n    uint32_t exif_ifd_offset = 0;\n    if (const TiffEntry* exif_ptr = find_entry(ifd0_entries, kTagExifIfd)) {\n        if (exif_ptr->count == 1 && exif_ptr->type == 4) {\n            exif_ifd_offset = exif_ptr->value_or_offset;\n        }\n    }\n\n    if (exif_ifd_offset != 0) {\n        std::vector<TiffEntry> exif_entries;\n        if (parse_ifd_entries(tiff, little_endian, exif_ifd_offset, exif_entries)) {\n            if (const TiffEntry* original = find_entry(exif_entries, kTagDateTimeOriginal)) {\n                if (const auto parsed = read_ascii_value(tiff, *original)) {\n                    metadata.capture_date = normalize_exif_date_value(*parsed);\n                }\n            }\n            if (!metadata.capture_date.has_value()) {\n                if (const TiffEntry* created = find_entry(exif_entries, kTagCreateDate)) {\n                    if (const auto parsed = read_ascii_value(tiff, *created)) {\n                        metadata.capture_date = normalize_exif_date_value(*parsed);\n                    }\n                }\n            }\n        }\n    }\n\n    uint32_t gps_ifd_offset = 0;\n    if (const TiffEntry* gps_ptr = find_entry(ifd0_entries, kTagGpsIfd)) {\n        if (gps_ptr->count == 1 && gps_ptr->type == 4) {\n            gps_ifd_offset = gps_ptr->value_or_offset;\n        }\n    }\n\n    if (gps_ifd_offset != 0) {\n        std::vector<TiffEntry> gps_entries;\n        if (parse_ifd_entries(tiff, little_endian, gps_ifd_offset, gps_entries)) {\n            char lat_ref = '\\0';\n            char lon_ref = '\\0';\n            std::optional<std::array<double, 3>> lat_dms;\n            std::optional<std::array<double, 3>> lon_dms;\n\n            if (const TiffEntry* lat_ref_entry = find_entry(gps_entries, kTagGpsLatitudeRef)) {\n                if (const auto text = read_ascii_value(tiff, *lat_ref_entry); text && !text->empty()) {\n                    lat_ref = static_cast<char>(std::toupper(static_cast<unsigned char>((*text)[0])));\n                }\n            }\n\n            if (const TiffEntry* lon_ref_entry = find_entry(gps_entries, kTagGpsLongitudeRef)) {\n                if (const auto text = read_ascii_value(tiff, *lon_ref_entry); text && !text->empty()) {\n                    lon_ref = static_cast<char>(std::toupper(static_cast<unsigned char>((*text)[0])));\n                }\n            }\n\n            if (const TiffEntry* lat_entry = find_entry(gps_entries, kTagGpsLatitude)) {\n                lat_dms = read_rational_triplet(tiff, *lat_entry, little_endian);\n            }\n\n            if (const TiffEntry* lon_entry = find_entry(gps_entries, kTagGpsLongitude)) {\n                lon_dms = read_rational_triplet(tiff, *lon_entry, little_endian);\n            }\n\n            if (lat_dms && lon_dms && (lat_ref == 'N' || lat_ref == 'S') && (lon_ref == 'E' || lon_ref == 'W')) {\n                const auto latitude = decode_gps_coordinate(*lat_dms, lat_ref);\n                const auto longitude = decode_gps_coordinate(*lon_dms, lon_ref);\n                if (latitude && longitude &&\n                    std::abs(*latitude) <= 90.0 && std::abs(*longitude) <= 180.0) {\n                    metadata.latitude = *latitude;\n                    metadata.longitude = *longitude;\n                }\n            }\n        }\n    }\n\n    return metadata;\n}\n\nstd::string shell_quote_argument(const std::string& raw)\n{\n#if defined(_WIN32)\n    std::string output;\n    output.reserve(raw.size() + 2);\n    output.push_back('\"');\n    for (char ch : raw) {\n        if (ch == '\"') {\n            output += \"\\\\\\\"\";\n        } else {\n            output.push_back(ch);\n        }\n    }\n    output.push_back('\"');\n    return output;\n#else\n    std::string output;\n    output.reserve(raw.size() + 2);\n    output.push_back('\\'');\n    for (char ch : raw) {\n        if (ch == '\\'') {\n            output += \"'\\\"'\\\"'\";\n        } else {\n            output.push_back(ch);\n        }\n    }\n    output.push_back('\\'');\n    return output;\n#endif\n}\n\nstd::optional<std::string> run_command_capture_output(const std::string& command)\n{\n#if defined(_WIN32)\n    FILE* pipe = _popen(command.c_str(), \"rb\");\n#else\n    FILE* pipe = popen(command.c_str(), \"r\");\n#endif\n    if (!pipe) {\n        return std::nullopt;\n    }\n\n    std::array<char, 4096> buffer{};\n    std::string output;\n    while (std::fgets(buffer.data(), static_cast<int>(buffer.size()), pipe) != nullptr) {\n        output.append(buffer.data());\n        if (output.size() > kHeifProbeOutputLimit) {\n            break;\n        }\n    }\n\n#if defined(_WIN32)\n    const int exit_code = _pclose(pipe);\n#else\n    const int exit_code = pclose(pipe);\n#endif\n\n    if (exit_code != 0) {\n        return std::nullopt;\n    }\n    return output;\n}\n\nstd::optional<std::string> json_string_field(const Json::Value& object, const char* key)\n{\n    if (!object.isObject() || !key || !object.isMember(key) || !object[key].isString()) {\n        return std::nullopt;\n    }\n    const std::string value = trim_copy(object[key].asString());\n    if (value.empty()) {\n        return std::nullopt;\n    }\n    return value;\n}\n\nstd::optional<double> json_number_field(const Json::Value& object, const char* key)\n{\n    if (!object.isObject() || !key || !object.isMember(key)) {\n        return std::nullopt;\n    }\n\n    const Json::Value& value = object[key];\n    if (value.isDouble() || value.isInt() || value.isUInt() || value.isInt64() || value.isUInt64()) {\n        return value.asDouble();\n    }\n\n    if (value.isString()) {\n        const std::string text = trim_copy(value.asString());\n        if (text.empty()) {\n            return std::nullopt;\n        }\n        try {\n            size_t consumed = 0;\n            const double numeric = std::stod(text, &consumed);\n            if (consumed == text.size()) {\n                return numeric;\n            }\n        } catch (const std::exception&) {\n            return std::nullopt;\n        }\n    }\n\n    return std::nullopt;\n}\n\nParsedExifMetadata extract_heif_metadata_with_exiftool(const std::filesystem::path& image_path)\n{\n    ParsedExifMetadata metadata;\n\n    const std::string path_utf8 = Utils::path_to_utf8(image_path);\n    if (path_utf8.empty()) {\n        return metadata;\n    }\n\n    std::ostringstream command;\n#if defined(_WIN32)\n    command << \"exiftool -j -n -DateTimeOriginal -CreateDate -DateTime -GPSLatitude -GPSLongitude -- \"\n            << shell_quote_argument(path_utf8) << \" 2>NUL\";\n#else\n    command << \"exiftool -j -n -DateTimeOriginal -CreateDate -DateTime -GPSLatitude -GPSLongitude -- \"\n            << shell_quote_argument(path_utf8) << \" 2>/dev/null\";\n#endif\n\n    const auto output = run_command_capture_output(command.str());\n    if (!output || output->empty()) {\n        return metadata;\n    }\n\n    Json::CharReaderBuilder reader_builder;\n    Json::Value root;\n    std::string errors;\n    std::istringstream stream(*output);\n    if (!Json::parseFromStream(reader_builder, stream, &root, &errors) ||\n        !root.isArray() || root.empty() || !root[0].isObject()) {\n        return metadata;\n    }\n\n    const Json::Value& item = root[0];\n\n    if (const auto date = json_string_field(item, \"DateTimeOriginal\")) {\n        metadata.capture_date = normalize_exif_date_value(*date);\n    }\n    if (!metadata.capture_date.has_value()) {\n        if (const auto date = json_string_field(item, \"CreateDate\")) {\n            metadata.capture_date = normalize_exif_date_value(*date);\n        }\n    }\n    if (!metadata.capture_date.has_value()) {\n        if (const auto date = json_string_field(item, \"DateTime\")) {\n            metadata.capture_date = normalize_exif_date_value(*date);\n        }\n    }\n\n    const auto latitude = json_number_field(item, \"GPSLatitude\");\n    const auto longitude = json_number_field(item, \"GPSLongitude\");\n    if (latitude && longitude &&\n        std::isfinite(*latitude) && std::isfinite(*longitude) &&\n        std::abs(*latitude) <= 90.0 && std::abs(*longitude) <= 180.0) {\n        metadata.latitude = *latitude;\n        metadata.longitude = *longitude;\n    }\n\n    return metadata;\n}\n\nstd::optional<std::string> pick_place_name(const Json::Value& root)\n{\n    static const std::array<const char*, 9> kAddressKeys = {\n        \"city\", \"town\", \"village\", \"hamlet\", \"municipality\", \"suburb\", \"county\", \"state\", \"country\"\n    };\n\n    if (root.isMember(\"address\") && root[\"address\"].isObject()) {\n        const auto& address = root[\"address\"];\n        for (const char* key : kAddressKeys) {\n            if (address.isMember(key) && address[key].isString()) {\n                const std::string value = trim_copy(address[key].asString());\n                if (!value.empty()) {\n                    return value;\n                }\n            }\n        }\n    }\n\n    if (root.isMember(\"name\") && root[\"name\"].isString()) {\n        const std::string value = trim_copy(root[\"name\"].asString());\n        if (!value.empty()) {\n            return value;\n        }\n    }\n\n    if (root.isMember(\"display_name\") && root[\"display_name\"].isString()) {\n        std::string display = root[\"display_name\"].asString();\n        const auto comma = display.find(',');\n        if (comma != std::string::npos) {\n            display = display.substr(0, comma);\n        }\n        display = trim_copy(display);\n        if (!display.empty()) {\n            return display;\n        }\n    }\n\n    return std::nullopt;\n}\n\n} // namespace\n\nImageRenameMetadataService::ImageRenameMetadataService(std::string config_dir)\n    : config_dir_(std::move(config_dir))\n{\n    open_cache_db();\n}\n\nImageRenameMetadataService::~ImageRenameMetadataService()\n{\n    if (cache_db_) {\n        sqlite3_close(cache_db_);\n        cache_db_ = nullptr;\n    }\n}\n\nbool ImageRenameMetadataService::open_cache_db()\n{\n    if (cache_db_) {\n        return true;\n    }\n\n    if (config_dir_.empty()) {\n        return false;\n    }\n\n    std::error_code ec;\n    const auto config_path = Utils::utf8_to_path(config_dir_);\n    std::filesystem::create_directories(config_path, ec);\n    if (ec) {\n        return false;\n    }\n\n    const auto db_path = config_path / \"image_place_cache.db\";\n    if (sqlite3_open(db_path.string().c_str(), &cache_db_) != SQLITE_OK) {\n        if (cache_db_) {\n            sqlite3_close(cache_db_);\n            cache_db_ = nullptr;\n        }\n        return false;\n    }\n\n    const char* create_sql = R\"(\n        CREATE TABLE IF NOT EXISTS reverse_geocode_cache (\n            latitude_key TEXT NOT NULL,\n            longitude_key TEXT NOT NULL,\n            place_slug TEXT,\n            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n            PRIMARY KEY(latitude_key, longitude_key)\n        );\n    )\";\n\n    char* error = nullptr;\n    if (sqlite3_exec(cache_db_, create_sql, nullptr, nullptr, &error) != SQLITE_OK) {\n        if (error) {\n            sqlite3_free(error);\n        }\n        sqlite3_close(cache_db_);\n        cache_db_ = nullptr;\n        return false;\n    }\n\n    return true;\n}\n\nImageRenameMetadataService::ExifMetadata ImageRenameMetadataService::extract_exif_metadata(\n    const std::filesystem::path& image_path) const\n{\n    ExifMetadata metadata;\n\n    const std::string extension = file_extension_lower(image_path);\n    const bool is_heif = has_extension(extension, {\".heic\", \".heif\", \".hif\"});\n\n    std::optional<std::vector<uint8_t>> exif_tiff;\n    if (has_extension(extension, {\".jpg\", \".jpeg\"})) {\n        exif_tiff = read_jpeg_exif_payload(image_path);\n    } else if (has_extension(extension, {\".tif\", \".tiff\"})) {\n        exif_tiff = read_tiff_exif_payload(image_path);\n    } else if (has_extension(extension, {\".png\"})) {\n        exif_tiff = read_png_exif_payload(image_path);\n    }\n\n    if (!exif_tiff) {\n        exif_tiff = read_jpeg_exif_payload(image_path);\n    }\n    if (!exif_tiff) {\n        exif_tiff = read_tiff_exif_payload(image_path);\n    }\n    if (!exif_tiff) {\n        exif_tiff = read_png_exif_payload(image_path);\n    }\n\n    if (exif_tiff) {\n        const ParsedExifMetadata parsed = parse_tiff_metadata(*exif_tiff);\n        metadata.capture_date = parsed.capture_date;\n        metadata.latitude = parsed.latitude;\n        metadata.longitude = parsed.longitude;\n        return metadata;\n    }\n\n    if (is_heif) {\n        const ParsedExifMetadata parsed = extract_heif_metadata_with_exiftool(image_path);\n        metadata.capture_date = parsed.capture_date;\n        metadata.latitude = parsed.latitude;\n        metadata.longitude = parsed.longitude;\n    }\n\n    return metadata;\n}\n\nImageRenameMetadataService::CacheLookup ImageRenameMetadataService::lookup_cache(\n    const std::string& lat_key,\n    const std::string& lon_key) const\n{\n    CacheLookup lookup;\n    if (!cache_db_) {\n        return lookup;\n    }\n\n    sqlite3_stmt* stmt = nullptr;\n    const char* query_sql =\n        \"SELECT place_slug FROM reverse_geocode_cache WHERE latitude_key = ? AND longitude_key = ?;\";\n\n    if (sqlite3_prepare_v2(cache_db_, query_sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        return lookup;\n    }\n\n    sqlite3_bind_text(stmt, 1, lat_key.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, lon_key.c_str(), -1, SQLITE_TRANSIENT);\n\n    const int step = sqlite3_step(stmt);\n    if (step == SQLITE_ROW) {\n        lookup.found = true;\n        if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) {\n            const char* text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));\n            if (text && *text != '\\0') {\n                lookup.place = text;\n            }\n        }\n    }\n\n    sqlite3_finalize(stmt);\n    return lookup;\n}\n\nvoid ImageRenameMetadataService::upsert_cache(const std::string& lat_key,\n                                              const std::string& lon_key,\n                                              const std::optional<std::string>& place) const\n{\n    if (!cache_db_) {\n        return;\n    }\n\n    sqlite3_stmt* stmt = nullptr;\n    const char* upsert_sql = R\"(\n        INSERT INTO reverse_geocode_cache (latitude_key, longitude_key, place_slug, updated_at)\n        VALUES (?, ?, ?, CURRENT_TIMESTAMP)\n        ON CONFLICT(latitude_key, longitude_key)\n        DO UPDATE SET place_slug = excluded.place_slug,\n                      updated_at = CURRENT_TIMESTAMP;\n    )\";\n\n    if (sqlite3_prepare_v2(cache_db_, upsert_sql, -1, &stmt, nullptr) != SQLITE_OK) {\n        return;\n    }\n\n    sqlite3_bind_text(stmt, 1, lat_key.c_str(), -1, SQLITE_TRANSIENT);\n    sqlite3_bind_text(stmt, 2, lon_key.c_str(), -1, SQLITE_TRANSIENT);\n\n    if (place.has_value() && !place->empty()) {\n        sqlite3_bind_text(stmt, 3, place->c_str(), -1, SQLITE_TRANSIENT);\n    } else {\n        sqlite3_bind_null(stmt, 3);\n    }\n\n    sqlite3_step(stmt);\n    sqlite3_finalize(stmt);\n}\n\nImageRenameMetadataService::ReverseGeocodeResult ImageRenameMetadataService::reverse_geocode(\n    double latitude,\n    double longitude)\n{\n    ReverseGeocodeResult result;\n\n    CURL* curl = curl_easy_init();\n    if (!curl) {\n        return result;\n    }\n\n    std::ostringstream url_builder;\n    const char* endpoint = std::getenv(\"AI_FILE_SORTER_NOMINATIM_URL\");\n    url_builder << ((endpoint && endpoint[0] != '\\0') ? endpoint : kDefaultNominatimUrl)\n                << \"?format=jsonv2&addressdetails=1&zoom=10&lat=\"\n                << std::fixed << std::setprecision(7) << latitude\n                << \"&lon=\" << std::fixed << std::setprecision(7) << longitude;\n\n    std::string response;\n    curl_easy_setopt(curl, CURLOPT_URL, url_builder.str().c_str());\n    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 8L);\n    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_callback);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);\n    curl_easy_setopt(curl, CURLOPT_USERAGENT, \"AIFileSorter/1.7 (reverse-geocoder)\");\n    configure_tls(curl);\n\n    curl_slist* headers = nullptr;\n    headers = curl_slist_append(headers, \"Accept: application/json\");\n    if (headers) {\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n    }\n\n    const CURLcode code = curl_easy_perform(curl);\n    long http_status = 0;\n    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);\n\n    if (headers) {\n        curl_slist_free_all(headers);\n    }\n    curl_easy_cleanup(curl);\n\n    if (code != CURLE_OK || http_status != 200) {\n        return result;\n    }\n\n    Json::CharReaderBuilder reader_builder;\n    Json::Value root;\n    std::string errors;\n    std::istringstream stream(response);\n    if (!Json::parseFromStream(reader_builder, stream, &root, &errors)) {\n        return result;\n    }\n\n    const auto place_name = pick_place_name(root);\n    result.success = true;\n    if (place_name.has_value()) {\n        const std::string place_slug = slugify(*place_name);\n        if (!place_slug.empty()) {\n            result.place = place_slug;\n        }\n    }\n\n    return result;\n}\n\nstd::optional<std::string> ImageRenameMetadataService::resolve_place_prefix(double latitude,\n                                                                             double longitude)\n{\n    // Requirement: no network available -> no place prefix.\n    if (!network_available()) {\n        return std::nullopt;\n    }\n\n    const std::string lat_key = format_coord_key(latitude);\n    const std::string lon_key = format_coord_key(longitude);\n\n    const CacheLookup cached = lookup_cache(lat_key, lon_key);\n    if (cached.found) {\n        return cached.place;\n    }\n\n    const auto now = std::chrono::steady_clock::now();\n    if (last_geocode_request_.time_since_epoch().count() != 0) {\n        const auto elapsed = now - last_geocode_request_;\n        if (elapsed < kMinReverseInterval) {\n            std::this_thread::sleep_for(kMinReverseInterval - elapsed);\n        }\n    }\n\n    const auto geocode = reverse_geocode(latitude, longitude);\n    last_geocode_request_ = std::chrono::steady_clock::now();\n\n    if (geocode.success) {\n        upsert_cache(lat_key, lon_key, geocode.place);\n    }\n\n    return geocode.place;\n}\n\nstd::string ImageRenameMetadataService::enrich_suggested_name(\n    const std::filesystem::path& image_path,\n    const std::string& suggested_name)\n{\n    if (suggested_name.empty()) {\n        return suggested_name;\n    }\n\n    const ExifMetadata metadata = extract_exif_metadata(image_path);\n\n    std::optional<std::string> place_prefix;\n    if (metadata.latitude.has_value() && metadata.longitude.has_value()) {\n        place_prefix = resolve_place_prefix(*metadata.latitude, *metadata.longitude);\n    }\n\n    return apply_prefix_to_filename(suggested_name, metadata.capture_date, place_prefix);\n}\n\nstd::optional<std::string> ImageRenameMetadataService::extract_capture_date(\n    const std::filesystem::path& image_path) const\n{\n    return extract_exif_metadata(image_path).capture_date;\n}\n\nstd::string ImageRenameMetadataService::apply_prefix_to_filename(\n    const std::string& suggested_name,\n    const std::optional<std::string>& date_prefix,\n    const std::optional<std::string>& place_prefix)\n{\n    if (suggested_name.empty()) {\n        return suggested_name;\n    }\n\n    std::vector<std::string> prefix_parts;\n    if (date_prefix.has_value() && !date_prefix->empty()) {\n        prefix_parts.push_back(*date_prefix);\n    }\n    if (place_prefix.has_value() && !place_prefix->empty()) {\n        const std::string place_slug = slugify(*place_prefix);\n        if (!place_slug.empty()) {\n            prefix_parts.push_back(place_slug);\n        }\n    }\n\n    if (prefix_parts.empty()) {\n        return suggested_name;\n    }\n\n    const auto suggested_path = Utils::utf8_to_path(suggested_name);\n    std::string stem = Utils::path_to_utf8(suggested_path.stem());\n    std::string ext = Utils::path_to_utf8(suggested_path.extension());\n\n    if (stem.empty()) {\n        stem = suggested_name;\n        ext.clear();\n    }\n\n    std::ostringstream prefix_builder;\n    for (size_t index = 0; index < prefix_parts.size(); ++index) {\n        if (index > 0) {\n            prefix_builder << '_';\n        }\n        prefix_builder << prefix_parts[index];\n    }\n    const std::string prefix = prefix_builder.str();\n    if (prefix.empty()) {\n        return suggested_name;\n    }\n\n    if (stem == prefix || stem.rfind(prefix + \"_\", 0) == 0) {\n        return suggested_name;\n    }\n\n    const std::string prefixed_stem = prefix + \"_\" + stem;\n    return ext.empty() ? prefixed_stem : prefixed_stem + ext;\n}\n\nstd::string ImageRenameMetadataService::slugify(const std::string& value)\n{\n    std::string output;\n    output.reserve(value.size());\n\n    bool last_sep = true;\n    for (unsigned char ch : value) {\n        if (std::isalnum(ch)) {\n            output.push_back(static_cast<char>(std::tolower(ch)));\n            last_sep = false;\n            continue;\n        }\n\n        if (!last_sep && !output.empty()) {\n            output.push_back('_');\n            last_sep = true;\n        }\n    }\n\n    while (!output.empty() && output.back() == '_') {\n        output.pop_back();\n    }\n\n    return output;\n}\n\nstd::optional<std::string> ImageRenameMetadataService::normalize_exif_date(const std::string& value)\n{\n    return normalize_exif_date_value(value);\n}\n\nstd::string ImageRenameMetadataService::format_coord_key(double value)\n{\n    std::ostringstream out;\n    out << std::fixed << std::setprecision(4) << value;\n    return out.str();\n}\n\nbool ImageRenameMetadataService::network_available()\n{\n    if (!network_checked_) {\n        network_available_ = Utils::is_network_available();\n        network_checked_ = true;\n    }\n    return network_available_;\n}\n"
  },
  {
    "path": "app/lib/IniConfig.cpp",
    "content": "#include \"IniConfig.hpp\"\n#include \"Logger.hpp\"\n#include <cstdio>\n#include <iostream>\n#include <optional>\n#include <utility>\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/fmt.h>\n\nnamespace {\ntemplate <typename... Args>\nvoid ini_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) {\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nstd::string trim_copy(const std::string& input)\n{\n    const auto begin = input.find_first_not_of(\" \\t\");\n    if (begin == std::string::npos) {\n        return {};\n    }\n    const auto end = input.find_last_not_of(\" \\t\");\n    return input.substr(begin, end - begin + 1);\n}\n\nbool should_skip_line(const std::string& line)\n{\n    return line.empty() || line.front() == ';' || line.front() == '#';\n}\n\nbool parse_section_header(const std::string& line, std::string& section)\n{\n    if (line.size() >= 2 && line.front() == '[' && line.back() == ']') {\n        section = line.substr(1, line.size() - 2);\n        return true;\n    }\n    return false;\n}\n\nstd::optional<std::pair<std::string, std::string>> parse_key_value(const std::string& line)\n{\n    const auto delimiter = line.find('=');\n    if (delimiter == std::string::npos) {\n        return std::nullopt;\n    }\n    std::string key = trim_copy(line.substr(0, delimiter));\n    std::string value = trim_copy(line.substr(delimiter + 1));\n    if (key.empty()) {\n        return std::nullopt;\n    }\n    return std::make_pair(std::move(key), std::move(value));\n}\n}\n\n\nbool IniConfig::load(const std::string &filename) {\n    std::ifstream file(filename);\n    if (!file.is_open()) {\n        ini_log(spdlog::level::err, \"Failed to open config file: {}\", filename);\n        return false;\n    }\n\n    std::string raw_line;\n    std::string section;\n    while (std::getline(file, raw_line)) {\n        const std::string line = trim_copy(raw_line);\n        if (should_skip_line(line)) {\n            continue;\n        }\n        if (parse_section_header(line, section)) {\n            continue;\n        }\n        if (auto key_value = parse_key_value(line)) {\n            data[section][key_value->first] = key_value->second;\n        }\n    }\n    return true;\n}\n\n\nstd::string IniConfig::getValue(const std::string &section, const std::string &key, const std::string &default_value) const {\n    auto sec_it = data.find(section);\n    if (sec_it != data.end()) {\n        auto key_it = sec_it->second.find(key);\n        if (key_it != sec_it->second.end()) {\n            return key_it->second;\n        }\n    }\n    return default_value;\n}\n\n\nvoid IniConfig::setValue(const std::string &section, const std::string &key, const std::string &value) {\n    data[section][key] = value;\n}\n\n\nbool IniConfig::save(const std::string &filename) const\n{\n    std::ofstream file(filename);\n    \n    if (!file.is_open()) {\n        ini_log(spdlog::level::err, \"Failed to open config file: {}\", filename);\n        return false;\n    }\n\n    for (const auto &section : data) {\n        file << \"[\" << section.first << \"]\\n\";\n        for (const auto &pair : section.second) {\n            file << pair.first << \" = \" << pair.second << \"\\n\";\n        }\n        file << \"\\n\";\n    }\n\n    return true;\n}\n\nbool IniConfig::hasValue(const std::string& section, const std::string& key) const\n{\n    const auto sec_it = data.find(section);\n    if (sec_it == data.end()) {\n        return false;\n    }\n    const auto key_it = sec_it->second.find(key);\n    return key_it != sec_it->second.end();\n}\n"
  },
  {
    "path": "app/lib/LLMClient.cpp",
    "content": "#include \"LLMClient.hpp\"\n#include \"Types.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include <curl/curl.h>\n#include <cstdlib>\n#include <filesystem>\n#if __has_include(<jsoncpp/json/json.h>)\n    #include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n    #include <json/json.h>\n#else\n    #error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\n#include <iostream>\n#include <sstream>\n#include <algorithm>\n#include <string>\n#include <utility>\n\n// Helper function to write the response from curl into a string\nstatic size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *response)\n{\n    size_t totalSize = size * nmemb;\n    response->append(static_cast<const char*>(contents), totalSize);\n    return totalSize;\n}\n\nnamespace {\nstd::string trim_ws(const std::string& value);\n\nstd::string escape_json(const std::string& input) {\n    std::string out;\n    out.reserve(input.size() * 2);\n    for (char c : input) {\n        switch (c) {\n            case '\"': out += \"\\\\\\\"\"; break;\n            case '\\\\': out += \"\\\\\\\\\"; break;\n            case '\\n': out += \"\\\\n\"; break;\n            case '\\r': out += \"\\\\r\"; break;\n            case '\\t': out += \"\\\\t\"; break;\n            default:\n                out += c;\n        }\n    }\n    return out;\n}\n\nlong resolve_custom_timeout_seconds() {\n    const char* env = std::getenv(\"AI_FILE_SORTER_CUSTOM_LLM_TIMEOUT\");\n    if (env && *env) {\n        char* end = nullptr;\n        const long value = std::strtol(env, &end, 10);\n        if (end != env && value > 0) {\n            return value;\n        }\n    }\n    return 60L;\n}\n\nlong resolve_openai_timeout_seconds() {\n    return 5L;\n}\n\nlong resolve_timeout_seconds(const std::string& base_url) {\n    const std::string trimmed = trim_ws(base_url);\n    if (trimmed.empty()) {\n        return resolve_openai_timeout_seconds();\n    }\n    return resolve_custom_timeout_seconds();\n}\n\nstd::string trim_ws(const std::string& value) {\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    const auto start = value.find_first_not_of(whitespace);\n    const auto end = value.find_last_not_of(whitespace);\n    if (start == std::string::npos || end == std::string::npos) {\n        return std::string();\n    }\n    return value.substr(start, end - start + 1);\n}\n\nstd::string trim_trailing_slashes(std::string value) {\n    while (!value.empty() && value.back() == '/') {\n        value.pop_back();\n    }\n    return value;\n}\n\nbool ends_with(const std::string& value, const std::string& suffix) {\n    if (suffix.size() > value.size()) {\n        return false;\n    }\n    return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());\n}\n\nstruct CurlRequest {\n    CURL* handle{nullptr};\n    curl_slist* headers{nullptr};\n\n    CurlRequest() = default;\n    CurlRequest(const CurlRequest&) = delete;\n    CurlRequest& operator=(const CurlRequest&) = delete;\n\n    CurlRequest(CurlRequest&& other) noexcept\n        : handle(other.handle),\n          headers(other.headers)\n    {\n        other.handle = nullptr;\n        other.headers = nullptr;\n    }\n\n    CurlRequest& operator=(CurlRequest&& other) noexcept\n    {\n        if (this != &other) {\n            cleanup();\n            handle = other.handle;\n            headers = other.headers;\n            other.handle = nullptr;\n            other.headers = nullptr;\n        }\n        return *this;\n    }\n\n    ~CurlRequest() {\n        cleanup();\n    }\n\nprivate:\n    void cleanup()\n    {\n        if (handle) {\n            curl_easy_cleanup(handle);\n            handle = nullptr;\n        }\n        if (headers) {\n            curl_slist_free_all(headers);\n            headers = nullptr;\n        }\n    }\n};\n\nCurlRequest create_curl_request(const std::shared_ptr<spdlog::logger>& logger)\n{\n    CurlRequest request;\n    request.handle = curl_easy_init();\n    if (!request.handle) {\n        if (logger) {\n            logger->critical(\"Failed to initialize cURL handle for remote request\");\n        }\n        throw std::runtime_error(\"Initialization Error: Failed to initialize cURL.\");\n    }\n\n#ifdef _WIN32\n    try {\n        const auto cert_path = Utils::ensure_ca_bundle();\n        curl_easy_setopt(request.handle, CURLOPT_CAINFO, cert_path.string().c_str());\n    } catch (const std::exception& ex) {\n        throw std::runtime_error(std::string(\"Failed to stage CA bundle: \") + ex.what());\n    }\n#endif\n    return request;\n}\n\nvoid configure_request_payload(CurlRequest& request,\n                               const std::string& api_url,\n                               const std::string& payload,\n                               const std::string& api_key,\n                               long timeout_seconds,\n                               std::string& response_buffer)\n{\n    curl_easy_setopt(request.handle, CURLOPT_URL, api_url.c_str());\n    curl_easy_setopt(request.handle, CURLOPT_POST, 1L);\n    curl_easy_setopt(request.handle, CURLOPT_TIMEOUT, timeout_seconds);\n\n    request.headers = curl_slist_append(request.headers, \"Content-Type: application/json\");\n    if (!api_key.empty()) {\n        const std::string auth = \"Authorization: Bearer \" + api_key;\n        request.headers = curl_slist_append(request.headers, auth.c_str());\n    }\n    curl_easy_setopt(request.handle, CURLOPT_HTTPHEADER, request.headers);\n\n    curl_easy_setopt(request.handle, CURLOPT_POSTFIELDS, payload.c_str());\n    curl_easy_setopt(request.handle, CURLOPT_WRITEFUNCTION, WriteCallback);\n    curl_easy_setopt(request.handle, CURLOPT_WRITEDATA, &response_buffer);\n}\n\nlong perform_request(CurlRequest& request, const std::shared_ptr<spdlog::logger>& logger)\n{\n    const CURLcode res = curl_easy_perform(request.handle);\n    if (res != CURLE_OK) {\n        if (logger) {\n            logger->error(\"cURL request failed: {}\", curl_easy_strerror(res));\n        }\n        throw std::runtime_error(\"Network Error: \" + std::string(curl_easy_strerror(res)));\n    }\n\n    long http_code = 0;\n    curl_easy_getinfo(request.handle, CURLINFO_RESPONSE_CODE, &http_code);\n    return http_code;\n}\n\nstd::string parse_category_response(const std::string& payload,\n                                    long http_code,\n                                    const std::shared_ptr<spdlog::logger>& logger)\n{\n    Json::CharReaderBuilder reader_builder;\n    Json::Value root;\n    std::istringstream response_stream(payload);\n    std::string errors;\n\n    if (!Json::parseFromStream(reader_builder, response_stream, &root, &errors)) {\n        if (logger) {\n            logger->error(\"Failed to parse JSON response: {}\", errors);\n        }\n        throw std::runtime_error(\"Response Error: Failed to parse JSON response. \" + errors);\n    }\n\n    if (http_code == 401) {\n        throw std::runtime_error(\"Authentication Error: Invalid or missing API key.\");\n    }\n    if (http_code == 403) {\n        throw std::runtime_error(\"Authorization Error: API key does not have sufficient permissions.\");\n    }\n    if (http_code >= 500) {\n        throw std::runtime_error(\"Server Error: Remote LLM server returned an error. Status code: \" + std::to_string(http_code));\n    }\n    if (http_code >= 400) {\n        const std::string error_message = root[\"error\"][\"message\"].asString();\n        throw std::runtime_error(\"Client Error: \" + error_message);\n    }\n\n    return root[\"choices\"][0][\"message\"][\"content\"].asString();\n}\n}\n\n\nLLMClient::LLMClient(std::string api_key, std::string model, std::string base_url)\n    : api_key(std::move(api_key)), model(std::move(model)), base_url(std::move(base_url))\n{}\n\n\nLLMClient::~LLMClient() = default;\n\n\nvoid LLMClient::set_prompt_logging_enabled(bool enabled)\n{\n    prompt_logging_enabled = enabled;\n}\n\n\nstd::string LLMClient::send_api_request(std::string json_payload) {\n    std::string response_string;\n    const std::string api_url = resolve_api_url();\n    auto logger = Logger::get_logger(\"core_logger\");\n\n    if (logger) {\n        logger->debug(\"Dispatching remote LLM request to {}\", api_url);\n    }\n\n    CurlRequest request = create_curl_request(logger);\n    configure_request_payload(request, api_url, json_payload, api_key, resolve_timeout_seconds(base_url), response_string);\n\n    const long http_code = perform_request(request, logger);\n    return parse_category_response(response_string, http_code, logger);\n}\n\nstd::string LLMClient::effective_model() const\n{\n    return model.empty() ? \"gpt-4o-mini\" : model;\n}\n\nstd::string LLMClient::resolve_api_url() const\n{\n    static const std::string kDefaultApi = \"https://api.openai.com/v1/chat/completions\";\n    static const std::string kChatSuffix = \"/chat/completions\";\n\n    if (base_url.empty()) {\n        return kDefaultApi;\n    }\n\n    std::string trimmed = trim_ws(base_url);\n    if (trimmed.empty()) {\n        return kDefaultApi;\n    }\n\n    trimmed = trim_trailing_slashes(trimmed);\n    if (ends_with(trimmed, kChatSuffix)) {\n        return trimmed;\n    }\n\n    return trimmed + kChatSuffix;\n}\n\n\nstd::string LLMClient::categorize_file(const std::string& file_name,\n                                       const std::string& file_path,\n                                       FileType file_type,\n                                       const std::string& consistency_context)\n{\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        if (!file_path.empty()) {\n            logger->debug(\"Requesting remote categorization for '{}' ({}) at '{}'\",\n                          file_name, to_string(file_type), file_path);\n        } else {\n            logger->debug(\"Requesting remote categorization for '{}' ({})\", file_name, to_string(file_type));\n        }\n    }\n    std::string json_payload = make_payload(file_name, file_path, file_type, consistency_context);\n\n    if (prompt_logging_enabled && !last_prompt.empty()) {\n        std::cout << \"\\n[DEV][PROMPT] Categorization request\\n\" << last_prompt << \"\\n\";\n    }\n\n    std::string category = send_api_request(json_payload);\n\n    if (prompt_logging_enabled) {\n        std::cout << \"[DEV][RESPONSE] Categorization reply\\n\" << category << \"\\n\";\n    }\n\n    return category;\n}\n\n\nstd::string LLMClient::make_payload(const std::string& file_name,\n                                    const std::string& file_path,\n                                    const FileType file_type,\n                                    const std::string& consistency_context)\n{\n    std::string prompt;\n    std::string sanitized_path = file_path;\n\n    if (!sanitized_path.empty()) {\n        prompt = \"Categorize the item with full path: \" + sanitized_path + \"\\n\";\n        prompt += \"File name: \" + file_name;\n    } else {\n        prompt = \"Categorize file: \" + file_name;\n    }\n\n    if (file_type == FileType::File) {\n        // already set above\n    } else {\n        if (!sanitized_path.empty()) {\n            prompt = \"Categorize the directory with full path: \" + sanitized_path + \"\\nDirectory name: \" + file_name;\n        } else {\n            prompt = \"Categorize directory: \" + file_name;\n        }\n    }\n\n    if (!consistency_context.empty()) {\n        prompt += \"\\n\\n\" + consistency_context;\n    }\n\n    last_prompt = prompt;\n    const std::string escaped_prompt = escape_json(prompt);\n    const std::string system_prompt =\n        \"You are a file categorization assistant. If it's an installer, describe the type of software it installs. \"\n        \"Consider the filename, extension, and any directory context provided. Always reply with one line in the \"\n        \"format <Main category> : <Subcategory>. Main category must be broad (one or two words, plural). Subcategory \"\n        \"must be specific, relevant, and must not repeat the main category.\";\n    const std::string escaped_system = escape_json(system_prompt);\n\n    std::ostringstream payload;\n    payload << \"{\\n\"\n            << \"    \\\"model\\\": \\\"\" << escape_json(effective_model()) << \"\\\",\\n\"\n            << \"    \\\"messages\\\": [\\n\"\n            << \"        {\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"\" << escaped_system << \"\\\"},\\n\"\n            << \"        {\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"\" << escaped_prompt << \"\\\"}\\n\"\n            << \"    ]\\n\"\n            << \"}\";\n\n    return payload.str();\n}\n\nstd::string LLMClient::make_generic_payload(const std::string& system_prompt,\n                                            const std::string& user_prompt,\n                                            int max_tokens) const\n{\n    std::ostringstream payload;\n    payload << \"{\\\"model\\\": \\\"\" << escape_json(effective_model()) << \"\\\",\";\n    payload << \"\\\"messages\\\": [\";\n    payload << \"{\\\"role\\\": \\\"system\\\", \\\"content\\\": \\\"\"\n            << escape_json(system_prompt) << \"\\\"},\";\n    payload << \"{\\\"role\\\": \\\"user\\\", \\\"content\\\": \\\"\"\n            << escape_json(user_prompt) << \"\\\"}]\";\n    if (max_tokens > 0) {\n        payload << \",\\\"max_tokens\\\": \" << max_tokens;\n    }\n    payload << \"}\";\n    return payload.str();\n}\n\nstd::string LLMClient::complete_prompt(const std::string& prompt,\n                                       int max_tokens)\n{\n    static const std::string kSystem =\n        \"You are a precise assistant that returns well-formed JSON responses.\";\n    std::string json_payload = make_generic_payload(kSystem, prompt, max_tokens);\n    return send_api_request(json_payload);\n}\n"
  },
  {
    "path": "app/lib/LLMDownloader.cpp",
    "content": "#include \"LLMDownloader.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include \"TestHooks.hpp\"\n#include <algorithm>\n#include <cstdlib>\n#include <curl/curl.h>\n#include <filesystem>\n#include <fstream>\n#include <iostream>\n#include <system_error>\n#include <stdexcept>\n#ifdef _WIN32\n#include <windows.h>\n#endif\n\nnamespace {\n\nconstexpr const char kMetadataSuffix[] = \".aifs.meta\";\nconstexpr const char kPartialDownloadSuffix[] = \".part\";\n\nbool replace_download_file(const std::filesystem::path& source,\n                           const std::filesystem::path& target,\n                           std::string& error)\n{\n#ifdef _WIN32\n    if (MoveFileExW(source.c_str(),\n                    target.c_str(),\n                    MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {\n        return true;\n    }\n    error = std::system_category().message(static_cast<int>(GetLastError()));\n    return false;\n#else\n    std::error_code ec;\n    std::filesystem::rename(source, target, ec);\n    if (!ec) {\n        return true;\n    }\n    error = ec.message();\n    return false;\n#endif\n}\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nTestHooks::LLMDownloadProbe& download_probe_slot() {\n    static TestHooks::LLMDownloadProbe probe;\n    return probe;\n}\n#endif\n\n} // namespace\n\n\nLLMDownloader::LLMDownloader(const std::string& download_url)\n    : url(download_url),\n      destination_dir(Utils::get_default_llm_destination())\n{\n    set_download_destination();\n    last_progress_update = std::chrono::steady_clock::now();\n}\n\n\nvoid LLMDownloader::set_download_destination() {\n    std::filesystem::create_directories(destination_dir);\n    download_destination = Utils::make_default_path_to_file_from_download_url(url);\n    load_cached_metadata();\n    migrate_legacy_partial_download_if_needed();\n}\n\nstd::string LLMDownloader::metadata_path() const\n{\n    return download_destination + kMetadataSuffix;\n}\n\nstd::string LLMDownloader::partial_download_path() const\n{\n    return download_destination + kPartialDownloadSuffix;\n}\n\nvoid LLMDownloader::load_cached_metadata()\n{\n    if (real_content_length > 0) {\n        return;\n    }\n\n    std::ifstream in(metadata_path());\n    if (!in.is_open()) {\n        return;\n    }\n\n    std::string cached_url;\n    long long cached_length = 0;\n    std::string line;\n    constexpr const char kUrlPrefix[] = \"url=\";\n    constexpr const char kLengthPrefix[] = \"content_length=\";\n    while (std::getline(in, line)) {\n        if (line.rfind(kUrlPrefix, 0) == 0) {\n            cached_url = line.substr(sizeof(kUrlPrefix) - 1);\n            continue;\n        }\n        if (line.rfind(kLengthPrefix, 0) == 0) {\n            try {\n                cached_length = std::stoll(line.substr(sizeof(kLengthPrefix) - 1));\n            } catch (const std::exception&) {\n                cached_length = 0;\n            }\n        }\n    }\n\n    if (!cached_url.empty() && cached_url != url) {\n        return;\n    }\n    if (cached_length > 0) {\n        real_content_length = cached_length;\n    }\n}\n\nvoid LLMDownloader::persist_cached_metadata() const\n{\n    if (real_content_length <= 0) {\n        return;\n    }\n\n    std::ofstream out(metadata_path(), std::ios::trunc);\n    if (!out.is_open()) {\n        return;\n    }\n\n    out << \"url=\" << url << \"\\n\";\n    out << \"content_length=\" << real_content_length << \"\\n\";\n}\n\nvoid LLMDownloader::migrate_legacy_partial_download_if_needed()\n{\n    if (real_content_length <= 0) {\n        return;\n    }\n\n    const auto partial_path = std::filesystem::path(partial_download_path());\n    std::error_code ec;\n    if (std::filesystem::exists(partial_path, ec) || ec) {\n        return;\n    }\n\n    const auto final_path = std::filesystem::path(download_destination);\n    const auto size = std::filesystem::file_size(final_path, ec);\n    if (ec || size == 0 || static_cast<long long>(size) >= real_content_length) {\n        return;\n    }\n\n    std::filesystem::rename(final_path, partial_path, ec);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        if (ec) {\n            logger->warn(\"Failed to migrate legacy partial download '{}' to '{}': {}\",\n                         final_path.string(),\n                         partial_path.string(),\n                         ec.message());\n        } else {\n            logger->info(\"Migrated legacy partial download '{}' to '{}'\",\n                         final_path.string(),\n                         partial_path.string());\n        }\n    }\n}\n\n\nvoid LLMDownloader::init_if_needed() {\n    if (initialized) return;\n\n    if (!Utils::is_network_available()) {\n        // std::cerr << \"Still no internet...\\n\";\n        return;\n    }\n\n    parse_headers();\n    set_download_destination();\n    initialized = true;\n}\n\n\nbool LLMDownloader::is_inited()\n{\n    return initialized;\n}\n\n\nsize_t LLMDownloader::write_data(void* ptr, size_t size, size_t nmemb, FILE* stream) {\n    return fwrite(ptr, size, nmemb, stream);\n}\n\n\nsize_t LLMDownloader::discard_callback(char* ptr, size_t size, size_t nmemb, void* userdata)\n{\n    return size * nmemb;\n}\n\n\nvoid LLMDownloader::parse_headers()\n{\n    CURL* curl = curl_easy_init();\n\n    if (!curl) {\n        throw std::runtime_error(\"Failed to initialize CURL\");\n    }\n\n    std::lock_guard<std::mutex> lock(mutex);\n    curl_headers.clear();\n    resumable = false;\n    real_content_length = 0;\n\n    setup_header_curl_options(curl);\n        \n    CURLcode res = curl_easy_perform(curl);\n\n    curl_off_t cl;\n    if (curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl) == CURLE_OK && cl > 0) {\n        real_content_length = cl;\n    }\n\n    curl_easy_cleanup(curl);\n\n    if (res != CURLE_OK) {\n        throw std::runtime_error(\"CURL HEAD request failed: \" + std::string(curl_easy_strerror(res)));\n    }\n\n    persist_cached_metadata();\n}\n\n\nint LLMDownloader::progress_func(void* clientp, curl_off_t dltotal, curl_off_t dlnow,\n    curl_off_t, curl_off_t)\n{\n    auto* self = static_cast<LLMDownloader*>(clientp);\n\n    if (self->cancel_requested.load(std::memory_order_relaxed)) {\n        return 1;\n    }\n\n    if (dltotal > 0 && self->on_status_text) {\n        std::string msg = \"Downloaded \" + Utils::format_size(self->resume_offset + dlnow) +\n            \" / \" + Utils::format_size(self->real_content_length);\n        self->on_status_text(msg);\n    }\n\n    curl_off_t total_size = self->real_content_length;\n\n    if (total_size == 0) {\n        return 0;\n    }\n\n    double raw_progress = static_cast<double>(self->resume_offset + dlnow) / static_cast<double>(total_size);\n    double clamped_progress = std::min(raw_progress, 1.0);\n\n    auto now = std::chrono::steady_clock::now();\n    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - self->last_progress_update);\n\n    if (elapsed.count() > 100) {\n        self->last_progress_update = now;\n\n        if (self->progress_callback) {\n            self->progress_callback(clamped_progress);\n        }\n    }\n\n    return 0;\n}\n\n\nsize_t LLMDownloader::header_callback(char* buffer, size_t size, size_t nitems, void* userdata) {\n    size_t total_size = size * nitems;\n    auto* self = static_cast<LLMDownloader*>(userdata);\n    std::string header(buffer, total_size);\n\n    // Normalize and parse header\n    auto colon_pos = header.find(':');\n    if (colon_pos != std::string::npos) {\n        std::string key = header.substr(0, colon_pos);\n        std::string value = header.substr(colon_pos + 1);\n\n        // Trim spaces\n        key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end());\n        value.erase(0, value.find_first_not_of(\" \\t\\r\\n\"));\n        value.erase(value.find_last_not_of(\" \\t\\r\\n\") + 1);\n\n        // Lowercase key\n        std::transform(key.begin(), key.end(), key.begin(), ::tolower);\n\n        // Store all headers\n        self->curl_headers[key] = value;\n    }\n\n    return total_size;\n}\n\n\nvoid LLMDownloader::start_download(std::function<void(double)> progress_cb,\n                                   std::function<void()> on_complete_cb,\n                                   std::function<void(const std::string&)> on_status_text,\n                                   std::function<void(const std::string&)> on_error_cb)\n{\n    if (download_thread.joinable()) {\n        download_thread.join();\n    }\n\n    cancel_requested.store(false, std::memory_order_relaxed);\n    this->progress_callback = std::move(progress_cb);\n    this->on_download_complete = std::move(on_complete_cb);\n    this->on_status_text = std::move(on_status_text);\n    this->on_download_error = std::move(on_error_cb);\n\n    download_thread = std::thread([this]() {\n        try {\n            perform_download();\n        } catch (const std::exception& ex) {\n            if (auto logger = Logger::get_logger(\"core_logger\")) {\n                logger->error(\"LLM download failed: {}\", ex.what());\n            }\n            if (this->on_status_text) {\n                this->on_status_text(std::string(\"Download error: \") + ex.what());\n            }\n            if (this->on_download_error) {\n                this->on_download_error(ex.what());\n            }\n        }\n    });\n}\n\n\nvoid LLMDownloader::perform_download()\n{\n    auto init_curl = []() -> CURL* {\n        CURL* handle = curl_easy_init();\n        if (!handle) {\n            throw std::runtime_error(\"Failed to initialize curl\");\n        }\n        return handle;\n    };\n\n    CURL* curl = init_curl();\n    auto cleanup_curl = [&]() {\n        if (curl) {\n            curl_easy_cleanup(curl);\n            curl = nullptr;\n        }\n    };\n\n    migrate_legacy_partial_download_if_needed();\n\n    long resume_from = determine_resume_offset();\n    resume_offset = resume_from;\n\n    if (real_content_length > 0 && resume_from >= real_content_length) {\n        notify_download_complete();\n        cleanup_curl();\n        return;\n    }\n\n    auto attempt_download = [&](long offset) -> CURLcode {\n#ifdef AI_FILE_SORTER_TEST_BUILD\n        if (auto& probe = download_probe_slot()) {\n            return probe(offset, partial_download_path());\n        }\n#endif\n        FILE* fp = open_output_file(offset);\n        if (!fp) {\n            cleanup_curl();\n            throw std::runtime_error(\"Failed to open file: \" + partial_download_path());\n        }\n\n        setup_download_curl_options(curl, fp, offset);\n        CURLcode result = curl_easy_perform(curl);\n        fclose(fp);\n        return result;\n    };\n\n    bool retried_full_download = false;\n\n    while (true) {\n        CURLcode res = attempt_download(resume_from);\n\n        if (res == CURLE_OK) {\n            mark_download_resumable();\n            notify_download_complete();\n            cleanup_curl();\n            return;\n        }\n\n        cancel_requested.store(false, std::memory_order_relaxed);\n\n        if (res == CURLE_ABORTED_BY_CALLBACK) {\n            if (on_download_error) {\n                on_download_error(\"Download cancelled\");\n            }\n            cleanup_curl();\n            return;\n        }\n\n        const bool range_error =\n            res == CURLE_HTTP_RANGE_ERROR ||\n            res == CURLE_BAD_DOWNLOAD_RESUME\n#ifdef CURLE_RANGE_ERROR\n            || res == CURLE_RANGE_ERROR\n#endif\n            ;\n\n        if (range_error && resume_from > 0 && !retried_full_download) {\n            if (auto logger = Logger::get_logger(\"core_logger\")) {\n                logger->warn(\"Range resume failed ({}). Retrying full download.\",\n                             curl_easy_strerror(res));\n            }\n            retried_full_download = true;\n            resume_from = 0;\n            resume_offset = 0;\n\n            std::error_code ec;\n            std::filesystem::remove(partial_download_path(), ec);\n\n            cleanup_curl();\n            curl = init_curl();\n            continue;\n        }\n\n        std::string error = std::string(\"Download failed: \") + curl_easy_strerror(res);\n        cleanup_curl();\n        throw std::runtime_error(error);\n    }\n}\n\n\nvoid LLMDownloader::mark_download_resumable()\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    resumable = true;\n}\n\n\nvoid LLMDownloader::notify_download_complete()\n{\n    const auto partial_path = std::filesystem::path(partial_download_path());\n    const auto final_path = std::filesystem::path(download_destination);\n\n    if (real_content_length <= 0) {\n        std::error_code ec;\n        const auto completed_path =\n            std::filesystem::exists(partial_path, ec) && !ec ? partial_path : final_path;\n        const auto size = std::filesystem::file_size(completed_path, ec);\n        if (!ec) {\n            real_content_length = static_cast<long long>(size);\n        }\n    }\n\n    std::error_code exists_ec;\n    if (std::filesystem::exists(partial_path, exists_ec) && !exists_ec) {\n        std::string error;\n        if (!replace_download_file(partial_path, final_path, error)) {\n            throw std::runtime_error(\"Failed to finalize download: \" + error);\n        }\n    }\n\n    persist_cached_metadata();\n\n    if (on_download_complete) {\n        on_download_complete();\n    }\n}\n\n\nvoid LLMDownloader::setup_common_curl_options(CURL* curl)\n{\n#ifdef _WIN32\n    try {\n        const auto cert_path = Utils::ensure_ca_bundle();\n        curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str());\n    } catch (const std::exception& ex) {\n        throw std::runtime_error(std::string(\"Failed to stage CA bundle: \") + ex.what());\n    }\n#endif\n\n    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);\n    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);\n}\n\n\nvoid LLMDownloader::setup_header_curl_options(CURL* curl)\n{    \n    setup_common_curl_options(curl);\n    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);\n    curl_easy_setopt(curl, CURLOPT_HEADER, 1L);\n    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &LLMDownloader::header_callback);\n    curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, discard_callback); // <-- avoids stdout\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, nullptr);\n}\n\n\nvoid LLMDownloader::setup_download_curl_options(CURL* curl, FILE* fp, long resume_offset)\n{\n    setup_common_curl_options(curl);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &LLMDownloader::write_data);\n    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &LLMDownloader::header_callback);\n    curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);\n    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);\n    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);\n    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &LLMDownloader::progress_func);\n    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);\n    if (resume_offset > 0) {\n        curl_easy_setopt(curl, CURLOPT_RESUME_FROM, resume_offset);\n    }\n}\n\n\nlong LLMDownloader::determine_resume_offset() const\n{\n    if (!is_download_resumable()) return 0;\n\n    FILE* fp = fopen(partial_download_path().c_str(), \"rb\");\n    if (!fp) return 0;\n\n    fseek(fp, 0, SEEK_END);\n    long offset = ftell(fp);\n    fclose(fp);\n    return offset;\n}\n\n\nFILE* LLMDownloader::open_output_file(long resume_offset) const\n{\n    return fopen(partial_download_path().c_str(), resume_offset > 0 ? \"ab\" : \"wb\");\n}\n\n\nbool LLMDownloader::has_existing_partial_download() const\n{\n    try {\n        const auto partial_path = partial_download_path();\n        if (std::filesystem::exists(partial_path)) {\n            return std::filesystem::file_size(partial_path) > 0;\n        }\n\n        if (!std::filesystem::exists(download_destination)) {\n            return false;\n        }\n        if (real_content_length <= 0) {\n            return false;\n        }\n        const auto final_size = std::filesystem::file_size(download_destination);\n        return final_size > 0 && static_cast<long long>(final_size) < real_content_length;\n    } catch (const std::filesystem::filesystem_error& e) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->warn(\"Unable to inspect download destination '{}': {}\", download_destination, e.what());\n        }\n        return false;\n    }\n}\n\n\nbool LLMDownloader::has_valid_content_length(const std::string& value) const\n{\n    try {\n        return std::stoll(value) > 0;\n    } catch (const std::exception& ex) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->warn(\"Invalid Content-Length header '{}': {}\", value, ex.what());\n        }\n        return false;\n    }\n}\n\n\nbool LLMDownloader::server_supports_resume_locked() const\n{\n    const auto ranges_it = curl_headers.find(\"accept-ranges\");\n    if (ranges_it == curl_headers.end() || ranges_it->second != \"bytes\") {\n        return false;\n    }\n\n    const auto length_it = curl_headers.find(\"content-length\");\n    if (length_it == curl_headers.end()) {\n        return false;\n    }\n\n    return has_valid_content_length(length_it->second);\n}\n\n\nbool LLMDownloader::is_download_resumable() const\n{\n    if (!has_existing_partial_download()) {\n        return false;\n    }\n\n    std::lock_guard<std::mutex> lock(mutex);\n    return server_supports_resume_locked();\n}\n\n\nbool LLMDownloader::is_download_complete() const\n{\n    try {\n        const auto partial_path = partial_download_path();\n        if (std::filesystem::exists(partial_path) && std::filesystem::file_size(partial_path) > 0) {\n            return false;\n        }\n        auto file_size = std::filesystem::file_size(download_destination);\n        return static_cast<std::int64_t>(file_size) >= real_content_length;\n    } catch (const std::filesystem::filesystem_error&) {\n        return false;\n    }\n}\n\n\n// bool LLMDownloader::is_download_complete() const\n// {\n//     FILE* fp = fopen(download_destination.c_str(), \"rb\");\n//     if (!fp) return false;\n\n//     fseek(fp, 0, SEEK_END);\n//     long size = ftell(fp);\n//     fclose(fp);\n\n//     return size >= real_content_length;\n// }\n\n\nlong long LLMDownloader::get_real_content_length() const\n{\n    return real_content_length;\n}\n\nLLMDownloader::DownloadStatus LLMDownloader::get_local_download_status() const\n{\n    std::error_code ec;\n    const auto partial_path = partial_download_path();\n    const auto partial_size = std::filesystem::file_size(partial_path, ec);\n    if (!ec && partial_size > 0) {\n        return DownloadStatus::InProgress;\n    }\n\n    ec.clear();\n    const auto size = std::filesystem::file_size(download_destination, ec);\n    if (ec || size == 0) {\n        return DownloadStatus::NotStarted;\n    }\n\n    const auto local_size = static_cast<long long>(size);\n    if (real_content_length > 0 && local_size < real_content_length) {\n        return DownloadStatus::InProgress;\n    }\n\n    return DownloadStatus::Complete;\n}\n\n\nstd::string LLMDownloader::get_download_destination() const\n{\n    return download_destination;\n}\n\nstd::string LLMDownloader::get_partial_download_destination() const\n{\n    return partial_download_path();\n}\n\n\nLLMDownloader::DownloadStatus LLMDownloader::get_download_status() const {\n    const auto local_status = get_local_download_status();\n    if (local_status != DownloadStatus::InProgress) {\n        return local_status;\n    }\n\n    if (!initialized) {\n        return DownloadStatus::InProgress;\n    }\n\n    if (is_download_complete()) {\n        return DownloadStatus::Complete;\n    }\n\n    if (is_download_resumable()) {\n        return DownloadStatus::InProgress;\n    }\n\n    return DownloadStatus::NotStarted;\n}\n\n\nvoid LLMDownloader::cancel_download()\n{\n    std::lock_guard<std::mutex> lock(mutex);\n    cancel_requested.store(true, std::memory_order_relaxed);\n}\n\n\nLLMDownloader::~LLMDownloader() {\n    if (download_thread.joinable()) {\n        download_thread.join();\n    }\n}\n\n\nvoid LLMDownloader::set_download_url(const std::string& new_url) {\n    if (new_url == url) return;\n\n    url = new_url;\n    initialized = false;\n    curl_headers.clear();\n    resumable = false;\n    real_content_length = 0;\n    resume_offset = 0;\n\n    try {\n        set_download_destination();\n    } catch (const std::exception& ex) {\n        // Log errors\n    }\n}\n\n\nstd::string LLMDownloader::get_download_url()\n{\n    return url;\n}\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nnamespace TestHooks {\n\nvoid set_llm_download_probe(LLMDownloadProbe probe) {\n    download_probe_slot() = std::move(probe);\n}\n\nvoid reset_llm_download_probe() {\n    download_probe_slot() = LLMDownloadProbe{};\n}\n\n} // namespace TestHooks\n\nvoid LLMDownloader::LLMDownloaderTestAccess::set_real_content_length(LLMDownloader& downloader,\n                                                                     long long length) {\n    downloader.real_content_length = length;\n}\n\nvoid LLMDownloader::LLMDownloaderTestAccess::set_download_destination(LLMDownloader& downloader,\n                                                                      const std::string& path) {\n    downloader.destination_dir = std::filesystem::path(path).parent_path().string();\n    downloader.download_destination = path;\n}\n\nvoid LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(LLMDownloader& downloader,\n                                                                long long content_length) {\n    std::lock_guard<std::mutex> lock(downloader.mutex);\n    downloader.curl_headers[\"accept-ranges\"] = \"bytes\";\n    downloader.curl_headers[\"content-length\"] = std::to_string(content_length);\n    downloader.real_content_length = content_length;\n}\n\n#endif\n"
  },
  {
    "path": "app/lib/LLMSelectionDialog.cpp",
    "content": "#include \"LLMSelectionDialog.hpp\"\n\n#include \"DialogUtils.hpp\"\n#include \"LlmCatalog.hpp\"\n#include \"ErrorMessages.hpp\"\n#include \"Settings.hpp\"\n#include \"Utils.hpp\"\n#include \"CustomLLMDialog.hpp\"\n#include \"CustomApiDialog.hpp\"\n#ifdef AI_FILE_SORTER_TEST_BUILD\n#include \"LLMSelectionDialogTestAccess.hpp\"\n#endif\n\n#include <QButtonGroup>\n#include <QCheckBox>\n#include <QDialogButtonBox>\n#include <QFormLayout>\n#include <QGroupBox>\n#include <QHBoxLayout>\n#include <QLabel>\n#include <QMetaObject>\n#include <QProgressBar>\n#include <QPushButton>\n#include <QRadioButton>\n#include <QToolButton>\n#include <QScreen>\n#include <QSizePolicy>\n#include <QComboBox>\n#include <QFileDialog>\n#include <QLineEdit>\n#include <QMessageBox>\n#include <QScrollArea>\n#include <QTimer>\n#include <QStyle>\n#include <QVBoxLayout>\n#include <QString>\n\n#include <cstdlib>\n#include <filesystem>\n\n\nnamespace {\n\nQString format_markup_label(const QString& title, const QString& value, const QString& color)\n{\n    return QStringLiteral(\"<b>%1:</b> <span style=\\\"color:%2\\\">%3</span>\")\n        .arg(title, color, value.toHtmlEscaped());\n}\n\nlong long local_file_size_or_zero(const std::string& path)\n{\n    std::error_code ec;\n    const auto size = std::filesystem::file_size(path, ec);\n    if (ec) {\n        return 0;\n    }\n    return static_cast<long long>(size);\n}\n\nvoid set_fixed_progress_width(QProgressBar* bar, int multiplier)\n{\n    if (!bar || multiplier <= 0) {\n        return;\n    }\n    const QSize hint = bar->sizeHint();\n    int base_width = hint.width();\n    if (base_width <= 0) {\n        base_width = 120;\n    }\n    bar->setFixedWidth(base_width * multiplier);\n\n    int base_height = hint.height();\n    if (base_height <= 0) {\n        base_height = std::max(12, bar->fontMetrics().height());\n    }\n    bar->setMinimumHeight(base_height);\n    bar->setMaximumHeight(base_height);\n}\n\nvoid apply_progress_style(QProgressBar* bar)\n{\n    if (!bar) {\n        return;\n    }\n#if defined(__APPLE__)\n    bar->setTextVisible(false);\n    bar->setStyleSheet(QStringLiteral(\n        \"QProgressBar {\"\n        \" border: 1px solid #d0d0d0;\"\n        \" border-radius: 4px;\"\n        \" background: #f4f4f4;\"\n        \" }\"\n        \"QProgressBar::chunk {\"\n        \" background-color: #0a84ff;\"\n        \" border-radius: 3px;\"\n        \" }\"));\n#endif\n}\n\n} // namespace\n\n\nLLMSelectionDialog::LLMSelectionDialog(Settings& settings, QWidget* parent)\n    : QDialog(parent)\n    , settings(settings)\n    , downloads_expanded_(settings.get_llm_downloads_expanded())\n{\n    setWindowTitle(tr(\"Choose LLM Mode\"));\n    setModal(true);\n    setup_ui();\n    connect_signals();\n\n    openai_api_key = settings.get_openai_api_key();\n    openai_model = settings.get_openai_model();\n    gemini_api_key = settings.get_gemini_api_key();\n    gemini_model = settings.get_gemini_model();\n    if (openai_api_key_edit) {\n        openai_api_key_edit->setText(QString::fromStdString(openai_api_key));\n    }\n    if (openai_model_edit) {\n        openai_model_edit->setText(QString::fromStdString(openai_model));\n    }\n    if (gemini_api_key_edit) {\n        gemini_api_key_edit->setText(QString::fromStdString(gemini_api_key));\n    }\n    if (gemini_model_edit) {\n        gemini_model_edit->setText(QString::fromStdString(gemini_model));\n    }\n\n    selected_choice = settings.get_llm_choice();\n    selected_custom_id = settings.get_active_custom_llm_id();\n    selected_custom_api_id = settings.get_active_custom_api_id();\n    switch (selected_choice) {\n    case LLMChoice::Remote_OpenAI:\n        openai_radio->setChecked(true);\n        break;\n    case LLMChoice::Remote_Gemini:\n        gemini_radio->setChecked(true);\n        break;\n    case LLMChoice::Remote_Custom:\n        custom_api_radio->setChecked(true);\n        break;\n    case LLMChoice::Local_3b:\n        local3_radio->setChecked(true);\n        break;\n    case LLMChoice::Local_3b_legacy:\n        if (local3_legacy_radio && local3_legacy_radio->isVisible()) {\n            local3_legacy_radio->setChecked(true);\n        } else {\n            local3_radio->setChecked(true);\n            selected_choice = LLMChoice::Local_3b;\n        }\n        break;\n    case LLMChoice::Local_7b:\n        local7_radio->setChecked(true);\n        break;\n    case LLMChoice::Custom:\n        custom_radio->setChecked(true);\n        break;\n    default:\n        local3_radio->setChecked(true);\n        selected_choice = LLMChoice::Local_3b;\n        break;\n    }\n    refresh_custom_lists();\n    refresh_custom_api_lists();\n    if (selected_choice == LLMChoice::Custom) {\n        select_custom_by_id(selected_custom_id);\n    }\n    if (selected_choice == LLMChoice::Remote_Custom) {\n        select_custom_api_by_id(selected_custom_api_id);\n    }\n\n    update_ui_for_choice();\n    adjust_dialog_size();\n    const int min_width = 620;\n    if (width() < min_width) {\n        resize(min_width, height());\n    }\n}\n\n\nLLMSelectionDialog::~LLMSelectionDialog()\n{\n    if (downloader && is_downloading.load()) {\n        downloader->cancel_download();\n    }\n    if (llava_model_download.downloader && llava_model_download.is_downloading.load()) {\n        llava_model_download.downloader->cancel_download();\n    }\n    if (llava_mmproj_download.downloader && llava_mmproj_download.is_downloading.load()) {\n        llava_mmproj_download.downloader->cancel_download();\n    }\n}\n\n\nvoid LLMSelectionDialog::setup_ui()\n{\n    auto* outer_layout = new QVBoxLayout(this);\n    scroll_area_ = new QScrollArea(this);\n    scroll_area_->setWidgetResizable(true);\n    scroll_area_->setFrameShape(QFrame::NoFrame);\n    auto* content = new QWidget(scroll_area_);\n    auto* layout = new QVBoxLayout(content);\n\n    auto* title = new QLabel(tr(\"Select LLM Mode\"), this);\n    title->setAlignment(Qt::AlignHCenter);\n    layout->addWidget(title);\n\n    layout->setSpacing(8);\n\n    auto* radio_container = new QWidget(this);\n    auto* radio_layout = new QVBoxLayout(radio_container);\n    radio_layout->setSpacing(10);\n\n    local7_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_7b), radio_container);\n    local7_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* local7_desc = new QLabel(tr(\"Larger local model. Slower on CPU, but performs much better with GPU acceleration.\\nSupports: Nvidia (CUDA), Apple (Metal), CPU.\"), radio_container);\n    local7_desc->setWordWrap(true);\n\n    local3_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_3b), radio_container);\n    local3_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* local3_row = new QWidget(radio_container);\n    auto* local3_row_layout = new QHBoxLayout(local3_row);\n    local3_row_layout->setContentsMargins(0, 0, 0, 0);\n    auto* local3_recommended = new QLabel(tr(\"Recommended\"), local3_row);\n    local3_recommended->setStyleSheet(QStringLiteral(\"color: #1f6feb; font-weight: 700;\"));\n    local3_row_layout->addWidget(local3_radio);\n    local3_row_layout->addWidget(local3_recommended);\n    local3_row_layout->addStretch(1);\n    auto* local3_desc = new QLabel(tr(\"Smaller local model that works quickly even on CPUs. Good for lightweight local use.\"), radio_container);\n    local3_desc->setWordWrap(true);\n\n    local3_legacy_radio = new QRadioButton(default_llm_label_for_choice(LLMChoice::Local_3b_legacy), radio_container);\n    local3_legacy_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    local3_legacy_desc = new QLabel(tr(\"Legacy model kept for existing downloads.\"), radio_container);\n    local3_legacy_desc->setWordWrap(true);\n    const bool has_legacy_3b = legacy_local_3b_available();\n    local3_legacy_radio->setVisible(has_legacy_3b);\n    local3_legacy_desc->setVisible(has_legacy_3b);\n\n    gemini_radio = new QRadioButton(tr(\"Gemini (Google AI Studio API key)\"), radio_container);\n    gemini_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* gemini_desc = new QLabel(tr(\"Use Google's Gemini models with your AI Studio API key (internet required).\"), radio_container);\n    gemini_desc->setWordWrap(true);\n    gemini_inputs = new QWidget(radio_container);\n    auto* gemini_form = new QFormLayout(gemini_inputs);\n    gemini_form->setContentsMargins(24, 0, 0, 0);\n    gemini_form->setHorizontalSpacing(10);\n    gemini_form->setVerticalSpacing(6);\n    gemini_api_key_edit = new QLineEdit(gemini_inputs);\n    gemini_api_key_edit->setEchoMode(QLineEdit::Password);\n    gemini_api_key_edit->setClearButtonEnabled(true);\n    gemini_api_key_edit->setPlaceholderText(tr(\"AIza...\"));\n    show_gemini_api_key_checkbox = new QCheckBox(tr(\"Show\"), gemini_inputs);\n    auto* gemini_key_row = new QWidget(gemini_inputs);\n    auto* gemini_key_layout = new QHBoxLayout(gemini_key_row);\n    gemini_key_layout->setContentsMargins(0, 0, 0, 0);\n    gemini_key_layout->addWidget(gemini_api_key_edit, 1);\n    gemini_key_layout->addWidget(show_gemini_api_key_checkbox);\n    auto* gemini_key_label = new QLabel(tr(\"Gemini API key\"), gemini_inputs);\n    gemini_key_label->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    gemini_form->addRow(gemini_key_label, gemini_key_row);\n\n    gemini_model_edit = new QLineEdit(gemini_inputs);\n    gemini_model_edit->setPlaceholderText(tr(\"e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro\"));\n    auto* gemini_model_label = new QLabel(tr(\"Model\"), gemini_inputs);\n    gemini_model_label->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    gemini_form->addRow(gemini_model_label, gemini_model_edit);\n\n    gemini_help_label = new QLabel(tr(\"Your key is stored locally in the config file for this device.\"), gemini_inputs);\n    gemini_help_label->setWordWrap(true);\n    gemini_form->addRow(gemini_help_label);\n    gemini_link_label = new QLabel(gemini_inputs);\n    gemini_link_label->setTextFormat(Qt::RichText);\n    gemini_link_label->setTextInteractionFlags(Qt::TextBrowserInteraction);\n    gemini_link_label->setOpenExternalLinks(true);\n    gemini_link_label->setText(tr(\"<a href=\\\"https://aistudio.google.com/app/apikey\\\">Get a Gemini API key</a>\"));\n    gemini_form->addRow(gemini_link_label);\n    gemini_inputs->setVisible(false);\n\n    openai_radio = new QRadioButton(tr(\"ChatGPT (OpenAI API key)\"), radio_container);\n    openai_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* openai_desc = new QLabel(tr(\"Use your own OpenAI API key to access ChatGPT models (internet required).\"), radio_container);\n    openai_desc->setWordWrap(true);\n    openai_inputs = new QWidget(radio_container);\n    auto* openai_form = new QFormLayout(openai_inputs);\n    openai_form->setContentsMargins(24, 0, 0, 0);\n    openai_form->setHorizontalSpacing(10);\n    openai_form->setVerticalSpacing(6);\n    openai_api_key_edit = new QLineEdit(openai_inputs);\n    openai_api_key_edit->setEchoMode(QLineEdit::Password);\n    openai_api_key_edit->setClearButtonEnabled(true);\n    openai_api_key_edit->setPlaceholderText(tr(\"sk-...\"));\n    show_openai_api_key_checkbox = new QCheckBox(tr(\"Show\"), openai_inputs);\n    auto* openai_key_row = new QWidget(openai_inputs);\n    auto* openai_key_layout = new QHBoxLayout(openai_key_row);\n    openai_key_layout->setContentsMargins(0, 0, 0, 0);\n    openai_key_layout->addWidget(openai_api_key_edit, 1);\n    openai_key_layout->addWidget(show_openai_api_key_checkbox);\n    auto* openai_key_label = new QLabel(tr(\"OpenAI API key\"), openai_inputs);\n    openai_key_label->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    openai_form->addRow(openai_key_label, openai_key_row);\n\n    openai_model_edit = new QLineEdit(openai_inputs);\n    openai_model_edit->setPlaceholderText(\n        tr(\"e.g. gpt-4o-mini, gpt-4.1, o3-mini\"));\n    auto* openai_model_label = new QLabel(tr(\"Model\"), openai_inputs);\n    openai_model_label->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    openai_form->addRow(openai_model_label, openai_model_edit);\n\n    openai_help_label = new QLabel(\n        tr(\"Your key is stored locally in the config file for this device.\"),\n        openai_inputs);\n    openai_help_label->setWordWrap(true);\n    openai_form->addRow(openai_help_label);\n    openai_link_label = new QLabel(openai_inputs);\n    openai_link_label->setTextFormat(Qt::RichText);\n    openai_link_label->setTextInteractionFlags(Qt::TextBrowserInteraction);\n    openai_link_label->setOpenExternalLinks(true);\n    openai_link_label->setText(\n        tr(\"<a href=\\\"https://platform.openai.com/api-keys\\\">Get an OpenAI API key</a>\"));\n    openai_form->addRow(openai_link_label);\n    openai_inputs->setVisible(false);\n\n    custom_api_radio = new QRadioButton(\n        tr(\"Custom OpenAI-compatible API (advanced)\"), radio_container);\n    custom_api_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* custom_api_desc = new QLabel(\n        tr(\"Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).\"),\n        radio_container);\n    custom_api_desc->setWordWrap(true);\n    auto* custom_api_row = new QWidget(radio_container);\n    auto* custom_api_layout = new QHBoxLayout(custom_api_row);\n    custom_api_layout->setContentsMargins(24, 0, 0, 0);\n    custom_api_combo = new QComboBox(custom_api_row);\n    custom_api_combo->setMinimumContentsLength(10);\n    custom_api_combo->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n    custom_api_combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    custom_api_combo->setFixedWidth(360);\n    add_custom_api_button = new QPushButton(tr(\"Add…\"), custom_api_row);\n    edit_custom_api_button = new QPushButton(tr(\"Edit…\"), custom_api_row);\n    delete_custom_api_button = new QPushButton(tr(\"Delete\"), custom_api_row);\n    add_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    edit_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    delete_custom_api_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    custom_api_layout->addWidget(custom_api_combo);\n    custom_api_layout->addWidget(add_custom_api_button);\n    custom_api_layout->addWidget(edit_custom_api_button);\n    custom_api_layout->addWidget(delete_custom_api_button);\n    custom_api_layout->addStretch(1);\n\n    custom_radio = new QRadioButton(\n        tr(\"Custom local LLM (gguf)\"), radio_container);\n    custom_radio->setStyleSheet(QStringLiteral(\"color: #1f6feb;\"));\n    auto* custom_row = new QWidget(radio_container);\n    auto* custom_layout = new QHBoxLayout(custom_row);\n    custom_layout->setContentsMargins(24, 0, 0, 0);\n    custom_combo = new QComboBox(custom_row);\n    custom_combo->setMinimumContentsLength(10);\n    custom_combo->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n    custom_combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    custom_combo->setFixedWidth(360);\n    add_custom_button = new QPushButton(tr(\"Add…\"), custom_row);\n    edit_custom_button = new QPushButton(tr(\"Edit…\"), custom_row);\n    delete_custom_button = new QPushButton(tr(\"Delete\"), custom_row);\n    add_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    edit_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    delete_custom_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    custom_layout->addWidget(custom_combo);\n    custom_layout->addWidget(add_custom_button);\n    custom_layout->addWidget(edit_custom_button);\n    custom_layout->addWidget(delete_custom_button);\n    custom_layout->addStretch(1);\n\n    radio_layout->addWidget(local3_row);\n    radio_layout->addWidget(local3_desc);\n    radio_layout->addWidget(local7_radio);\n    radio_layout->addWidget(local7_desc);\n    radio_layout->addWidget(local3_legacy_radio);\n    radio_layout->addWidget(local3_legacy_desc);\n    radio_layout->addWidget(gemini_radio);\n    radio_layout->addWidget(gemini_desc);\n    radio_layout->addWidget(gemini_inputs);\n    radio_layout->addWidget(openai_radio);\n    radio_layout->addWidget(openai_desc);\n    radio_layout->addWidget(openai_inputs);\n    radio_layout->addWidget(custom_api_radio);\n    radio_layout->addWidget(custom_api_desc);\n    radio_layout->addWidget(custom_api_row);\n    radio_layout->addWidget(custom_radio);\n    radio_layout->addWidget(custom_row);\n\n    auto* llm_group = new QButtonGroup(this);\n    llm_group->setExclusive(true);\n    llm_group->addButton(openai_radio);\n    llm_group->addButton(gemini_radio);\n    llm_group->addButton(custom_api_radio);\n    llm_group->addButton(local3_radio);\n    if (local3_legacy_radio) {\n        llm_group->addButton(local3_legacy_radio);\n    }\n    llm_group->addButton(local7_radio);\n    llm_group->addButton(custom_radio);\n\n    layout->addWidget(radio_container);\n\n    download_toggle_button = new QToolButton(this);\n    download_toggle_button->setText(tr(\"Downloads\"));\n    download_toggle_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\n    download_toggle_button->setArrowType(Qt::RightArrow);\n    download_toggle_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\n    download_toggle_button->setLayoutDirection(Qt::LeftToRight);\n    download_toggle_button->setCheckable(true);\n    download_toggle_button->setChecked(downloads_expanded_);\n    download_toggle_button->setArrowType(downloads_expanded_ ? Qt::DownArrow : Qt::RightArrow);\n    download_toggle_button->setStyleSheet(QStringLiteral(\"color: #1f6feb; font-weight: 600;\"));\n    auto* downloads_toggle_row = new QWidget(this);\n    auto* downloads_toggle_layout = new QHBoxLayout(downloads_toggle_row);\n    downloads_toggle_layout->setContentsMargins(0, 0, 0, 0);\n    downloads_toggle_layout->addWidget(download_toggle_button);\n    downloads_toggle_layout->addStretch(1);\n    layout->addWidget(downloads_toggle_row);\n\n    downloads_container = new QWidget(this);\n    auto* downloads_layout = new QVBoxLayout(downloads_container);\n    downloads_layout->setContentsMargins(0, 0, 0, 0);\n    downloads_layout->setSpacing(10);\n\n    download_section = new QWidget(downloads_container);\n    auto* download_layout = new QVBoxLayout(download_section);\n    download_layout->setSpacing(6);\n\n    remote_url_label = new QLabel(download_section);\n    remote_url_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    local_path_label = new QLabel(download_section);\n    local_path_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    file_size_label = new QLabel(download_section);\n    file_size_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    status_label = new QLabel(download_section);\n    status_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    progress_bar = new QProgressBar(download_section);\n    progress_bar->setRange(0, 100);\n    progress_bar->setValue(0);\n    progress_bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    set_fixed_progress_width(progress_bar, 3);\n    apply_progress_style(progress_bar);\n    progress_bar->setVisible(false);\n\n    download_button = new QPushButton(tr(\"Download\"), download_section);\n    download_button->setEnabled(false);\n    delete_download_button = new QPushButton(tr(\"Delete\"), download_section);\n    delete_download_button->setEnabled(false);\n\n    auto* download_actions = new QWidget(download_section);\n    auto* download_actions_layout = new QHBoxLayout(download_actions);\n    download_actions_layout->setContentsMargins(0, 0, 0, 0);\n    download_actions_layout->setSpacing(8);\n    download_actions_layout->addWidget(download_button);\n    download_actions_layout->addWidget(delete_download_button);\n    download_actions_layout->addStretch(1);\n\n    download_layout->addWidget(remote_url_label);\n    download_layout->addWidget(local_path_label);\n    download_layout->addWidget(file_size_label);\n    download_layout->addWidget(status_label);\n    download_layout->addWidget(progress_bar);\n    download_layout->addWidget(download_actions, 0, Qt::AlignLeft);\n\n    downloads_layout->addWidget(download_section);\n    download_section->setVisible(false);\n\n    visual_llm_download_section = new QGroupBox(tr(\"Image analysis models (LLaVA)\"), downloads_container);\n    auto* visual_layout = new QVBoxLayout(visual_llm_download_section);\n    auto* visual_hint = new QLabel(tr(\"Download the visual LLM files required for image analysis.\"), visual_llm_download_section);\n    visual_hint->setWordWrap(true);\n    visual_layout->addWidget(visual_hint);\n\n    setup_visual_llm_download_entry(llava_model_download,\n                                visual_llm_download_section,\n                                tr(\"LLaVA 1.6 Mistral 7B (text model)\"),\n                                \"LLAVA_MODEL_URL\");\n    visual_layout->addWidget(llava_model_download.container);\n\n    setup_visual_llm_download_entry(llava_mmproj_download,\n                                visual_llm_download_section,\n                                tr(\"LLaVA mmproj (vision encoder)\"),\n                                \"LLAVA_MMPROJ_URL\");\n    visual_layout->addWidget(llava_mmproj_download.container);\n\n    downloads_layout->addWidget(visual_llm_download_section);\n    layout->addWidget(downloads_container);\n    downloads_container->setVisible(false);\n\n    button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);\n    ok_button = button_box->button(QDialogButtonBox::Ok);\n\n    scroll_area_->setWidget(content);\n    outer_layout->addWidget(scroll_area_);\n    outer_layout->addWidget(button_box);\n}\n\n\nvoid LLMSelectionDialog::connect_signals()\n{\n    auto update_handler = [this]() { update_ui_for_choice(); };\n    connect(openai_radio, &QRadioButton::toggled, this, update_handler);\n    connect(gemini_radio, &QRadioButton::toggled, this, update_handler);\n    connect(custom_api_radio, &QRadioButton::toggled, this, update_handler);\n    connect(local3_radio, &QRadioButton::toggled, this, update_handler);\n    if (local3_legacy_radio) {\n        connect(local3_legacy_radio, &QRadioButton::toggled, this, update_handler);\n    }\n    connect(local7_radio, &QRadioButton::toggled, this, update_handler);\n    connect(custom_radio, &QRadioButton::toggled, this, update_handler);\n    connect(custom_combo, &QComboBox::currentTextChanged, this, update_handler);\n    connect(custom_api_combo, &QComboBox::currentTextChanged, this, update_handler);\n    connect(openai_api_key_edit, &QLineEdit::textChanged, this, update_handler);\n    connect(openai_model_edit, &QLineEdit::textChanged, this, update_handler);\n    connect(gemini_api_key_edit, &QLineEdit::textChanged, this, update_handler);\n    connect(gemini_model_edit, &QLineEdit::textChanged, this, update_handler);\n    connect(add_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_add_custom);\n    connect(edit_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_edit_custom);\n    connect(delete_custom_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_custom);\n    connect(add_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_add_custom_api);\n    connect(edit_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_edit_custom_api);\n    connect(delete_custom_api_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_custom_api);\n    if (delete_download_button) {\n        connect(delete_download_button, &QPushButton::clicked, this, &LLMSelectionDialog::handle_delete_download);\n    }\n    if (download_toggle_button) {\n        connect(download_toggle_button, &QToolButton::toggled, this, [this](bool checked) {\n            downloads_expanded_ = checked;\n            if (downloads_container) {\n                downloads_container->setVisible(checked);\n            }\n            download_toggle_button->setArrowType(checked ? Qt::DownArrow : Qt::RightArrow);\n            adjust_dialog_size();\n        });\n    }\n\n    if (show_openai_api_key_checkbox) {\n        connect(show_openai_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (openai_api_key_edit) {\n                openai_api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password);\n            }\n        });\n    }\n\n    if (show_gemini_api_key_checkbox) {\n        connect(show_gemini_api_key_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (gemini_api_key_edit) {\n                gemini_api_key_edit->setEchoMode(checked ? QLineEdit::Normal : QLineEdit::Password);\n            }\n        });\n    }\n\n    connect(download_button, &QPushButton::clicked, this, &LLMSelectionDialog::start_download);\n    if (llava_model_download.download_button) {\n        connect(llava_model_download.download_button, &QPushButton::clicked, this, [this]() {\n            start_visual_llm_download(llava_model_download);\n        });\n    }\n    if (llava_mmproj_download.download_button) {\n        connect(llava_mmproj_download.download_button, &QPushButton::clicked, this, [this]() {\n            start_visual_llm_download(llava_mmproj_download);\n        });\n    }\n    connect(button_box, &QDialogButtonBox::accepted, this, &LLMSelectionDialog::accept);\n    connect(button_box, &QDialogButtonBox::rejected, this, &LLMSelectionDialog::reject);\n}\n\nvoid LLMSelectionDialog::showEvent(QShowEvent* event)\n{\n    QDialog::showEvent(event);\n    QTimer::singleShot(0, this, [this]() {\n        adjust_dialog_size();\n    });\n}\n\n\nLLMChoice LLMSelectionDialog::get_selected_llm_choice() const\n{\n    return selected_choice;\n}\n\nstd::string LLMSelectionDialog::get_selected_custom_llm_id() const\n{\n    return selected_custom_id;\n}\n\nstd::string LLMSelectionDialog::get_selected_custom_api_id() const\n{\n    return selected_custom_api_id;\n}\n\nstd::string LLMSelectionDialog::get_openai_api_key() const\n{\n    return openai_api_key;\n}\n\nstd::string LLMSelectionDialog::get_openai_model() const\n{\n    return openai_model;\n}\n\nstd::string LLMSelectionDialog::get_gemini_api_key() const\n{\n    return gemini_api_key;\n}\n\nstd::string LLMSelectionDialog::get_gemini_model() const\n{\n    return gemini_model;\n}\n\nbool LLMSelectionDialog::get_llm_downloads_expanded() const\n{\n    return downloads_expanded_;\n}\n\n\nvoid LLMSelectionDialog::set_status_message(const QString& message)\n{\n    status_label->setText(message);\n}\n\nbool LLMSelectionDialog::legacy_local_3b_available() const\n{\n    const char* env_url = std::getenv(\"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\");\n    if (!env_url || *env_url == '\\0') {\n        return false;\n    }\n    std::string path;\n    try {\n        path = Utils::make_default_path_to_file_from_download_url(env_url);\n    } catch (...) {\n        return false;\n    }\n    std::error_code ec;\n    return !path.empty() && std::filesystem::exists(path, ec);\n}\n\nvoid LLMSelectionDialog::update_legacy_local_3b_visibility()\n{\n    if (!local3_legacy_radio || !local3_legacy_desc) {\n        return;\n    }\n    const bool available = legacy_local_3b_available();\n    local3_legacy_radio->setVisible(available);\n    local3_legacy_desc->setVisible(available);\n    if (!available && local3_legacy_radio->isChecked() && local3_radio) {\n        local3_radio->setChecked(true);\n    }\n}\n\nvoid LLMSelectionDialog::update_ui_for_choice()\n{\n    update_legacy_local_3b_visibility();\n    update_custom_buttons();\n    update_custom_api_buttons();\n\n    update_radio_selection();\n    update_custom_choice_ui();\n    update_custom_api_choice_ui();\n    update_visual_llm_downloads();\n\n    const bool is_local_builtin = (selected_choice == LLMChoice::Local_3b\n        || selected_choice == LLMChoice::Local_3b_legacy\n        || selected_choice == LLMChoice::Local_7b);\n\n    if (selected_choice == LLMChoice::Custom || is_remote_choice(selected_choice) || !is_local_builtin) {\n        return;\n    }\n\n    update_local_choice_ui();\n}\n\nvoid LLMSelectionDialog::update_radio_selection()\n{\n    if (openai_radio->isChecked()) {\n        selected_choice = LLMChoice::Remote_OpenAI;\n    } else if (gemini_radio->isChecked()) {\n        selected_choice = LLMChoice::Remote_Gemini;\n    } else if (custom_api_radio->isChecked()) {\n        selected_choice = LLMChoice::Remote_Custom;\n    } else if (local3_legacy_radio && local3_legacy_radio->isChecked()) {\n        selected_choice = LLMChoice::Local_3b_legacy;\n    } else if (local3_radio->isChecked()) {\n        selected_choice = LLMChoice::Local_3b;\n    } else if (local7_radio->isChecked()) {\n        selected_choice = LLMChoice::Local_7b;\n    } else if (custom_radio->isChecked()) {\n        selected_choice = LLMChoice::Custom;\n    }\n}\n\nvoid LLMSelectionDialog::update_custom_choice_ui()\n{\n    if (!ok_button && button_box) {\n        ok_button = button_box->button(QDialogButtonBox::Ok);\n    }\n    const bool is_local_builtin = (selected_choice == LLMChoice::Local_3b\n        || selected_choice == LLMChoice::Local_3b_legacy\n        || selected_choice == LLMChoice::Local_7b);\n    const bool is_remote_openai = selected_choice == LLMChoice::Remote_OpenAI;\n    const bool is_remote_gemini = selected_choice == LLMChoice::Remote_Gemini;\n    const bool is_remote_custom = selected_choice == LLMChoice::Remote_Custom;\n    const bool is_custom = selected_choice == LLMChoice::Custom;\n    if (download_toggle_button) {\n        download_toggle_button->setVisible(is_local_builtin);\n    }\n    if (downloads_container) {\n        const bool show_downloads = is_local_builtin && download_toggle_button\n            && download_toggle_button->isChecked();\n        downloads_container->setVisible(show_downloads);\n    }\n    download_section->setVisible(is_local_builtin);\n    adjust_dialog_size();\n    if (openai_inputs) {\n        openai_inputs->setVisible(is_remote_openai);\n        openai_inputs->setEnabled(is_remote_openai);\n    }\n    if (gemini_inputs) {\n        gemini_inputs->setVisible(is_remote_gemini);\n        gemini_inputs->setEnabled(is_remote_gemini);\n    }\n\n    custom_combo->setEnabled(is_custom);\n    edit_custom_button->setEnabled(is_custom && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0);\n    delete_custom_button->setEnabled(is_custom && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0);\n\n    if (is_custom) {\n        if (custom_combo->currentIndex() >= 0) {\n            selected_custom_id = custom_combo->currentData().toString().toStdString();\n        } else {\n            selected_custom_id.clear();\n        }\n        if (ok_button) ok_button->setEnabled(!selected_custom_id.empty());\n        progress_bar->setVisible(false);\n        download_button->setVisible(false);\n        set_status_message(selected_custom_id.empty() ? tr(\"Choose or add a custom model.\") : tr(\"Custom model selected.\"));\n        return;\n    }\n\n    if (is_remote_custom) {\n        return;\n    }\n\n    if (is_remote_openai) {\n        update_openai_fields_state();\n        return;\n    }\n    if (is_remote_gemini) {\n        update_gemini_fields_state();\n        return;\n    }\n\n    if (!is_local_builtin) {\n        if (ok_button) ok_button->setEnabled(true);\n        progress_bar->setVisible(false);\n        download_button->setVisible(false);\n        set_status_message(tr(\"Selection ready.\"));\n        return;\n    }\n}\n\nvoid LLMSelectionDialog::update_custom_api_choice_ui()\n{\n    if (!ok_button && button_box) {\n        ok_button = button_box->button(QDialogButtonBox::Ok);\n    }\n\n    const bool is_custom_api = selected_choice == LLMChoice::Remote_Custom;\n    if (custom_api_combo) {\n        custom_api_combo->setEnabled(is_custom_api);\n    }\n    if (edit_custom_api_button) {\n        edit_custom_api_button->setEnabled(is_custom_api && custom_api_combo\n            && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0);\n    }\n    if (delete_custom_api_button) {\n        delete_custom_api_button->setEnabled(is_custom_api && custom_api_combo\n            && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0);\n    }\n\n    if (!is_custom_api) {\n        return;\n    }\n\n    if (custom_api_combo && custom_api_combo->currentIndex() >= 0) {\n        selected_custom_api_id = custom_api_combo->currentData().toString().toStdString();\n    } else {\n        selected_custom_api_id.clear();\n    }\n\n    if (ok_button) {\n        ok_button->setEnabled(!selected_custom_api_id.empty());\n    }\n    if (progress_bar) {\n        progress_bar->setVisible(false);\n    }\n    if (download_button) {\n        download_button->setVisible(false);\n    }\n    set_status_message(selected_custom_api_id.empty()\n        ? tr(\"Choose or add a custom API endpoint.\")\n        : tr(\"Custom API selected.\"));\n}\n\nvoid LLMSelectionDialog::update_openai_fields_state()\n{\n    if (!ok_button && button_box) {\n        ok_button = button_box->button(QDialogButtonBox::Ok);\n    }\n\n    const bool is_openai = selected_choice == LLMChoice::Remote_OpenAI;\n    if (openai_inputs) {\n        openai_inputs->setVisible(is_openai);\n    }\n    bool valid = false;\n    if (is_openai) {\n        openai_api_key = openai_api_key_edit ? openai_api_key_edit->text().trimmed().toStdString() : std::string();\n        openai_model = openai_model_edit ? openai_model_edit->text().trimmed().toStdString() : std::string();\n        valid = openai_inputs_valid();\n        set_status_message(valid\n            ? tr(\"ChatGPT will use your API key and model.\")\n            : tr(\"Enter your OpenAI API key and model to continue.\"));\n    }\n\n    if (ok_button) {\n        ok_button->setEnabled(valid);\n    }\n    if (progress_bar) {\n        progress_bar->setVisible(false);\n    }\n    if (download_button) {\n        download_button->setVisible(false);\n        download_button->setEnabled(false);\n    }\n}\n\nvoid LLMSelectionDialog::update_gemini_fields_state()\n{\n    if (!ok_button && button_box) {\n        ok_button = button_box->button(QDialogButtonBox::Ok);\n    }\n\n    const bool is_gemini = selected_choice == LLMChoice::Remote_Gemini;\n    if (gemini_inputs) {\n        gemini_inputs->setVisible(is_gemini);\n    }\n\n    bool valid = false;\n    if (is_gemini) {\n        gemini_api_key = gemini_api_key_edit ? gemini_api_key_edit->text().trimmed().toStdString() : std::string();\n        gemini_model = gemini_model_edit ? gemini_model_edit->text().trimmed().toStdString() : std::string();\n        valid = gemini_inputs_valid();\n        set_status_message(valid\n            ? tr(\"Gemini will use your API key and model.\")\n            : tr(\"Enter your Gemini API key and model to continue.\"));\n    }\n\n    if (ok_button) {\n        ok_button->setEnabled(valid);\n    }\n    if (progress_bar) {\n        progress_bar->setVisible(false);\n    }\n    if (download_button) {\n        download_button->setVisible(false);\n        download_button->setEnabled(false);\n    }\n}\n\nbool LLMSelectionDialog::openai_inputs_valid() const\n{\n    const QString key_text = openai_api_key_edit ? openai_api_key_edit->text().trimmed() : QString();\n    const QString model_text = openai_model_edit ? openai_model_edit->text().trimmed() : QString();\n    return !key_text.isEmpty() && !model_text.isEmpty();\n}\n\nbool LLMSelectionDialog::gemini_inputs_valid() const\n{\n    const QString key_text = gemini_api_key_edit ? gemini_api_key_edit->text().trimmed() : QString();\n    const QString model_text = gemini_model_edit ? gemini_model_edit->text().trimmed() : QString();\n    return !key_text.isEmpty() && !model_text.isEmpty();\n}\n\nvoid LLMSelectionDialog::update_local_choice_ui()\n{\n    if (!ok_button && button_box) {\n        ok_button = button_box->button(QDialogButtonBox::Ok);\n    }\n    refresh_downloader();\n\n    if (!downloader) {\n        if (ok_button) ok_button->setEnabled(false);\n        download_button->setEnabled(false);\n        return;\n    }\n\n    update_download_info();\n\n    const auto status = downloader->get_download_status();\n    switch (status) {\n    case LLMDownloader::DownloadStatus::Complete:\n        progress_bar->setVisible(true);\n        progress_bar->setValue(100);\n        download_button->setEnabled(false);\n        download_button->setVisible(false);\n        if (delete_download_button) {\n            delete_download_button->setVisible(true);\n            delete_download_button->setEnabled(true);\n        }\n        if (ok_button) {\n            ok_button->setEnabled(true);\n        }\n        set_status_message(tr(\"Model ready.\"));\n        break;\n    case LLMDownloader::DownloadStatus::InProgress:\n        progress_bar->setVisible(true);\n        download_button->setVisible(true);\n        download_button->setEnabled(!is_downloading.load());\n        download_button->setText(tr(\"Resume download\"));\n        if (delete_download_button) {\n            delete_download_button->setVisible(true);\n            delete_download_button->setEnabled(true);\n        }\n        if (ok_button) {\n            ok_button->setEnabled(false);\n        }\n        set_status_message(tr(\"Partial download detected. You can resume.\"));\n        break;\n    case LLMDownloader::DownloadStatus::NotStarted:\n    default:\n        progress_bar->setVisible(false);\n        progress_bar->setValue(0);\n        download_button->setVisible(true);\n        download_button->setEnabled(!is_downloading.load());\n        download_button->setText(tr(\"Download\"));\n        if (delete_download_button) {\n            delete_download_button->setVisible(true);\n            delete_download_button->setEnabled(false);\n        }\n        if (ok_button) {\n            ok_button->setEnabled(false);\n        }\n        set_status_message(tr(\"Download required.\"));\n        break;\n    }\n}\n\n\nvoid LLMSelectionDialog::refresh_downloader()\n{\n    const std::string env_var = current_download_env_var();\n    if (env_var.empty()) {\n        downloader.reset();\n        set_status_message(tr(\"Unsupported LLM selection.\"));\n        return;\n    }\n\n    const char* env_url = std::getenv(env_var.c_str());\n    if (!env_url) {\n        downloader.reset();\n        set_status_message(tr(\"Missing download URL environment variable (%1).\" ).arg(QString::fromStdString(env_var)));\n        return;\n    }\n\n    if (!downloader) {\n        downloader = std::make_unique<LLMDownloader>(env_url);\n    } else {\n        downloader->set_download_url(env_url);\n    }\n\n    if (downloader->get_local_download_status() == LLMDownloader::DownloadStatus::InProgress) {\n        try {\n            downloader->init_if_needed();\n        } catch (const std::exception& ex) {\n            set_status_message(QString::fromStdString(ex.what()));\n            downloader.reset();\n        }\n    }\n}\n\nvoid LLMSelectionDialog::handle_delete_download()\n{\n    if (!downloader) {\n        return;\n    }\n\n    const std::string path = downloader->get_download_destination();\n    if (path.empty()) {\n        return;\n    }\n\n    const QString model_label = default_llm_label_for_choice(selected_choice);\n    const QString title = tr(\"Delete downloaded model?\");\n    const QString prompt = tr(\"Delete the downloaded model %1?\").arg(model_label);\n    const auto answer = QMessageBox::question(this, title, prompt, QMessageBox::Yes | QMessageBox::No);\n    if (answer != QMessageBox::Yes) {\n        return;\n    }\n\n    downloader->cancel_download();\n    is_downloading.store(false);\n\n    std::error_code ec;\n    bool removed_any = false;\n    if (std::filesystem::exists(path, ec)) {\n        removed_any = std::filesystem::remove(path, ec) || removed_any;\n    }\n    const std::string partial_path = downloader->get_partial_download_destination();\n    if (std::filesystem::exists(partial_path, ec)) {\n        removed_any = std::filesystem::remove(partial_path, ec) || removed_any;\n    }\n    const std::string meta_path = path + \".aifs.meta\";\n    if (std::filesystem::exists(meta_path, ec)) {\n        removed_any = std::filesystem::remove(meta_path, ec) || removed_any;\n    }\n\n    if (ec) {\n        set_status_message(tr(\"Failed to delete downloaded model.\"));\n    } else if (removed_any) {\n        set_status_message(tr(\"Deleted downloaded model.\"));\n    } else {\n        set_status_message(tr(\"No downloaded model found to delete.\"));\n    }\n\n    refresh_downloader();\n    update_download_info();\n    update_local_choice_ui();\n}\n\n\nvoid LLMSelectionDialog::update_download_info()\n{\n    if (!downloader) {\n        return;\n    }\n\n    remote_url_label->setText(format_markup_label(tr(\"Remote URL\"),\n                                                  QString::fromStdString(downloader->get_download_url()),\n                                                  QStringLiteral(\"#1565c0\")));\n\n    local_path_label->setText(format_markup_label(tr(\"Local path\"),\n                                                 QString::fromStdString(downloader->get_download_destination()),\n                                                 QStringLiteral(\"#2e7d32\")));\n\n    long long size = downloader->get_real_content_length();\n    if (size <= 0 && downloader->get_local_download_status() == LLMDownloader::DownloadStatus::Complete) {\n        size = local_file_size_or_zero(downloader->get_download_destination());\n    }\n    if (size > 0) {\n        file_size_label->setText(format_markup_label(tr(\"File size\"),\n                                                     QString::fromStdString(Utils::format_size(size)),\n                                                     QStringLiteral(\"#333\")));\n    } else {\n        file_size_label->setText(tr(\"File size: unknown\"));\n    }\n}\n\nvoid LLMSelectionDialog::refresh_custom_lists()\n{\n    if (!custom_combo) {\n        return;\n    }\n\n    custom_combo->blockSignals(true);\n    custom_combo->clear();\n    for (const auto& entry : settings.get_custom_llms()) {\n        custom_combo->addItem(QString::fromStdString(entry.name),\n                              QString::fromStdString(entry.id));\n    }\n    if (!selected_custom_id.empty()) {\n        select_custom_by_id(selected_custom_id);\n    } else if (custom_combo->count() > 0) {\n        custom_combo->setCurrentIndex(0);\n        selected_custom_id = custom_combo->currentData().toString().toStdString();\n    }\n    custom_combo->blockSignals(false);\n    update_custom_buttons();\n}\n\nvoid LLMSelectionDialog::refresh_custom_api_lists()\n{\n    if (!custom_api_combo) {\n        return;\n    }\n\n    custom_api_combo->blockSignals(true);\n    custom_api_combo->clear();\n    for (const auto& entry : settings.get_custom_api_endpoints()) {\n        custom_api_combo->addItem(QString::fromStdString(entry.name),\n                                  QString::fromStdString(entry.id));\n    }\n    if (!selected_custom_api_id.empty()) {\n        select_custom_api_by_id(selected_custom_api_id);\n    } else if (custom_api_combo->count() > 0) {\n        custom_api_combo->setCurrentIndex(0);\n        selected_custom_api_id = custom_api_combo->currentData().toString().toStdString();\n    }\n    custom_api_combo->blockSignals(false);\n    update_custom_api_buttons();\n}\n\nvoid LLMSelectionDialog::select_custom_by_id(const std::string& id)\n{\n    for (int i = 0; i < custom_combo->count(); ++i) {\n        if (custom_combo->itemData(i).toString().toStdString() == id) {\n            custom_combo->setCurrentIndex(i);\n            return;\n        }\n    }\n    if (custom_combo->count() > 0) {\n        custom_combo->setCurrentIndex(0);\n    }\n}\n\nvoid LLMSelectionDialog::select_custom_api_by_id(const std::string& id)\n{\n    if (!custom_api_combo) {\n        return;\n    }\n    for (int i = 0; i < custom_api_combo->count(); ++i) {\n        if (custom_api_combo->itemData(i).toString().toStdString() == id) {\n            custom_api_combo->setCurrentIndex(i);\n            return;\n        }\n    }\n    if (custom_api_combo->count() > 0) {\n        custom_api_combo->setCurrentIndex(0);\n    }\n}\n\nvoid LLMSelectionDialog::handle_add_custom()\n{\n    CustomLLMDialog editor(this);\n    if (editor.exec() != QDialog::Accepted) {\n        return;\n    }\n    CustomLLM entry = editor.result();\n    selected_custom_id = settings.upsert_custom_llm(entry);\n    refresh_custom_lists();\n    select_custom_by_id(selected_custom_id);\n    custom_radio->setChecked(true);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::handle_add_custom_api()\n{\n    CustomApiDialog editor(this);\n    if (editor.exec() != QDialog::Accepted) {\n        return;\n    }\n    CustomApiEndpoint entry = editor.result();\n    selected_custom_api_id = settings.upsert_custom_api_endpoint(entry);\n    refresh_custom_api_lists();\n    select_custom_api_by_id(selected_custom_api_id);\n    custom_api_radio->setChecked(true);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::handle_edit_custom()\n{\n    if (!custom_combo || custom_combo->currentIndex() < 0) {\n        return;\n    }\n    const std::string id = custom_combo->currentData().toString().toStdString();\n    CustomLLM entry = settings.find_custom_llm(id);\n    if (entry.id.empty()) {\n        return;\n    }\n\n    CustomLLMDialog editor(this, entry);\n    if (editor.exec() != QDialog::Accepted) {\n        return;\n    }\n    CustomLLM updated = editor.result();\n    updated.id = entry.id;\n    selected_custom_id = settings.upsert_custom_llm(updated);\n    refresh_custom_lists();\n    select_custom_by_id(selected_custom_id);\n    custom_radio->setChecked(true);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::handle_edit_custom_api()\n{\n    if (!custom_api_combo || custom_api_combo->currentIndex() < 0) {\n        return;\n    }\n    const std::string id = custom_api_combo->currentData().toString().toStdString();\n    CustomApiEndpoint entry = settings.find_custom_api_endpoint(id);\n    if (entry.id.empty()) {\n        return;\n    }\n\n    CustomApiDialog editor(this, entry);\n    if (editor.exec() != QDialog::Accepted) {\n        return;\n    }\n    CustomApiEndpoint updated = editor.result();\n    updated.id = entry.id;\n    selected_custom_api_id = settings.upsert_custom_api_endpoint(updated);\n    refresh_custom_api_lists();\n    select_custom_api_by_id(selected_custom_api_id);\n    custom_api_radio->setChecked(true);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::handle_delete_custom()\n{\n    if (!custom_combo || custom_combo->currentIndex() < 0) {\n        return;\n    }\n    const std::string id = custom_combo->currentData().toString().toStdString();\n    const QString name = custom_combo->currentText();\n    const auto response = QMessageBox::question(this,\n                                                tr(\"Delete custom model\"),\n                                                tr(\"Remove '%1' from your custom LLMs? This does not delete the file on disk.\")\n                                                    .arg(name));\n    if (response != QMessageBox::Yes) {\n        return;\n    }\n    settings.remove_custom_llm(id);\n    if (selected_custom_id == id) {\n        selected_custom_id.clear();\n    }\n    refresh_custom_lists();\n    custom_radio->setChecked(custom_combo->count() > 0);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::handle_delete_custom_api()\n{\n    if (!custom_api_combo || custom_api_combo->currentIndex() < 0) {\n        return;\n    }\n    const std::string id = custom_api_combo->currentData().toString().toStdString();\n    const QString name = custom_api_combo->currentText();\n    const auto response = QMessageBox::question(this,\n                                                tr(\"Delete custom API\"),\n                                                tr(\"Remove '%1' from your custom API list? This does not affect the server.\")\n                                                    .arg(name));\n    if (response != QMessageBox::Yes) {\n        return;\n    }\n    settings.remove_custom_api_endpoint(id);\n    if (selected_custom_api_id == id) {\n        selected_custom_api_id.clear();\n    }\n    refresh_custom_api_lists();\n    custom_api_radio->setChecked(custom_api_combo->count() > 0);\n    update_ui_for_choice();\n}\n\nvoid LLMSelectionDialog::update_custom_buttons()\n{\n    const bool has_selection = custom_combo && custom_combo->currentIndex() >= 0 && custom_combo->count() > 0;\n    if (edit_custom_button) {\n        edit_custom_button->setEnabled(has_selection && custom_radio->isChecked());\n    }\n    if (delete_custom_button) {\n        delete_custom_button->setEnabled(has_selection && custom_radio->isChecked());\n    }\n}\n\nvoid LLMSelectionDialog::update_custom_api_buttons()\n{\n    const bool has_selection = custom_api_combo && custom_api_combo->currentIndex() >= 0 && custom_api_combo->count() > 0;\n    if (edit_custom_api_button) {\n        edit_custom_api_button->setEnabled(has_selection && custom_api_radio->isChecked());\n    }\n    if (delete_custom_api_button) {\n        delete_custom_api_button->setEnabled(has_selection && custom_api_radio->isChecked());\n    }\n}\n\nvoid LLMSelectionDialog::setup_visual_llm_download_entry(VisualLlmDownloadEntry& entry,\n                                                     QWidget* parent,\n                                                     const QString& title,\n                                                     const std::string& env_var)\n{\n    entry.env_var = env_var;\n    entry.display_name = title.toStdString();\n    auto* group = new QGroupBox(title, parent);\n    entry.container = group;\n\n    auto* entry_layout = new QVBoxLayout(group);\n    entry_layout->setSpacing(6);\n\n    entry.remote_url_label = new QLabel(group);\n    entry.remote_url_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    entry.local_path_label = new QLabel(group);\n    entry.local_path_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    entry.file_size_label = new QLabel(group);\n    entry.file_size_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    entry.status_label = new QLabel(group);\n    entry.status_label->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    entry.progress_bar = new QProgressBar(group);\n    entry.progress_bar->setRange(0, 100);\n    entry.progress_bar->setValue(0);\n    entry.progress_bar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    set_fixed_progress_width(entry.progress_bar, 3);\n    apply_progress_style(entry.progress_bar);\n    entry.progress_bar->setVisible(false);\n\n    entry.download_button = new QPushButton(tr(\"Download\"), group);\n    entry.download_button->setEnabled(false);\n    entry.delete_button = new QPushButton(tr(\"Delete\"), group);\n    entry.delete_button->setEnabled(false);\n\n    auto* action_row = new QWidget(group);\n    auto* action_layout = new QHBoxLayout(action_row);\n    action_layout->setContentsMargins(0, 0, 0, 0);\n    action_layout->setSpacing(8);\n    action_layout->addWidget(entry.download_button);\n    action_layout->addWidget(entry.delete_button);\n    action_layout->addStretch(1);\n\n    entry_layout->addWidget(entry.remote_url_label);\n    entry_layout->addWidget(entry.local_path_label);\n    entry_layout->addWidget(entry.file_size_label);\n    entry_layout->addWidget(entry.status_label);\n    entry_layout->addWidget(entry.progress_bar);\n    entry_layout->addWidget(action_row, 0, Qt::AlignLeft);\n\n    if (entry.delete_button) {\n        auto* entry_ptr = &entry;\n        connect(entry.delete_button, &QPushButton::clicked, this, [this, entry_ptr]() {\n            handle_delete_visual_download(*entry_ptr);\n        });\n    }\n}\n\nvoid LLMSelectionDialog::set_visual_status_message(VisualLlmDownloadEntry& entry, const QString& message)\n{\n    if (entry.status_label) {\n        entry.status_label->setText(message);\n    }\n}\n\nvoid LLMSelectionDialog::refresh_visual_llm_download_entry(VisualLlmDownloadEntry& entry)\n{\n    if (entry.env_var.empty()) {\n        entry.downloader.reset();\n        set_visual_status_message(entry, tr(\"Missing download URL environment variable.\"));\n        if (entry.download_button) {\n            entry.download_button->setEnabled(false);\n        }\n        return;\n    }\n\n    const char* env_url = std::getenv(entry.env_var.c_str());\n    if (!env_url) {\n        entry.downloader.reset();\n        set_visual_status_message(entry,\n                                  tr(\"Missing download URL environment variable (%1).\")\n                                      .arg(QString::fromStdString(entry.env_var)));\n        if (entry.download_button) {\n            entry.download_button->setEnabled(false);\n        }\n        return;\n    }\n\n    if (!entry.downloader) {\n        entry.downloader = std::make_unique<LLMDownloader>(env_url);\n    } else {\n        entry.downloader->set_download_url(env_url);\n    }\n\n    if (entry.downloader->get_local_download_status() == LLMDownloader::DownloadStatus::InProgress) {\n        try {\n            entry.downloader->init_if_needed();\n        } catch (const std::exception& ex) {\n            set_visual_status_message(entry, QString::fromStdString(ex.what()));\n            entry.downloader.reset();\n        }\n    }\n}\n\nvoid LLMSelectionDialog::update_visual_llm_download_entry(VisualLlmDownloadEntry& entry)\n{\n    if (!entry.downloader) {\n        if (entry.progress_bar) {\n            entry.progress_bar->setVisible(false);\n        }\n        if (entry.download_button) {\n            entry.download_button->setVisible(true);\n            entry.download_button->setEnabled(false);\n        }\n        if (entry.delete_button) {\n            entry.delete_button->setVisible(true);\n            entry.delete_button->setEnabled(false);\n        }\n        return;\n    }\n\n    if (entry.remote_url_label) {\n        entry.remote_url_label->setText(format_markup_label(tr(\"Remote URL\"),\n                                                            QString::fromStdString(entry.downloader->get_download_url()),\n                                                            QStringLiteral(\"#1565c0\")));\n    }\n    if (entry.local_path_label) {\n        entry.local_path_label->setText(format_markup_label(tr(\"Local path\"),\n                                                            QString::fromStdString(entry.downloader->get_download_destination()),\n                                                            QStringLiteral(\"#2e7d32\")));\n    }\n    const auto local_status = entry.downloader->get_local_download_status();\n    if (entry.file_size_label) {\n        long long size = entry.downloader->get_real_content_length();\n        if (size <= 0 && local_status == LLMDownloader::DownloadStatus::Complete) {\n            size = local_file_size_or_zero(entry.downloader->get_download_destination());\n        }\n        if (size > 0) {\n            entry.file_size_label->setText(format_markup_label(tr(\"File size\"),\n                                                               QString::fromStdString(Utils::format_size(size)),\n                                                               QStringLiteral(\"#333\")));\n        } else {\n            entry.file_size_label->setText(tr(\"File size: unknown\"));\n        }\n    }\n\n    const auto status = entry.downloader->get_download_status();\n    switch (status) {\n    case LLMDownloader::DownloadStatus::Complete:\n        if (entry.progress_bar) {\n            entry.progress_bar->setVisible(true);\n            entry.progress_bar->setValue(100);\n        }\n        if (entry.download_button) {\n            entry.download_button->setEnabled(false);\n            entry.download_button->setVisible(false);\n        }\n        if (entry.delete_button) {\n            entry.delete_button->setVisible(true);\n            entry.delete_button->setEnabled(true);\n        }\n        set_visual_status_message(entry, tr(\"Model ready.\"));\n        break;\n    case LLMDownloader::DownloadStatus::InProgress:\n        if (entry.progress_bar) {\n            entry.progress_bar->setVisible(true);\n        }\n        if (entry.download_button) {\n            entry.download_button->setVisible(true);\n            entry.download_button->setEnabled(!entry.is_downloading.load());\n            entry.download_button->setText(tr(\"Resume download\"));\n        }\n        if (entry.delete_button) {\n            entry.delete_button->setVisible(true);\n            entry.delete_button->setEnabled(true);\n        }\n        set_visual_status_message(entry, tr(\"Partial download detected. You can resume.\"));\n        break;\n    case LLMDownloader::DownloadStatus::NotStarted:\n    default:\n        if (entry.progress_bar) {\n            entry.progress_bar->setVisible(false);\n            entry.progress_bar->setValue(0);\n        }\n        if (entry.download_button) {\n            entry.download_button->setVisible(true);\n            entry.download_button->setEnabled(!entry.is_downloading.load());\n            entry.download_button->setText(tr(\"Download\"));\n        }\n        if (entry.delete_button) {\n            entry.delete_button->setVisible(true);\n            entry.delete_button->setEnabled(false);\n        }\n        set_visual_status_message(entry, tr(\"Download required.\"));\n        break;\n    }\n}\n\nvoid LLMSelectionDialog::update_visual_llm_downloads()\n{\n    if (!visual_llm_download_section) {\n        return;\n    }\n\n    refresh_visual_llm_download_entry(llava_model_download);\n    update_visual_llm_download_entry(llava_model_download);\n\n    refresh_visual_llm_download_entry(llava_mmproj_download);\n    update_visual_llm_download_entry(llava_mmproj_download);\n}\n\nvoid LLMSelectionDialog::start_visual_llm_download(VisualLlmDownloadEntry& entry)\n{\n    if (!entry.downloader || entry.is_downloading.load()) {\n        return;\n    }\n\n    bool network_available = Utils::is_network_available();\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    if (use_network_available_override_) {\n        network_available = network_available_override_;\n    }\n#endif\n    if (!network_available) {\n        DialogUtils::show_error_dialog(this, ERR_NO_INTERNET_CONNECTION);\n        return;\n    }\n\n    try {\n        entry.downloader->init_if_needed();\n    } catch (const std::exception& ex) {\n        DialogUtils::show_error_dialog(this, ex.what());\n        return;\n    }\n\n    entry.is_downloading = true;\n    if (entry.download_button) {\n        entry.download_button->setEnabled(false);\n    }\n    if (entry.progress_bar) {\n        entry.progress_bar->setVisible(true);\n        entry.progress_bar->setValue(0);\n    }\n    set_visual_status_message(entry, tr(\"Downloading…\"));\n\n    auto* entry_ptr = &entry;\n    entry.downloader->start_download(\n        [this, entry_ptr](double fraction) {\n            QMetaObject::invokeMethod(this, [entry_ptr, fraction]() {\n                if (entry_ptr->progress_bar) {\n                    entry_ptr->progress_bar->setVisible(true);\n                    entry_ptr->progress_bar->setValue(static_cast<int>(fraction * 100));\n                }\n            }, Qt::QueuedConnection);\n        },\n        [this, entry_ptr]() {\n            QMetaObject::invokeMethod(this, [this, entry_ptr]() {\n                entry_ptr->is_downloading = false;\n                set_visual_status_message(*entry_ptr, tr(\"Download complete.\"));\n                update_visual_llm_download_entry(*entry_ptr);\n            }, Qt::QueuedConnection);\n        },\n        [this, entry_ptr](const std::string& text) {\n            QMetaObject::invokeMethod(this, [this, entry_ptr, text]() {\n                set_visual_status_message(*entry_ptr, QString::fromStdString(text));\n            }, Qt::QueuedConnection);\n        },\n        [this, entry_ptr](const std::string& error_text) {\n            QMetaObject::invokeMethod(this, [this, entry_ptr, error_text]() {\n                entry_ptr->is_downloading = false;\n                if (entry_ptr->progress_bar) {\n                    entry_ptr->progress_bar->setVisible(false);\n                }\n                if (entry_ptr->download_button) {\n                    entry_ptr->download_button->setEnabled(true);\n                }\n\n                const QString error = QString::fromStdString(error_text);\n                if (error.compare(QStringLiteral(\"Download cancelled\"), Qt::CaseInsensitive) == 0) {\n                    set_visual_status_message(*entry_ptr, tr(\"Download cancelled.\"));\n                } else {\n                    set_visual_status_message(*entry_ptr, tr(\"Download error: %1\").arg(error));\n                }\n            }, Qt::QueuedConnection);\n        });\n}\n\nvoid LLMSelectionDialog::handle_delete_visual_download(VisualLlmDownloadEntry& entry)\n{\n    if (!entry.downloader) {\n        return;\n    }\n\n    const std::string path = entry.downloader->get_download_destination();\n    if (path.empty()) {\n        return;\n    }\n\n    const QString display_name = QString::fromStdString(entry.display_name);\n    const QString title = tr(\"Delete downloaded model?\");\n    const QString prompt = tr(\"Delete the downloaded model %1?\").arg(display_name);\n    const auto answer = QMessageBox::question(this, title, prompt, QMessageBox::Yes | QMessageBox::No);\n    if (answer != QMessageBox::Yes) {\n        return;\n    }\n\n    entry.downloader->cancel_download();\n    entry.is_downloading.store(false);\n\n    std::error_code ec;\n    bool removed_any = false;\n    if (std::filesystem::exists(path, ec)) {\n        removed_any = std::filesystem::remove(path, ec) || removed_any;\n    }\n    const std::string partial_path = entry.downloader->get_partial_download_destination();\n    if (std::filesystem::exists(partial_path, ec)) {\n        removed_any = std::filesystem::remove(partial_path, ec) || removed_any;\n    }\n    const std::string meta_path = path + \".aifs.meta\";\n    if (std::filesystem::exists(meta_path, ec)) {\n        removed_any = std::filesystem::remove(meta_path, ec) || removed_any;\n    }\n\n    if (ec) {\n        set_visual_status_message(entry, tr(\"Failed to delete downloaded model.\"));\n    } else if (removed_any) {\n        set_visual_status_message(entry, tr(\"Deleted downloaded model.\"));\n    } else {\n        set_visual_status_message(entry, tr(\"No downloaded model found to delete.\"));\n    }\n\n    refresh_visual_llm_download_entry(entry);\n    update_visual_llm_download_entry(entry);\n}\n\nvoid LLMSelectionDialog::adjust_dialog_size()\n{\n    if (!scroll_area_) {\n        return;\n    }\n    auto* widget = scroll_area_->widget();\n    if (!widget) {\n        return;\n    }\n\n    widget->adjustSize();\n    const QSize content_hint = widget->sizeHint();\n    const int content_height = content_hint.height();\n    const int content_width = content_hint.width();\n\n    int scroll_height = content_height;\n    const int button_height = button_box ? button_box->sizeHint().height() : 0;\n    const int button_width = button_box ? button_box->sizeHint().width() : 0;\n\n    QMargins margins;\n    int spacing = 0;\n    if (layout()) {\n        margins = layout()->contentsMargins();\n        spacing = layout()->spacing();\n    }\n\n    const int frame = scroll_area_->frameWidth() * 2;\n    int desired_width = std::max(content_width + frame, button_width);\n    desired_width += margins.left() + margins.right();\n    int desired_height = scroll_height + button_height + margins.top() + margins.bottom();\n    if (button_height > 0) {\n        desired_height += spacing;\n    }\n\n    if (const QScreen* screen = this->screen()) {\n        const QSize available = screen->availableGeometry().size();\n        const int max_width = static_cast<int>(available.width() * 0.8);\n        const int max_height = static_cast<int>(available.height() * 0.8);\n        const int max_scroll_height = std::max(\n            0,\n            max_height - (button_height + margins.top() + margins.bottom() + (button_height > 0 ? spacing : 0)));\n        int target_height = desired_height;\n        const bool needs_scroll = target_height > max_height;\n        if (needs_scroll) {\n            scroll_area_->setMinimumHeight(0);\n            scroll_area_->setMaximumHeight(max_scroll_height);\n            target_height = max_height;\n        } else {\n            scroll_area_->setMinimumHeight(scroll_height);\n            scroll_area_->setMaximumHeight(scroll_height);\n        }\n        int scrollbar_padding = 0;\n        if (needs_scroll) {\n            scrollbar_padding = scroll_area_->style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, scroll_area_);\n        }\n        const int min_width = 620;\n        int target_width = std::min(desired_width + scrollbar_padding, max_width);\n        target_width = std::max(target_width, min_width);\n        resize(target_width, target_height);\n    } else {\n        scroll_area_->setMinimumHeight(scroll_height);\n        scroll_area_->setMaximumHeight(scroll_height);\n        adjustSize();\n    }\n\n    widget->updateGeometry();\n    if (layout()) {\n        layout()->invalidate();\n        layout()->activate();\n    }\n}\n\n\nvoid LLMSelectionDialog::start_download()\n{\n    if (!downloader || is_downloading.load()) {\n        return;\n    }\n\n    if (!Utils::is_network_available()) {\n        DialogUtils::show_error_dialog(this, ERR_NO_INTERNET_CONNECTION);\n        return;\n    }\n\n    try {\n        downloader->init_if_needed();\n    } catch (const std::exception& ex) {\n        DialogUtils::show_error_dialog(this, ex.what());\n        return;\n    }\n\n    is_downloading = true;\n    download_button->setEnabled(false);\n    progress_bar->setVisible(true);\n    set_status_message(tr(\"Downloading…\"));\n    progress_bar->setValue(0);\n    button_box->button(QDialogButtonBox::Ok)->setEnabled(false);\n\n    downloader->start_download(\n        [this](double fraction) {\n            QMetaObject::invokeMethod(this, [this, fraction]() {\n                progress_bar->setVisible(true);\n                progress_bar->setValue(static_cast<int>(fraction * 100));\n            }, Qt::QueuedConnection);\n        },\n        [this]() {\n            QMetaObject::invokeMethod(this, [this]() {\n                is_downloading = false;\n                set_status_message(tr(\"Download complete.\"));\n                update_ui_for_choice();\n            }, Qt::QueuedConnection);\n        },\n        [this](const std::string& text) {\n            QMetaObject::invokeMethod(this, [this, text]() {\n                set_status_message(QString::fromStdString(text));\n            }, Qt::QueuedConnection);\n        },\n        [this](const std::string& error_text) {\n            QMetaObject::invokeMethod(this, [this, error_text]() {\n                is_downloading = false;\n                progress_bar->setVisible(false);\n                download_button->setEnabled(true);\n\n                const QString error = QString::fromStdString(error_text);\n                if (error.compare(QStringLiteral(\"Download cancelled\"), Qt::CaseInsensitive) == 0) {\n                    set_status_message(tr(\"Download cancelled.\"));\n                } else {\n                    set_status_message(tr(\"Download error: %1\").arg(error));\n                }\n                button_box->button(QDialogButtonBox::Ok)->setEnabled(false);\n            }, Qt::QueuedConnection);\n        });\n}\n\n\nstd::string LLMSelectionDialog::current_download_env_var() const\n{\n    if (selected_choice == LLMChoice::Local_3b) {\n        return \"LOCAL_LLM_3B_DOWNLOAD_URL\";\n    }\n    if (selected_choice == LLMChoice::Local_3b_legacy) {\n        return \"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\";\n    }\n    if (selected_choice == LLMChoice::Local_7b) {\n        return \"LOCAL_LLM_7B_DOWNLOAD_URL\";\n    }\n    return std::string();\n}\n\n#if defined(AI_FILE_SORTER_TEST_BUILD)\n\nLLMSelectionDialogTestAccess::VisualEntryRefs LLMSelectionDialogTestAccess::llava_model_entry(LLMSelectionDialog& dialog)\n{\n    return {\n        dialog.llava_model_download.status_label,\n        dialog.llava_model_download.download_button,\n        dialog.llava_model_download.progress_bar,\n        dialog.llava_model_download.downloader.get()\n    };\n}\n\nLLMSelectionDialogTestAccess::VisualEntryRefs LLMSelectionDialogTestAccess::llava_mmproj_entry(LLMSelectionDialog& dialog)\n{\n    return {\n        dialog.llava_mmproj_download.status_label,\n        dialog.llava_mmproj_download.download_button,\n        dialog.llava_mmproj_download.progress_bar,\n        dialog.llava_mmproj_download.downloader.get()\n    };\n}\n\nvoid LLMSelectionDialogTestAccess::refresh_visual_downloads(LLMSelectionDialog& dialog)\n{\n    dialog.update_visual_llm_downloads();\n}\n\nvoid LLMSelectionDialogTestAccess::update_llava_model_entry(LLMSelectionDialog& dialog)\n{\n    dialog.update_visual_llm_download_entry(dialog.llava_model_download);\n}\n\nvoid LLMSelectionDialogTestAccess::start_llava_model_download(LLMSelectionDialog& dialog)\n{\n    dialog.start_visual_llm_download(dialog.llava_model_download);\n}\n\nvoid LLMSelectionDialogTestAccess::set_network_available_override(LLMSelectionDialog& dialog,\n                                                                   std::optional<bool> value)\n{\n    if (value.has_value()) {\n        dialog.use_network_available_override_ = true;\n        dialog.network_available_override_ = *value;\n    } else {\n        dialog.use_network_available_override_ = false;\n    }\n}\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n"
  },
  {
    "path": "app/lib/LlavaImageAnalyzer.cpp",
    "content": "#include \"LlavaImageAnalyzer.hpp\"\n\n#include \"Logger.hpp\"\n#include \"LlamaModelParams.hpp\"\n\n#include <QString>\n\n#include <algorithm>\n#include <cctype>\n#include <cstdlib>\n#include <cstdio>\n#include <cstring>\n#include <cerrno>\n#include <climits>\n#include <limits>\n#include <memory>\n#include <optional>\n#include <sstream>\n#include <string_view>\n#include <thread>\n#include <unordered_set>\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\n#include \"ggml-backend.h\"\n#include \"llama.h\"\n#include \"mtmd.h\"\n#include \"mtmd-helper.h\"\n#endif\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\nextern \"C\" {\n#if defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK)\ntypedef void (*mtmd_progress_callback_t)(const char* name,\n                                         int32_t current_batch,\n                                         int32_t total_batches,\n                                         void* user_data);\nMTMD_API void mtmd_helper_set_progress_callback(mtmd_progress_callback_t callback,\n                                                void* user_data);\n#endif\n#if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK)\nMTMD_API void mtmd_helper_log_set(ggml_log_callback log_callback, void* user_data);\n#endif\n}\n#endif\n\nnamespace {\nconstexpr size_t kMaxFilenameWords = 3;\nconstexpr size_t kMaxFilenameLength = 50;\n\n#if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK)\nbool is_mtmd_prompt_log_line(std::string_view line) {\n    return line.starts_with(\"add_text:\");\n}\n#endif\n\nstd::string to_lower_copy(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nstd::optional<bool> read_env_bool(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value || value[0] == '\\0') {\n        return std::nullopt;\n    }\n\n    std::string lowered = to_lower_copy(value);\n    if (lowered == \"1\" || lowered == \"true\" || lowered == \"yes\" || lowered == \"on\") {\n        return true;\n    }\n    if (lowered == \"0\" || lowered == \"false\" || lowered == \"no\" || lowered == \"off\") {\n        return false;\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> read_env_value(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value) {\n        return std::nullopt;\n    }\n    return std::string(value);\n}\n\nvoid set_env_value(const char* key, const std::optional<std::string>& value) {\n#if defined(_WIN32)\n    if (value.has_value()) {\n        _putenv_s(key, value->c_str());\n    } else {\n        _putenv_s(key, \"\");\n    }\n#else\n    if (value.has_value()) {\n        setenv(key, value->c_str(), 1);\n    } else {\n        unsetenv(key);\n    }\n#endif\n}\n\nclass ScopedEnvValue {\npublic:\n    ScopedEnvValue(const char* key, std::optional<std::string> value)\n        : key_(key), original_(read_env_value(key)) {\n        set_env_value(key_, value);\n    }\n\n    ~ScopedEnvValue() {\n        set_env_value(key_, original_);\n    }\n\n    ScopedEnvValue(const ScopedEnvValue&) = delete;\n    ScopedEnvValue& operator=(const ScopedEnvValue&) = delete;\n\nprivate:\n    const char* key_;\n    std::optional<std::string> original_;\n};\n\nstd::optional<int> read_env_int(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value || *value == '\\0') {\n        return std::nullopt;\n    }\n\n    char* end_ptr = nullptr;\n    errno = 0;\n    long parsed = std::strtol(value, &end_ptr, 10);\n    if (end_ptr == value || *end_ptr != '\\0' || errno == ERANGE) {\n        return std::nullopt;\n    }\n    if (parsed < INT_MIN || parsed > INT_MAX) {\n        return std::nullopt;\n    }\n\n    return static_cast<int>(parsed);\n}\n\nstd::optional<int> resolve_visual_gpu_layer_override() {\n    if (const auto visual_override = read_env_int(\"AI_FILE_SORTER_VISUAL_N_GPU_LAYERS\")) {\n        return visual_override;\n    }\n    return read_env_int(\"LLAVA_N_GPU_LAYERS\");\n}\n\nstd::string read_env_lower(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value || value[0] == '\\0') {\n        return {};\n    }\n    return to_lower_copy(value);\n}\n\nstd::string resolve_backend_name() {\n    std::string backend = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n    if (backend.empty()) {\n        backend = read_env_lower(\"LLAMA_ARG_DEVICE\");\n    }\n#ifdef GGML_USE_METAL\n    if (backend.empty()) {\n        backend = \"metal\";\n    }\n#endif\n    return backend;\n}\n\nstd::string trim_copy(const std::string& value) {\n    auto result = value;\n    const auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    result.erase(result.begin(), std::find_if(result.begin(), result.end(), not_space));\n    result.erase(std::find_if(result.rbegin(), result.rend(), not_space).base(), result.end());\n    return result;\n}\n\nQString sanitize_utf8_text(const std::string& value) {\n    QString cleaned = QString::fromUtf8(value.c_str());\n    cleaned.remove(QChar::ReplacementCharacter);\n    return cleaned.normalized(QString::NormalizationForm_C);\n}\n\nstd::vector<std::string> split_words(const QString& value) {\n    std::vector<std::string> words;\n    QString current;\n    for (const QChar ch : value) {\n        if (ch.isLetterOrNumber()) {\n            current.append(ch.toLower());\n        } else if (!current.isEmpty()) {\n            words.emplace_back(current.toUtf8().toStdString());\n            current.clear();\n        }\n    }\n    if (!current.isEmpty()) {\n        words.emplace_back(current.toUtf8().toStdString());\n    }\n    return words;\n}\n\nconst std::unordered_set<std::string> kStopwords = {\n    \"a\", \"an\", \"and\", \"are\", \"as\", \"at\", \"based\", \"be\", \"by\", \"category\", \"describes\",\n    \"description\", \"depicts\", \"details\", \"document\", \"file\", \"filename\", \"for\", \"from\",\n    \"gif\", \"has\", \"image\", \"in\", \"is\", \"it\", \"jpeg\", \"jpg\", \"of\", \"on\", \"only\",\n    \"photo\", \"picture\", \"png\", \"shows\", \"the\", \"this\", \"to\", \"txt\", \"unknown\", \"with\"\n};\n\nbool case_insensitive_contains(std::string_view text, std::string_view needle) {\n    if (needle.empty()) {\n        return true;\n    }\n    std::string text_lower(text);\n    std::string needle_lower(needle);\n    std::transform(text_lower.begin(), text_lower.end(), text_lower.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    std::transform(needle_lower.begin(), needle_lower.end(), needle_lower.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return text_lower.find(needle_lower) != std::string::npos;\n}\n\nint32_t resolve_default_visual_batch_size(bool gpu_enabled, std::string_view backend_name) {\n    if (!gpu_enabled) {\n        return 512;\n    }\n    if (case_insensitive_contains(backend_name, \"metal\")) {\n        return 1024;\n    }\n#if defined(_WIN32)\n    // Windows GPU drivers are more sensitive to an initial oversized context\n    // allocation, so keep image analysis at the proven 512-token batch.\n    return 512;\n#else\n    if (case_insensitive_contains(backend_name, \"vulkan\")) {\n        return 512;\n    }\n    return 768;\n#endif\n}\n\nllama_model_params build_visual_model_params_for_path(\n    const std::string& model_path,\n    const std::shared_ptr<spdlog::logger>& logger) {\n    const auto visual_override = resolve_visual_gpu_layer_override();\n    const auto global_override = read_env_value(\"AI_FILE_SORTER_N_GPU_LAYERS\");\n    const auto legacy_override = read_env_value(\"LLAMA_CPP_N_GPU_LAYERS\");\n\n    std::optional<ScopedEnvValue> ai_override_guard;\n    std::optional<ScopedEnvValue> legacy_override_guard;\n\n    if (visual_override.has_value()) {\n        const std::string override_value = std::to_string(*visual_override);\n        ai_override_guard.emplace(\"AI_FILE_SORTER_N_GPU_LAYERS\", override_value);\n        legacy_override_guard.emplace(\"LLAMA_CPP_N_GPU_LAYERS\", override_value);\n        if (logger) {\n            logger->info(\"Using visual-specific n_gpu_layers override={}\", *visual_override);\n        }\n    } else {\n        ai_override_guard.emplace(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n        legacy_override_guard.emplace(\"LLAMA_CPP_N_GPU_LAYERS\", std::nullopt);\n        if ((global_override.has_value() && !global_override->empty()) ||\n            (legacy_override.has_value() && !legacy_override->empty())) {\n            if (logger) {\n                logger->info(\n                    \"Ignoring global n_gpu_layers override for visual analysis; \"\n                    \"set AI_FILE_SORTER_VISUAL_N_GPU_LAYERS to override image analysis specifically.\");\n            }\n        }\n    }\n\n    return build_model_params_for_path(model_path, logger);\n}\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\nstruct BackendMemoryInfo {\n    size_t free_bytes = 0;\n    size_t total_bytes = 0;\n    std::string name;\n};\n\nstd::optional<BackendMemoryInfo> query_backend_memory(std::string_view backend_name) {\n    const size_t device_count = ggml_backend_dev_count();\n    BackendMemoryInfo best{};\n    bool found = false;\n\n    for (size_t i = 0; i < device_count; ++i) {\n        auto* device = ggml_backend_dev_get(i);\n        if (!device) {\n            continue;\n        }\n        if (ggml_backend_dev_type(device) != GGML_BACKEND_DEVICE_TYPE_GPU) {\n            continue;\n        }\n        auto* reg = ggml_backend_dev_backend_reg(device);\n        const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr;\n        if (!backend_name.empty() && !case_insensitive_contains(reg_name ? reg_name : \"\", backend_name)) {\n            continue;\n        }\n\n        size_t free_bytes = 0;\n        size_t total_bytes = 0;\n        ggml_backend_dev_memory(device, &free_bytes, &total_bytes);\n        if (free_bytes == 0 && total_bytes == 0) {\n            continue;\n        }\n\n        if (!found || total_bytes > best.total_bytes) {\n            best.free_bytes = free_bytes;\n            best.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes;\n            const char* dev_name = ggml_backend_dev_name(device);\n            best.name = dev_name ? dev_name : \"\";\n            found = true;\n        }\n    }\n\n    if (found) {\n        return best;\n    }\n    return std::nullopt;\n}\n\nbool should_enable_mmproj_gpu(const std::filesystem::path& mmproj_path,\n                              std::string_view backend_name,\n                              const std::shared_ptr<spdlog::logger>& logger) {\n    if (!case_insensitive_contains(backend_name, \"vulkan\")) {\n        return true;\n    }\n\n    const auto memory = query_backend_memory(\"vulkan\");\n    if (!memory.has_value()) {\n        if (logger) {\n            logger->warn(\"Vulkan memory metrics unavailable; using CPU for visual encoder to avoid OOM. \"\n                         \"Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU.\");\n        }\n        return false;\n    }\n\n    std::error_code ec;\n    const auto file_size = std::filesystem::file_size(mmproj_path, ec);\n    if (ec) {\n        if (logger) {\n            logger->warn(\"Failed to stat mmproj file '{}'; using CPU for visual encoder to avoid OOM. \"\n                         \"Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU.\",\n                         mmproj_path.string());\n        }\n        return false;\n    }\n\n    constexpr size_t kMinHeadroomBytes = 512ULL * 1024ULL * 1024ULL;\n    const size_t mmproj_bytes = static_cast<size_t>(\n        std::min<std::uintmax_t>(file_size, std::numeric_limits<size_t>::max()));\n    const size_t inflated_bytes = mmproj_bytes + (mmproj_bytes / 3);\n    const size_t required_bytes = inflated_bytes + kMinHeadroomBytes;\n\n    if (memory->free_bytes < required_bytes) {\n        if (logger) {\n            const double to_mib = 1024.0 * 1024.0;\n            logger->warn(\n                \"Vulkan free memory {:.1f} MiB < {:.1f} MiB needed for mmproj; using CPU for visual encoder. \"\n                \"Set AI_FILE_SORTER_VISUAL_USE_GPU=1 to force GPU.\",\n                memory->free_bytes / to_mib,\n                required_bytes / to_mib);\n        }\n        return false;\n    }\n\n    return true;\n}\n\nstruct BitmapDeleter {\n    void operator()(mtmd_bitmap* ptr) const {\n        if (ptr) {\n            mtmd_bitmap_free(ptr);\n        }\n    }\n};\n\nstruct ChunkDeleter {\n    void operator()(mtmd_input_chunks* ptr) const {\n        if (ptr) {\n            mtmd_input_chunks_free(ptr);\n        }\n    }\n};\n\nusing BitmapPtr = std::unique_ptr<mtmd_bitmap, BitmapDeleter>;\nusing ChunkPtr = std::unique_ptr<mtmd_input_chunks, ChunkDeleter>;\n\nllama_token greedy_sample(const float* logits, int vocab_size, float temperature) {\n    const float temp = std::max(temperature, 1e-3f);\n    int best_index = 0;\n    float best_value = -std::numeric_limits<float>::infinity();\n    for (int i = 0; i < vocab_size; ++i) {\n        const float value = logits[i] / temp;\n        if (value > best_value) {\n            best_value = value;\n            best_index = i;\n        }\n    }\n    return static_cast<llama_token>(best_index);\n}\n#endif\n\n} // namespace\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nnamespace LlavaImageAnalyzerTestAccess {\nint32_t default_visual_batch_size(bool gpu_enabled, std::string_view backend_name) {\n    return resolve_default_visual_batch_size(gpu_enabled, backend_name);\n}\n\nint32_t visual_model_n_gpu_layers_for_model(const std::string& model_path) {\n    return build_visual_model_params_for_path(model_path, nullptr).n_gpu_layers;\n}\n}\n#endif\n\nLlavaImageAnalyzer::LlavaImageAnalyzer(const std::filesystem::path& model_path,\n                                       const std::filesystem::path& mmproj_path)\n    : LlavaImageAnalyzer(model_path, mmproj_path, Settings{}) {}\n\nLlavaImageAnalyzer::LlavaImageAnalyzer(const std::filesystem::path& model_path,\n                                       const std::filesystem::path& mmproj_path,\n                                       Settings settings)\n#ifdef AI_FILE_SORTER_HAS_MTMD\n    : model_path_(model_path)\n    , mmproj_path_(mmproj_path)\n    , settings_(settings)\n#else\n    : settings_(settings)\n#endif\n{\n    if (settings_.n_threads <= 0) {\n        settings_.n_threads = static_cast<int32_t>(std::max(1u, std::thread::hardware_concurrency()));\n    }\n\n#ifndef AI_FILE_SORTER_HAS_MTMD\n    (void)model_path;\n    (void)mmproj_path;\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->error(\"Visual LLM support is not available in this build.\");\n    }\n    return;\n#else\n    visual_gpu_override_ = read_env_bool(\"AI_FILE_SORTER_VISUAL_USE_GPU\");\n    if (visual_gpu_override_.has_value()) {\n        settings_.use_gpu = *visual_gpu_override_;\n    }\n\n    auto logger = Logger::get_logger(\"core_logger\");\n    const std::string backend_name = resolve_backend_name();\n    const auto cleanup = [this]() {\n        if (vision_ctx_) {\n            mtmd_free(vision_ctx_);\n            vision_ctx_ = nullptr;\n        }\n        if (context_) {\n            llama_free(context_);\n            context_ = nullptr;\n        }\n        if (model_) {\n            llama_model_free(model_);\n            model_ = nullptr;\n        }\n    };\n\n    llama_model_params model_params = llama_model_default_params();\n    if (settings_.use_gpu) {\n        model_params = build_visual_model_params_for_path(model_path.string(), logger);\n    } else {\n        model_params.n_gpu_layers = 0;\n    }\n    text_gpu_enabled_ = settings_.use_gpu && model_params.n_gpu_layers != 0;\n    context_tokens_ = settings_.n_ctx;\n    batch_size_ = resolve_default_visual_batch_size(text_gpu_enabled_, backend_name);\n    model_ = llama_model_load_from_file(model_path.string().c_str(), model_params);\n    if (!model_) {\n        throw std::runtime_error(\"Failed to load LLaVA text model at \" + model_path.string());\n    }\n\n    vocab_ = llama_model_get_vocab(model_);\n\n    bool mmproj_use_gpu = text_gpu_enabled_;\n    if (mmproj_use_gpu && (!visual_gpu_override_.has_value() || !*visual_gpu_override_)) {\n        mmproj_use_gpu = should_enable_mmproj_gpu(mmproj_path, backend_name, logger);\n    }\n    mmproj_gpu_enabled_ = mmproj_use_gpu;\n\n    mtmd_context_params mm_params = mtmd_context_params_default();\n    mm_params.use_gpu = mmproj_gpu_enabled_;\n    mm_params.n_threads = settings_.n_threads;\n    vision_ctx_ = mtmd_init_from_file(mmproj_path.string().c_str(), model_, mm_params);\n    if (!vision_ctx_) {\n        cleanup();\n        throw std::runtime_error(\"Failed to load mmproj file at \" + mmproj_path.string());\n    }\n    if (!mtmd_support_vision(vision_ctx_)) {\n        cleanup();\n        throw std::runtime_error(\"The provided mmproj file does not expose vision capabilities\");\n    }\n    try {\n        initialize_context();\n    } catch (...) {\n        cleanup();\n        throw;\n    }\n#endif\n}\n\nLlavaImageAnalyzer::~LlavaImageAnalyzer() {\n#ifdef AI_FILE_SORTER_HAS_MTMD\n    if (vision_ctx_) {\n        mtmd_free(vision_ctx_);\n        vision_ctx_ = nullptr;\n    }\n    if (context_) {\n        llama_free(context_);\n        context_ = nullptr;\n    }\n    if (model_) {\n        llama_model_free(model_);\n        model_ = nullptr;\n    }\n#endif\n}\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\nvoid LlavaImageAnalyzer::initialize_context() {\n    auto logger = Logger::get_logger(\"core_logger\");\n    const int32_t initial_ctx = context_tokens_ > 0 ? context_tokens_ : settings_.n_ctx;\n    const int32_t initial_batch = batch_size_ > 0 ? batch_size_ : 512;\n\n    auto try_init_context = [&](int32_t n_ctx, int32_t n_batch) -> bool {\n        if (context_) {\n            llama_free(context_);\n            context_ = nullptr;\n        }\n\n        const int32_t bounded_ctx = std::max<int32_t>(1, n_ctx);\n        const int32_t bounded_batch = std::max<int32_t>(1, std::min(n_batch, bounded_ctx));\n\n        llama_context_params ctx_params = llama_context_default_params();\n        ctx_params.n_ctx = bounded_ctx;\n        ctx_params.n_batch = bounded_batch;\n        ctx_params.n_ubatch = bounded_batch;\n        ctx_params.n_threads = settings_.n_threads;\n        ctx_params.n_threads_batch = settings_.n_threads;\n        context_ = llama_init_from_model(model_, ctx_params);\n        if (context_) {\n            llama_set_n_threads(context_, settings_.n_threads, settings_.n_threads);\n        }\n        return context_ != nullptr;\n    };\n\n    auto apply_context_limits = [&](int32_t n_ctx, int32_t n_batch) {\n        context_tokens_ = std::max<int32_t>(1, n_ctx);\n        batch_size_ = std::max<int32_t>(1, std::min(n_batch, context_tokens_));\n    };\n\n    bool context_ready = try_init_context(initial_ctx, initial_batch);\n    if (context_ready) {\n        apply_context_limits(initial_ctx, initial_batch);\n    } else if (initial_batch > 512) {\n        if (logger) {\n            logger->warn(\"Failed to initialize llama_context (n_ctx={}, n_batch={}); retrying with smaller batch.\",\n                         initial_ctx, initial_batch);\n        }\n        const int32_t smaller_batch = 512;\n        context_ready = try_init_context(initial_ctx, smaller_batch);\n        if (context_ready) {\n            apply_context_limits(initial_ctx, smaller_batch);\n        }\n    }\n    if (!context_ready) {\n        if (logger) {\n            logger->warn(\"Failed to initialize llama_context (n_ctx={}, n_batch={}); retrying with smaller buffers.\",\n                         initial_ctx, std::min(initial_batch, 512));\n        }\n        const int32_t reduced_ctx = std::min(initial_ctx, 2048);\n        const int32_t reduced_batch = std::min(initial_batch, 512);\n        context_ready = try_init_context(reduced_ctx, reduced_batch);\n        if (context_ready) {\n            apply_context_limits(reduced_ctx, reduced_batch);\n        } else {\n            const int32_t smaller_batch = std::min(reduced_batch, 256);\n            context_ready = try_init_context(reduced_ctx, smaller_batch);\n            if (context_ready) {\n                apply_context_limits(reduced_ctx, smaller_batch);\n            } else {\n                const int32_t smaller_ctx = std::min(reduced_ctx, 1024);\n                context_ready = try_init_context(smaller_ctx, smaller_batch);\n                if (context_ready) {\n                    apply_context_limits(smaller_ctx, smaller_batch);\n                }\n            }\n        }\n    }\n\n    if (!context_ready) {\n        std::string hint;\n        if (text_gpu_enabled_) {\n            hint = \" (try AI_FILE_SORTER_VISUAL_USE_GPU=0 to force CPU)\";\n        }\n        throw std::runtime_error(\"Failed to create llama_context\" + hint);\n    }\n\n    reset_context_state();\n}\n\nvoid LlavaImageAnalyzer::reset_context_state() {\n    if (!context_) {\n        return;\n    }\n    llama_memory_clear(llama_get_memory(context_), true);\n    llama_synchronize(context_);\n    llama_perf_context_reset(context_);\n}\n#endif\n\nbool LlavaImageAnalyzer::is_supported_image(const std::filesystem::path& path) {\n    if (!path.has_extension()) {\n        return false;\n    }\n    std::string ext = to_lower_copy(path.extension().string());\n    static const std::unordered_set<std::string> kExtensions = {\n        \".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\", \".tga\", \".psd\", \".hdr\",\n        \".pic\", \".pnm\", \".ppm\", \".pgm\", \".pbm\"\n    };\n    return kExtensions.find(ext) != kExtensions.end();\n}\n\nLlavaImageAnalysisResult LlavaImageAnalyzer::analyze(const std::filesystem::path& image_path) {\n#ifndef AI_FILE_SORTER_HAS_MTMD\n    (void)image_path;\n    throw std::runtime_error(\"Visual LLM support is not available in this build.\");\n#else\n    auto logger = Logger::get_logger(\"core_logger\");\n    BitmapPtr bitmap(mtmd_helper_bitmap_init_from_file(vision_ctx_, image_path.string().c_str()));\n    if (!bitmap) {\n        throw std::runtime_error(\"Failed to load image for LLaVA: \" + image_path.string());\n    }\n\n    const std::string description = infer_text(bitmap.get(),\n                                               build_description_prompt(),\n                                               settings_.n_predict);\n\n    const std::string raw_filename = infer_text(nullptr,\n                                                build_filename_prompt(description),\n                                                settings_.n_predict);\n    if (logger) {\n        logger->info(\"LLaVA raw filename: {}\", raw_filename);\n    }\n    std::string filename_base = sanitize_filename(raw_filename, kMaxFilenameWords, kMaxFilenameLength);\n    if (filename_base.empty()) {\n        filename_base = sanitize_filename(description, kMaxFilenameWords, kMaxFilenameLength);\n    }\n    if (filename_base.empty()) {\n        filename_base = \"image_\" + slugify(image_path.stem().string());\n    }\n\n    LlavaImageAnalysisResult result;\n    result.description = description;\n    result.suggested_name = normalize_filename(filename_base, image_path);\n    if (logger) {\n        logger->info(\"LLaVA suggested filename: {}\", result.suggested_name);\n    }\n    return result;\n#endif\n}\n\nstd::string LlavaImageAnalyzer::build_description_prompt() const {\n    std::ostringstream oss;\n    oss << \"Please provide a detailed description of this image, focusing on the main subject \"\n        << \"and any important details.\\n\"\n        << \"Image: <__media__>\\n\"\n        << \"Description:\";\n    return oss.str();\n}\n\nstd::string LlavaImageAnalyzer::build_filename_prompt(const std::string& description) const {\n    std::ostringstream oss;\n    oss << \"Based on the description below, generate a specific and descriptive filename for the image.\\n\"\n        << \"Limit the filename to a maximum of 3 words. Use nouns and avoid starting with verbs like \"\n        << \"'depicts', 'shows', 'presents', etc.\\n\"\n        << \"Do not include any data type words like 'image', 'jpg', 'png', etc. Use only letters and \"\n        << \"connect words with underscores.\\n\\n\"\n        << \"Description: \" << description << \"\\n\\n\"\n        << \"Example:\\n\"\n        << \"Description: A photo of a sunset over the mountains.\\n\"\n        << \"Filename: sunset_over_mountains\\n\\n\"\n        << \"Now generate the filename.\\n\\n\"\n        << \"Output only the filename, without any additional text.\\n\\n\"\n        << \"Filename:\";\n    return oss.str();\n}\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\nvoid LlavaImageAnalyzer::mtmd_progress_callback(const char* name,\n                                                int32_t current_batch,\n                                                int32_t total_batches,\n                                                void* user_data) {\n    if (!user_data || total_batches <= 0 || current_batch <= 0) {\n        return;\n    }\n    if (name && std::strcmp(name, \"image\") != 0) {\n        return;\n    }\n    auto* self = static_cast<LlavaImageAnalyzer*>(user_data);\n    if (!self->settings_.batch_progress) {\n        return;\n    }\n    self->settings_.batch_progress(current_batch, total_batches);\n}\n\n#if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK)\nvoid LlavaImageAnalyzer::mtmd_log_callback(enum ggml_log_level level,\n                                           const char* text,\n                                           void* user_data) {\n    (void)level;\n    if (!text) {\n        return;\n    }\n    auto* self = static_cast<LlavaImageAnalyzer*>(user_data);\n#if !defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK)\n    if (self && self->settings_.batch_progress) {\n        int current_batch = 0;\n        int total_batches = 0;\n        if (std::sscanf(text, \"decoding image batch %d/%d\",\n                        &current_batch,\n                        &total_batches) == 2) {\n            if (current_batch > 0 && total_batches > 0) {\n                self->settings_.batch_progress(current_batch, total_batches);\n            }\n        }\n    }\n#endif\n    if (!self || !self->settings_.log_visual_output) {\n        return;\n    }\n    if (is_mtmd_prompt_log_line(text)) {\n        return;\n    }\n    std::fputs(text, stderr);\n    std::fflush(stderr);\n}\n#endif\n\n#endif\n\n#ifdef AI_FILE_SORTER_HAS_MTMD\nstd::string LlavaImageAnalyzer::infer_text(mtmd_bitmap* bitmap,\n                                           const std::string& prompt,\n                                           int32_t max_tokens) {\n    if (!context_) {\n        initialize_context();\n    }\n    reset_context_state();\n\n    ChunkPtr chunks(mtmd_input_chunks_init());\n    if (!chunks) {\n        throw std::runtime_error(\"Failed to allocate mtmd input chunks\");\n    }\n\n    mtmd_input_text text{};\n    text.text = prompt.c_str();\n    text.add_special = true;\n    text.parse_special = true;\n\n    const mtmd_bitmap* bitmaps[] = { bitmap };\n    const mtmd_bitmap** bitmap_ptr = nullptr;\n    int32_t bitmap_count = 0;\n    if (bitmap) {\n        bitmap_ptr = bitmaps;\n        bitmap_count = 1;\n    }\n\n#if defined(AI_FILE_SORTER_MTMD_LOG_CALLBACK)\n    struct LogGuard {\n        bool active{false};\n        explicit LogGuard(LlavaImageAnalyzer* self) : active(true) {\n            mtmd_helper_log_set(&LlavaImageAnalyzer::mtmd_log_callback, self);\n        }\n        ~LogGuard() {\n            if (!active) {\n                return;\n            }\n            mtmd_helper_log_set(nullptr, nullptr);\n        }\n    };\n\n    LogGuard log_guard(this);\n#endif\n\n    const int32_t tokenize_res = mtmd_tokenize(\n        vision_ctx_,\n        chunks.get(),\n        &text,\n        bitmap_ptr,\n        bitmap_count);\n    if (tokenize_res != 0) {\n        throw std::runtime_error(\"mtmd_tokenize failed with code \" + std::to_string(tokenize_res));\n    }\n\n#if defined(AI_FILE_SORTER_MTMD_PROGRESS_CALLBACK)\n    struct ProgressGuard {\n        bool active{false};\n        ProgressGuard(bool enabled, LlavaImageAnalyzer* self) : active(enabled) {\n            if (!active) {\n                return;\n            }\n            mtmd_helper_set_progress_callback(&LlavaImageAnalyzer::mtmd_progress_callback, self);\n        }\n        ~ProgressGuard() {\n            if (!active) {\n                return;\n            }\n            mtmd_helper_set_progress_callback(nullptr, nullptr);\n        }\n    };\n\n    const bool enable_progress = bitmap && settings_.batch_progress;\n    ProgressGuard progress_guard(enable_progress, this);\n#endif\n\n    llama_pos new_n_past = 0;\n    if (mtmd_helper_eval_chunks(vision_ctx_,\n                                context_,\n                                chunks.get(),\n                                0 /* n_past */,\n                                0 /* seq_id */,\n                                (batch_size_ > 0 ? batch_size_ : 512) /* n_batch */,\n                                true /* logits_last */,\n                                &new_n_past) != 0) {\n        throw std::runtime_error(\"mtmd_helper_eval_chunks failed\");\n    }\n\n    std::string response;\n    response.reserve(256);\n\n    const int vocab_size = llama_vocab_n_tokens(vocab_);\n    for (int32_t i = 0; i < max_tokens; ++i) {\n        const float* logits = llama_get_logits(context_);\n        if (!logits) {\n            throw std::runtime_error(\"llama_get_logits returned nullptr\");\n        }\n\n        llama_token token_id = greedy_sample(logits, vocab_size, settings_.temperature);\n        if (llama_vocab_is_eog(vocab_, token_id)) {\n            break;\n        }\n\n        char buffer[256];\n        const int n = llama_token_to_piece(vocab_, token_id, buffer, sizeof(buffer), 0, true);\n        if (n < 0) {\n            throw std::runtime_error(\"Failed to convert token to text piece\");\n        }\n        response.append(buffer, n);\n\n        llama_batch batch = llama_batch_get_one(&token_id, 1);\n        if (llama_decode(context_, batch) != 0) {\n            throw std::runtime_error(\"llama_decode failed during generation\");\n        }\n    }\n\n    return trim(response);\n}\n#else\nstd::string LlavaImageAnalyzer::infer_text(void* bitmap,\n                                           const std::string& prompt,\n                                           int32_t max_tokens) {\n    (void)bitmap;\n    (void)prompt;\n    (void)max_tokens;\n    throw std::runtime_error(\"Visual LLM support is not available in this build.\");\n}\n#endif\n\nstd::string LlavaImageAnalyzer::sanitize_filename(const std::string& value,\n                                                  size_t max_words,\n                                                  size_t max_length) const {\n    QString cleaned = sanitize_utf8_text(value).trimmed();\n    const QString prefix = QStringLiteral(\"filename:\");\n    if (cleaned.startsWith(prefix, Qt::CaseInsensitive)) {\n        cleaned = cleaned.mid(prefix.size()).trimmed();\n    }\n    const int newline = cleaned.indexOf('\\n');\n    if (newline != -1) {\n        cleaned = cleaned.left(newline);\n    }\n    const int carriage = cleaned.indexOf('\\r');\n    if (carriage != -1) {\n        cleaned = cleaned.left(carriage);\n    }\n    if (cleaned.size() >= 2) {\n        const QChar first = cleaned.front();\n        const QChar last = cleaned.back();\n        if ((first == '\"' && last == '\"') || (first == '\\'' && last == '\\'')) {\n            cleaned = cleaned.mid(1, cleaned.size() - 2);\n        }\n    }\n\n    auto words = split_words(cleaned);\n    std::vector<std::string> filtered;\n    filtered.reserve(words.size());\n    std::unordered_set<std::string> seen;\n    for (const auto& word : words) {\n        if (word.empty()) {\n            continue;\n        }\n        if (kStopwords.find(word) != kStopwords.end()) {\n            continue;\n        }\n        if (seen.insert(word).second) {\n            filtered.push_back(word);\n        }\n        if (filtered.size() >= max_words) {\n            break;\n        }\n    }\n\n    if (filtered.empty()) {\n        return std::string();\n    }\n\n    QString joined;\n    for (size_t i = 0; i < filtered.size(); ++i) {\n        if (i > 0) {\n            joined.append('_');\n        }\n        joined.append(QString::fromUtf8(filtered[i].c_str()));\n    }\n\n    if (joined.size() > static_cast<int>(max_length)) {\n        joined = joined.left(static_cast<int>(max_length));\n    }\n    while (!joined.isEmpty() && joined.endsWith('_')) {\n        joined.chop(1);\n    }\n\n    return joined.toUtf8().toStdString();\n}\n\nstd::string LlavaImageAnalyzer::trim(std::string value) {\n    return trim_copy(value);\n}\n\nstd::string LlavaImageAnalyzer::slugify(const std::string& value) {\n    const QString input = sanitize_utf8_text(value);\n    QString slug;\n    slug.reserve(input.size());\n    bool last_sep = false;\n    for (const QChar ch : input) {\n        if (ch.isLetterOrNumber()) {\n            slug.append(ch.toLower());\n            last_sep = false;\n        } else if (!last_sep && !slug.isEmpty()) {\n            slug.append('_');\n            last_sep = true;\n        }\n    }\n    if (!slug.isEmpty() && slug.endsWith('_')) {\n        slug.chop(1);\n    }\n    if (slug.isEmpty()) {\n        slug = QStringLiteral(\"item\");\n    }\n    return slug.toUtf8().toStdString();\n}\n\nstd::string LlavaImageAnalyzer::normalize_filename(const std::string& base,\n                                                   const std::filesystem::path& original_path) {\n    const std::string ext = original_path.extension().string();\n    if (base.empty()) {\n        return original_path.filename().string();\n    }\n    return ext.empty() ? base : base + ext;\n}\n"
  },
  {
    "path": "app/lib/LlmCatalog.cpp",
    "content": "#include \"LlmCatalog.hpp\"\n\n#include <QObject>\n\n#include <algorithm>\n#include <cstdlib>\n\nnamespace {\nQString resolved_llm_name(const DefaultLlmEntry& entry)\n{\n    const char* env_value = std::getenv(entry.name_env);\n    if (env_value && *env_value) {\n        return QString::fromUtf8(env_value);\n    }\n    return QString::fromUtf8(entry.fallback_name);\n}\n} // namespace\n\nconst std::vector<DefaultLlmEntry>& default_llm_entries()\n{\n    static const std::vector<DefaultLlmEntry> entries = {\n        {LLMChoice::Local_3b, \"LOCAL_LLM_3B_DOWNLOAD_URL\", \"LOCAL_LLM_3B_DISPLAY_NAME\",\n         \"LLaMa 3b v3.2 Instruct Q4\"},\n        {LLMChoice::Local_3b_legacy, \"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\",\n         \"LOCAL_LLM_3B_LEGACY_DISPLAY_NAME\", \"LLaMa 3b v3.2 Instruct Q8, legacy\"},\n        {LLMChoice::Local_7b, \"LOCAL_LLM_7B_DOWNLOAD_URL\", \"LOCAL_LLM_7B_DISPLAY_NAME\",\n         \"Mistral 7b Instruct v0.2 Q5\"}};\n    return entries;\n}\n\nQString default_llm_label(const DefaultLlmEntry& entry)\n{\n    return QObject::tr(\"Local LLM (%1)\").arg(resolved_llm_name(entry));\n}\n\nQString default_llm_label_for_choice(LLMChoice choice)\n{\n    const auto& entries = default_llm_entries();\n    const auto it = std::find_if(entries.begin(), entries.end(),\n                                 [choice](const DefaultLlmEntry& entry) {\n                                     return entry.choice == choice;\n                                 });\n    if (it == entries.end()) {\n        return QObject::tr(\"Local LLM\");\n    }\n    return default_llm_label(*it);\n}\n"
  },
  {
    "path": "app/lib/LocalLLMClient.cpp",
    "content": "#include \"LocalLLMClient.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include \"TestHooks.hpp\"\n#include \"LocalLLMTestAccess.hpp\"\n#include \"llama.h\"\n#include \"gguf.h\"\n#include \"ggml-backend.h\"\n#include <string>\n#include <vector>\n#include <cctype>\n#include <cstdio>\n#include <stdexcept>\n#include <iostream>\n#include <sstream>\n#include <spdlog/spdlog.h>\n#include <cstdlib>\n#include <algorithm>\n#include <cstring>\n#include <climits>\n#include <cerrno>\n#include <filesystem>\n#include <optional>\n#include <cmath>\n#include <fstream>\n#include <limits>\n#include <string_view>\n#include <string>\n#include <array>\n#include <utility>\n\n#if defined(__APPLE__)\n#include <mach/mach.h>\n#include <sys/sysctl.h>\n#endif\n\n#if defined(_WIN32)\n[[maybe_unused]] static void set_env_var(const char *key, const char *value) {\n    _putenv_s(key, value);\n}\n#else\n[[maybe_unused]] static void set_env_var(const char *key, const char *value) {\n    setenv(key, value, 1);\n}\n#endif\n\n\nnamespace {\n\nstruct GgufCtxDeleter {\n    void operator()(gguf_context* ctx) const { gguf_free(ctx); }\n};\n\nbool try_parse_env_int(const char *key, int &out) {\n    const char *value = std::getenv(key);\n    if (!value || *value == '\\0') {\n        return false;\n    }\n\n    char *end_ptr = nullptr;\n    errno = 0;\n    long parsed = std::strtol(value, &end_ptr, 10);\n    if (end_ptr == value || *end_ptr != '\\0' || errno == ERANGE) {\n        return false;\n    }\n    if (parsed > INT_MAX || parsed < INT_MIN) {\n        return false;\n    }\n\n    out = static_cast<int>(parsed);\n    return true;\n}\n\nint resolve_gpu_layer_override() {\n    int parsed = 0;\n    if (try_parse_env_int(\"AI_FILE_SORTER_N_GPU_LAYERS\", parsed)) {\n        return parsed;\n    }\n    if (try_parse_env_int(\"LLAMA_CPP_N_GPU_LAYERS\", parsed)) {\n        return parsed;\n    }\n    return INT_MIN;\n}\n\nstd::string gpu_layers_to_string(int value) {\n    if (value == -1) {\n        return \"auto (-1)\";\n    }\n    return std::to_string(value);\n}\n\nint resolve_context_length() {\n    int parsed = 0;\n    if (try_parse_env_int(\"AI_FILE_SORTER_CTX_TOKENS\", parsed) && parsed > 0) {\n        return parsed;\n    }\n    if (try_parse_env_int(\"LLAMA_CPP_MAX_CONTEXT\", parsed) && parsed > 0) {\n        return parsed;\n    }\n    return 2048; // increased default to better accommodate larger prompts (whitelists, hints)\n}\n\nbool is_cpu_backend_requested() {\n    auto is_cpu_env = [](const char* value) {\n        if (!value || *value == '\\0') {\n            return false;\n        }\n        std::string lowered(value);\n        std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) {\n            return static_cast<char>(std::tolower(c));\n        });\n        return lowered == \"cpu\";\n    };\n\n    if (is_cpu_env(std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\")) ||\n        is_cpu_env(std::getenv(\"LLAMA_ARG_DEVICE\"))) {\n        return true;\n    }\n\n    const int override_layers = resolve_gpu_layer_override();\n    return override_layers != INT_MIN && override_layers <= 0;\n}\n\nbool allow_gpu_fallback(const LocalLLMClient::FallbackDecisionCallback& callback,\n                        const std::shared_ptr<spdlog::logger>& logger,\n                        std::string_view reason)\n{\n    if (is_cpu_backend_requested()) {\n        return false;\n    }\n    if (!callback) {\n        return true;\n    }\n    bool allowed = callback(std::string(reason));\n    if (!allowed && logger) {\n        logger->warn(\"GPU fallback declined: {}\", reason);\n    }\n    return allowed;\n}\n\nstruct MetalDeviceInfo {\n    size_t total_bytes = 0;\n    size_t free_bytes = 0;\n    std::string name;\n\n    bool valid() const {\n        return total_bytes > 0;\n    }\n};\n\n#if defined(GGML_USE_METAL)\nMetalDeviceInfo query_primary_gpu_device() {\n    MetalDeviceInfo info;\n\n#if defined(__APPLE__)\n    uint64_t memsize = 0;\n    size_t len = sizeof(memsize);\n    if (sysctlbyname(\"hw.memsize\", &memsize, &len, nullptr, 0) == 0) {\n        info.total_bytes = static_cast<size_t>(memsize);\n    }\n\n    mach_port_t host_port = mach_host_self();\n    vm_size_t page_size = 0;\n    if (host_port != MACH_PORT_NULL && host_page_size(host_port, &page_size) == KERN_SUCCESS) {\n        vm_statistics64_data_t vm_stat {};\n        mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;\n        if (host_statistics64(host_port, HOST_VM_INFO64,\n                              reinterpret_cast<host_info64_t>(&vm_stat), &count) == KERN_SUCCESS) {\n            const uint64_t free_pages = static_cast<uint64_t>(vm_stat.free_count) +\n                                        static_cast<uint64_t>(vm_stat.inactive_count);\n            info.free_bytes = static_cast<size_t>(free_pages * static_cast<uint64_t>(page_size));\n        }\n    }\n\n    info.name = \"Metal (system memory)\";\n#endif\n\n    return info;\n}\n\nbool metal_backend_available(const std::shared_ptr<spdlog::logger>& logger) {\n    ggml_backend_reg_t metal = ggml_backend_reg_by_name(\"Metal\");\n    if (!metal) {\n        metal = ggml_backend_reg_by_name(\"MTL\");\n    }\n    if (!metal) {\n        if (logger) {\n            logger->warn(\"Metal backend not registered under aliases Metal/MTL; falling back to CPU\");\n        }\n        return false;\n    }\n    const size_t dev_count = ggml_backend_reg_dev_count(metal);\n    if (dev_count == 0) {\n        if (logger) {\n            logger->warn(\"No Metal devices detected; falling back to CPU\");\n        }\n        return false;\n    }\n    return true;\n}\n#endif // defined(GGML_USE_METAL)\n\nbool case_insensitive_contains(std::string_view text, std::string_view needle) {\n    if (needle.empty()) {\n        return true;\n    }\n\n    std::string text_lower(text);\n    std::string needle_lower(needle);\n    std::transform(text_lower.begin(), text_lower.end(), text_lower.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    std::transform(needle_lower.begin(), needle_lower.end(), needle_lower.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return text_lower.find(needle_lower) != std::string::npos;\n}\n\nstd::string to_lower_copy(std::string value);\n\nstd::string trim_copy(std::string value) {\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space));\n    value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end());\n    return value;\n}\n\nstd::string collapse_spaces_copy(std::string value) {\n    std::string collapsed;\n    collapsed.reserve(value.size());\n    bool previous_space = false;\n    for (unsigned char ch : value) {\n        if (std::isspace(ch)) {\n            if (!previous_space) {\n                collapsed.push_back(' ');\n            }\n            previous_space = true;\n            continue;\n        }\n        collapsed.push_back(static_cast<char>(ch));\n        previous_space = false;\n    }\n    return trim_copy(std::move(collapsed));\n}\n\nstd::string strip_wrapping_punctuation(std::string value) {\n    auto is_wrapping = [](unsigned char ch) {\n        switch (ch) {\n            case '\"':\n            case '\\'':\n            case '`':\n            case '(':\n            case ')':\n            case '[':\n            case ']':\n            case '{':\n            case '}':\n            case '<':\n            case '>':\n                return true;\n            default:\n                return false;\n        }\n    };\n\n    while (!value.empty() && (std::isspace(static_cast<unsigned char>(value.front())) ||\n                              is_wrapping(static_cast<unsigned char>(value.front())))) {\n        value.erase(value.begin());\n    }\n    while (!value.empty() && (std::isspace(static_cast<unsigned char>(value.back())) ||\n                              is_wrapping(static_cast<unsigned char>(value.back())) ||\n                              value.back() == '.' || value.back() == ',' ||\n                              value.back() == ':' || value.back() == ';')) {\n        value.pop_back();\n    }\n    return value;\n}\n\nstd::string strip_trailing_parenthetical_gloss(std::string value) {\n    value = trim_copy(std::move(value));\n    while (true) {\n        const auto open = value.rfind(\" (\");\n        if (open == std::string::npos) {\n            break;\n        }\n\n        std::string gloss = trim_copy(value.substr(open + 2));\n        if (!gloss.empty() && gloss.back() == ')') {\n            gloss.pop_back();\n            gloss = trim_copy(std::move(gloss));\n        }\n\n        const bool has_alpha_chars = std::any_of(gloss.begin(), gloss.end(), [](unsigned char ch) {\n            return std::isalpha(ch);\n        });\n        if (!has_alpha_chars) {\n            break;\n        }\n\n        value = trim_copy(value.substr(0, open));\n    }\n    return value;\n}\n\nstd::size_t find_case_insensitive(const std::string& value, std::string_view needle) {\n    const std::string lower_value = to_lower_copy(value);\n    std::string lower_needle(needle);\n    std::transform(lower_needle.begin(), lower_needle.end(), lower_needle.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return lower_value.find(lower_needle);\n}\n\nstd::string strip_explanatory_suffix(std::string value) {\n    static const std::vector<std::string_view> markers = {\n        \" (based on\",\n        \" (note\",\n        \" (since\",\n        \" - this \",\n        \" - based on\",\n        \" because \",\n        \" based on \",\n        \" which \",\n        \" since \",\n        \" however \",\n        \" specifically \",\n        \" indicating \",\n        \" indicates \",\n        \" commonly \",\n        \" related to \"\n    };\n\n    std::size_t cut = std::string::npos;\n    for (const std::string_view marker : markers) {\n        const auto pos = find_case_insensitive(value, marker);\n        if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) {\n            cut = pos;\n        }\n    }\n    if (cut != std::string::npos) {\n        value.resize(cut);\n    }\n\n    return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value)));\n}\n\nstd::string extract_category_phrase(std::string value) {\n    struct PhrasePattern {\n        std::string_view prefix;\n        std::string_view suffix;\n    };\n    static const std::vector<PhrasePattern> patterns = {\n        {\"falls under the \", \" category\"},\n        {\"falls under \", \" category\"},\n        {\"belongs to the \", \" category\"},\n        {\"belongs to \", \" category\"},\n        {\"categorized as \", \"\"},\n        {\"classified as \", \"\"},\n        {\"category is \", \"\"},\n        {\"category would be \", \"\"}\n    };\n\n    const std::string lower = to_lower_copy(value);\n    for (const auto& pattern : patterns) {\n        const auto start = lower.find(pattern.prefix);\n        if (start == std::string::npos) {\n            continue;\n        }\n        const std::size_t content_start = start + pattern.prefix.size();\n        std::size_t content_end = value.size();\n        if (!pattern.suffix.empty()) {\n            content_end = lower.find(pattern.suffix, content_start);\n            if (content_end == std::string::npos || content_end <= content_start) {\n                continue;\n            }\n        }\n        return value.substr(content_start, content_end - content_start);\n    }\n    return value;\n}\n\nstd::string strip_inline_label_artifacts(std::string value, bool category_label) {\n    const auto markers = category_label\n        ? std::array<std::string_view, 8>{\n              \", subcategory\",\n              \", sub category\",\n              \" - subcategory\",\n              \" - sub category\",\n              \"; subcategory\",\n              \"; sub category\",\n              \" subcategory:\",\n              \" sub category:\"\n          }\n        : std::array<std::string_view, 8>{\n              \", category\",\n              \", main category\",\n              \" - category\",\n              \" - main category\",\n              \"; category\",\n              \"; main category\",\n              \" category:\",\n              \" main category:\"\n          };\n\n    std::size_t cut = std::string::npos;\n    for (const std::string_view marker : markers) {\n        const auto pos = find_case_insensitive(value, marker);\n        if (pos != std::string::npos && (cut == std::string::npos || pos < cut)) {\n            cut = pos;\n        }\n    }\n    if (cut != std::string::npos) {\n        value.resize(cut);\n    }\n\n    return trim_copy(std::move(value));\n}\n\nstd::string normalize_candidate_label(std::string value, bool category_label) {\n    value = strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(std::move(value))));\n    if (value.empty()) {\n        return value;\n    }\n    if (category_label) {\n        value = extract_category_phrase(std::move(value));\n    }\n    value = strip_explanatory_suffix(std::move(value));\n    value = strip_trailing_parenthetical_gloss(std::move(value));\n    value = strip_inline_label_artifacts(std::move(value), category_label);\n    return strip_wrapping_punctuation(collapse_spaces_copy(std::move(value)));\n}\n\nstd::string to_lower_copy(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nbool has_alpha(std::string_view value) {\n    return std::any_of(value.begin(), value.end(), [](unsigned char ch) {\n        return std::isalpha(ch);\n    });\n}\n\nbool is_heading_like_label(const std::string& value) {\n    const std::string lower = to_lower_copy(strip_wrapping_punctuation(collapse_spaces_copy(trim_copy(value))));\n    static const std::array<std::string_view, 16> exact_matches = {\n        \"category\",\n        \"main category\",\n        \"subcategory\",\n        \"sub category\",\n        \"categorization\",\n        \"classification\",\n        \"result\",\n        \"answer\",\n        \"note\",\n        \"warning\",\n        \"disclaimer\",\n        \"reason\",\n        \"explanation\",\n        \"full path\",\n        \"file name\",\n        \"directory name\"\n    };\n    for (const std::string_view candidate : exact_matches) {\n        if (lower == candidate) {\n            return true;\n        }\n    }\n    return case_insensitive_contains(lower, \"categorization\") ||\n           case_insensitive_contains(lower, \"classification\");\n}\n\nstd::vector<std::string> split_segments(const std::string& line, std::string_view delimiter) {\n    std::vector<std::string> segments;\n    std::size_t start = 0;\n    while (start <= line.size()) {\n        const auto pos = line.find(delimiter, start);\n        const std::string segment = trim_copy(line.substr(start, pos == std::string::npos ? pos : pos - start));\n        if (!segment.empty()) {\n            segments.push_back(segment);\n        }\n        if (pos == std::string::npos) {\n            break;\n        }\n        start = pos + delimiter.size();\n    }\n    return segments;\n}\n\nstd::optional<std::pair<std::string, std::string>> extract_inline_pair_from_line(const std::string& line) {\n    for (std::string_view delimiter : {std::string_view(\" : \"), std::string_view(\":\")}) {\n        const auto segments = split_segments(line, delimiter);\n        if (segments.size() < 2) {\n            continue;\n        }\n\n        for (std::size_t idx = segments.size() - 1; idx > 0; --idx) {\n            const std::string left = normalize_candidate_label(segments[idx - 1], true);\n            const std::string right = normalize_candidate_label(segments[idx], false);\n            if (left.size() < 2 || right.empty()) {\n                continue;\n            }\n            if (!has_alpha(left) || !has_alpha(right)) {\n                continue;\n            }\n            if (is_heading_like_label(left)) {\n                continue;\n            }\n            return std::make_pair(left, right);\n        }\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> extract_labeled_value(const std::string& line,\n                                                 std::initializer_list<std::string_view> labels,\n                                                 bool category_label) {\n    const auto colon = line.find(':');\n    if (colon == std::string::npos) {\n        return std::nullopt;\n    }\n\n    const std::string key = to_lower_copy(trim_copy(line.substr(0, colon)));\n    for (const std::string_view label : labels) {\n        if (key == label) {\n            const std::string value = normalize_candidate_label(line.substr(colon + 1), category_label);\n            if (!value.empty()) {\n                return value;\n            }\n            break;\n        }\n    }\n    return std::nullopt;\n}\n\nstd::string strip_code_fence(std::string output) {\n    output = trim_copy(std::move(output));\n    if (output.rfind(\"```\", 0) != 0) {\n        return output;\n    }\n\n    const auto first_newline = output.find('\\n');\n    if (first_newline == std::string::npos) {\n        return output;\n    }\n\n    const auto last_fence = output.rfind(\"\\n```\");\n    if (last_fence == std::string::npos || last_fence <= first_newline) {\n        return output;\n    }\n\n    return trim_copy(output.substr(first_newline + 1, last_fence - first_newline - 1));\n}\n\nstd::string sanitize_categorization_output(std::string output) {\n    output = strip_code_fence(std::move(output));\n    if (output.empty()) {\n        return output;\n    }\n\n    std::vector<std::string> lines;\n    std::istringstream input(output);\n    for (std::string line; std::getline(input, line); ) {\n        line = trim_copy(std::move(line));\n        if (!line.empty()) {\n            lines.push_back(std::move(line));\n        }\n    }\n\n    if (lines.empty()) {\n        return output;\n    }\n\n    std::string category;\n    std::string subcategory;\n    for (auto it = lines.rbegin(); it != lines.rend(); ++it) {\n        if (subcategory.empty()) {\n            if (auto value = extract_labeled_value(*it, {\"subcategory\", \"sub category\"}, false)) {\n                subcategory = std::move(*value);\n            }\n        }\n        if (category.empty()) {\n            if (auto value = extract_labeled_value(*it, {\"category\", \"main category\"}, true)) {\n                category = std::move(*value);\n            }\n        }\n        if (!category.empty() && !subcategory.empty()) {\n            return category + \" : \" + subcategory;\n        }\n    }\n\n    for (auto it = lines.rbegin(); it != lines.rend(); ++it) {\n        if (auto pair = extract_inline_pair_from_line(*it)) {\n            return pair->first + \" : \" + pair->second;\n        }\n    }\n\n    if (!category.empty()) {\n        return category;\n    }\n\n    return output;\n}\n\nstd::string categorization_system_prompt() {\n    return \"You are a file categorization assistant. If the file is an installer, \"\n           \"determine the type of software it installs. Base your answer on the \"\n           \"filename, extension, and any directory context provided. Reply with \"\n           \"exactly one line in the format <Main category> : <Subcategory>. Main \"\n           \"category must be broad (one or two words, plural). Subcategory must be \"\n           \"specific, relevant, and must not repeat the main category. Do not \"\n           \"explain your answer, add extra lines, or use label words like \"\n           \"'Category' or 'Subcategory'. If uncertain, make your best guess from \"\n           \"the name only.\";\n}\n\nint prompt_token_budget(int context_tokens, int max_tokens) {\n    if (context_tokens <= 0) {\n        return 0;\n    }\n    const int generation_reserve = std::max(32, max_tokens);\n    return std::max(1, context_tokens - generation_reserve);\n}\n\nstd::string truncate_with_ellipsis(std::string value, std::size_t limit) {\n    if (value.size() <= limit) {\n        return value;\n    }\n    if (limit <= 3) {\n        value.resize(limit);\n        return value;\n    }\n    value.resize(limit - 3);\n    value += \"...\";\n    return value;\n}\n\nstd::string shrink_user_prompt_for_context(const std::string& prompt, int attempt) {\n    static const std::array<std::size_t, 4> kSummaryBudgets = {1200, 800, 500, 300};\n    static const std::array<std::size_t, 4> kPromptBudgets = {1800, 1400, 1000, 700};\n\n    std::string trimmed = prompt;\n    const auto summary_marker = trimmed.find(\"\\nDocument summary: \");\n    if (summary_marker != std::string::npos) {\n        const auto file_name_marker = trimmed.find(\"\\nFile name:\", summary_marker + 1);\n        const auto directory_name_marker = trimmed.find(\"\\nDirectory name:\", summary_marker + 1);\n        std::size_t suffix_start = std::string::npos;\n        if (file_name_marker != std::string::npos) {\n            suffix_start = file_name_marker;\n        }\n        if (directory_name_marker != std::string::npos) {\n            suffix_start = suffix_start == std::string::npos\n                ? directory_name_marker\n                : std::min(suffix_start, directory_name_marker);\n        }\n        if (suffix_start == std::string::npos) {\n            suffix_start = trimmed.size();\n        }\n\n        const std::size_t summary_start = summary_marker + std::string(\"\\nDocument summary: \").size();\n        const std::size_t summary_length = suffix_start > summary_start ? suffix_start - summary_start : 0;\n        const std::size_t budget = kSummaryBudgets[std::min<std::size_t>(\n            static_cast<std::size_t>(attempt),\n            kSummaryBudgets.size() - 1)];\n        if (summary_length > budget) {\n            const std::string prefix = trimmed.substr(0, summary_start);\n            const std::string summary = truncate_with_ellipsis(trimmed.substr(summary_start, summary_length), budget);\n            const std::string suffix = trimmed.substr(suffix_start);\n            return prefix + summary + suffix;\n        }\n    }\n\n    const std::size_t budget = kPromptBudgets[std::min<std::size_t>(\n        static_cast<std::size_t>(attempt),\n        kPromptBudgets.size() - 1)];\n    if (trimmed.size() > budget) {\n        return truncate_with_ellipsis(trimmed, budget);\n    }\n\n    return trimmed;\n}\n\nbool is_probably_integrated_gpu(ggml_backend_dev_t device,\n                                enum ggml_backend_dev_type type) {\n#if defined(AI_FILE_SORTER_GGML_HAS_IGPU_ENUM)\n    (void) device;\n    return type == GGML_BACKEND_DEVICE_TYPE_IGPU;\n#else\n    (void) type;\n\n    const auto matches_hint = [](const char * value) {\n        if (!value || value[0] == '\\0') {\n            return false;\n        }\n        constexpr std::array<std::string_view, 4> hints = {\"integrated\", \"apu\", \"shared\", \"uma\"};\n        const std::string_view view(value);\n        for (const std::string_view hint : hints) {\n            if (case_insensitive_contains(view, hint)) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    return matches_hint(ggml_backend_dev_name(device)) ||\n           matches_hint(ggml_backend_dev_description(device));\n#endif\n}\n\nvoid load_ggml_backends_once(const std::shared_ptr<spdlog::logger>& logger) {\n    static bool loaded = false;\n    if (loaded) {\n        return;\n    }\n\n    const char* ggml_dir = std::getenv(\"AI_FILE_SORTER_GGML_DIR\");\n    if (ggml_dir && ggml_dir[0] != '\\0') {\n        if (logger) {\n            logger->info(\"Loading ggml backends from '{}'\", ggml_dir);\n        }\n        ggml_backend_load_all_from_path(ggml_dir);\n    } else {\n        ggml_backend_load_all();\n    }\n\n    loaded = true;\n}\n\nusing BackendMemoryInfo = TestHooks::BackendMemoryInfo;\n\nusing BackendMemoryProbe = TestHooks::BackendMemoryProbe;\nusing BackendAvailabilityProbe = TestHooks::BackendAvailabilityProbe;\n\nBackendMemoryProbe& backend_memory_probe_slot() {\n    static BackendMemoryProbe probe;\n    return probe;\n}\n\nBackendAvailabilityProbe& backend_availability_probe_slot() {\n    static BackendAvailabilityProbe probe;\n    return probe;\n}\n\nbool query_backend_available_impl(std::string_view backend_name) {\n    if (backend_name.empty()) {\n        return false;\n    }\n\n    const std::string backend_name_str(backend_name);\n    ggml_backend_reg_t backend_reg = ggml_backend_reg_by_name(backend_name_str.c_str());\n    if (!backend_reg) {\n        return false;\n    }\n\n    return ggml_backend_reg_dev_count(backend_reg) > 0;\n}\n\nbool resolve_backend_available(std::string_view backend_name) {\n    if (auto& probe = backend_availability_probe_slot()) {\n        return probe(backend_name);\n    }\n    return query_backend_available_impl(backend_name);\n}\n\nbool backend_name_matches(const char *name, std::string_view backend_name) {\n    if (backend_name.empty()) {\n        return true;\n    }\n    return name && case_insensitive_contains(name, backend_name);\n}\n\nstd::optional<BackendMemoryInfo> build_backend_memory_info(ggml_backend_dev_t device,\n                                                           std::string_view backend_name) {\n    if (!device) {\n        return std::nullopt;\n    }\n\n    const auto type = ggml_backend_dev_type(device);\n    if (type != GGML_BACKEND_DEVICE_TYPE_GPU) {\n        return std::nullopt;\n    }\n\n    auto * reg = ggml_backend_dev_backend_reg(device);\n    const char * name = reg ? ggml_backend_reg_name(reg) : nullptr;\n    if (!backend_name_matches(name, backend_name)) {\n        return std::nullopt;\n    }\n\n    size_t free_bytes = 0;\n    size_t total_bytes = 0;\n    ggml_backend_dev_memory(device, &free_bytes, &total_bytes);\n    if (free_bytes == 0 && total_bytes == 0) {\n        return std::nullopt;\n    }\n\n    BackendMemoryInfo info;\n    info.memory.free_bytes = free_bytes;\n    info.memory.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes;\n    info.is_integrated = is_probably_integrated_gpu(device, type);\n    info.name = name ? name : \"\";\n\n    return info;\n}\n\nstd::optional<BackendMemoryInfo> query_backend_memory_metrics_impl(std::string_view backend_name) {\n    const size_t device_count = ggml_backend_dev_count();\n    BackendMemoryInfo best{};\n    bool found = false;\n\n    for (size_t i = 0; i < device_count; ++i) {\n        auto * device = ggml_backend_dev_get(i);\n        const auto info = build_backend_memory_info(device, backend_name);\n        if (!info.has_value()) {\n            continue;\n        }\n        if (!found || info->memory.total_bytes > best.memory.total_bytes) {\n            best = *info;\n            found = true;\n        }\n    }\n\n    if (found) {\n        return best;\n    }\n    return std::nullopt;\n}\n\n[[maybe_unused]] std::optional<BackendMemoryInfo> resolve_backend_memory(std::string_view backend_name) {\n    if (auto& probe = backend_memory_probe_slot()) {\n        return probe(backend_name);\n    }\n    return query_backend_memory_metrics_impl(backend_name);\n}\n\n} // namespace\n\nnamespace TestHooks {\n\nvoid set_backend_memory_probe(BackendMemoryProbe probe) {\n    backend_memory_probe_slot() = std::move(probe);\n}\n\nvoid reset_backend_memory_probe() {\n    backend_memory_probe_slot() = BackendMemoryProbe{};\n}\n\nvoid set_backend_availability_probe(BackendAvailabilityProbe probe) {\n    backend_availability_probe_slot() = std::move(probe);\n}\n\nvoid reset_backend_availability_probe() {\n    backend_availability_probe_slot() = BackendAvailabilityProbe{};\n}\n\n} // namespace TestHooks\n\nnamespace {\n\nbool read_file_prefix(std::ifstream& file,\n                      std::vector<char>& buffer,\n                      std::size_t requested_bytes,\n                      std::size_t& bytes_read)\n{\n    const auto compute_safe_request = [&](std::size_t& safe_request) -> bool {\n        if (requested_bytes == 0 || requested_bytes > buffer.size()) {\n            return false;\n        }\n        const auto max_streamsize = static_cast<std::size_t>(std::numeric_limits<std::streamsize>::max());\n        const std::size_t clamped_request = std::min(requested_bytes, buffer.size());\n        safe_request = std::min(clamped_request, max_streamsize);\n        return safe_request > 0;\n    };\n\n    const auto validate_read_count = [&](std::streamsize read_count, std::size_t to_request) -> bool {\n        if (read_count <= 0) {\n            return false;\n        }\n        if (read_count > static_cast<std::streamsize>(to_request) ||\n            static_cast<std::size_t>(read_count) > buffer.size()) {\n            return false;\n        }\n        return true;\n    };\n\n    std::size_t safe_request = 0;\n    if (!compute_safe_request(safe_request)) {\n        return false;\n    }\n\n    const std::streamsize to_request = static_cast<std::streamsize>(safe_request);\n    file.read(buffer.data(), to_request);\n    if (!file && !file.eof()) {\n        return false;\n    }\n\n    const std::streamsize read_count = file.gcount();\n    if (!validate_read_count(read_count, safe_request)) {\n        return false;\n    }\n\n    bytes_read = static_cast<std::size_t>(read_count);\n    return true;\n}\n\nuint32_t read_le32(const char* ptr)\n{\n    uint32_t value = 0;\n    std::memcpy(&value, ptr, sizeof(uint32_t));\n    return value;\n}\n\nuint64_t read_le64(const char* ptr)\n{\n    uint64_t value = 0;\n    std::memcpy(&value, ptr, sizeof(uint64_t));\n    return value;\n}\n\nstd::optional<int32_t> read_uint_value(uint32_t type,\n                                       const char* ptr,\n                                       std::size_t available_bytes)\n{\n    switch (type) {\n        case 4: // GGUF_TYPE_UINT32\n        case 5: // GGUF_TYPE_INT32:\n            if (available_bytes >= sizeof(uint32_t)) {\n                return static_cast<int32_t>(read_le32(ptr));\n            }\n            break;\n        case 10: // GGUF_TYPE_UINT64\n        case 11: // GGUF_TYPE_INT64\n            if (available_bytes >= sizeof(uint64_t)) {\n                return static_cast<int32_t>(read_le64(ptr));\n            }\n            break;\n        default:\n            break;\n    }\n    return std::nullopt;\n}\n\nstd::optional<int32_t> read_gguf_numeric(gguf_context* ctx, int64_t id)\n{\n    const enum gguf_type type = gguf_get_kv_type(ctx, id);\n    switch (type) {\n        case GGUF_TYPE_INT16: return static_cast<int32_t>(gguf_get_val_i16(ctx, id));\n        case GGUF_TYPE_INT32: return gguf_get_val_i32(ctx, id);\n        case GGUF_TYPE_INT64: return static_cast<int32_t>(gguf_get_val_i64(ctx, id));\n        case GGUF_TYPE_UINT16: return static_cast<int32_t>(gguf_get_val_u16(ctx, id));\n        case GGUF_TYPE_UINT32: return static_cast<int32_t>(gguf_get_val_u32(ctx, id));\n        case GGUF_TYPE_UINT64: return static_cast<int32_t>(gguf_get_val_u64(ctx, id));\n        default:\n            return std::nullopt;\n    }\n}\n\nstd::optional<int32_t> try_block_count_keys(gguf_context* ctx,\n                                            const std::array<const char*, 6>& keys)\n{\n    for (const char* key : keys) {\n        const int64_t id = gguf_find_key(ctx, key);\n        if (id < 0) {\n            continue;\n        }\n        if (auto value = read_gguf_numeric(ctx, id)) {\n            return value;\n        }\n    }\n    return std::nullopt;\n}\n\nstd::optional<int32_t> infer_block_count_from_tensors(gguf_context* ctx)\n{\n    const int64_t tensor_count = gguf_get_n_tensors(ctx);\n    int32_t max_layer = -1;\n    for (int64_t i = 0; i < tensor_count; ++i) {\n        const char* tname = gguf_get_tensor_name(ctx, i);\n        if (!tname) {\n            continue;\n        }\n        int32_t current = -1;\n        for (const char* p = tname; *p; ++p) {\n            if (std::isdigit(static_cast<unsigned char>(*p))) {\n                int value = 0;\n                while (*p && std::isdigit(static_cast<unsigned char>(*p))) {\n                    value = value * 10 + (*p - '0');\n                    ++p;\n                }\n                current = std::max(current, value);\n            }\n        }\n        if (current > max_layer) {\n            max_layer = current;\n        }\n    }\n    if (max_layer >= 0) {\n        return max_layer + 1; // zero-indexed\n    }\n    return std::nullopt;\n}\n\nbool format_prompt(llama_model* model,\n                   std::string_view system_prompt,\n                   std::string_view user_prompt,\n                   std::string& final_prompt)\n{\n    if (!model) {\n        return false;\n    }\n\n    const char* tmpl = llama_model_chat_template(model, nullptr);\n    if (!tmpl || tmpl[0] == '\\0') {\n        final_prompt.clear();\n        if (!system_prompt.empty()) {\n            final_prompt.append(system_prompt);\n            final_prompt.append(\"\\n\\n\");\n        }\n        final_prompt.append(user_prompt);\n        return true;\n    }\n\n    std::vector<std::string> owned_messages;\n    owned_messages.reserve(system_prompt.empty() ? 1 : 2);\n    std::vector<llama_chat_message> messages;\n    messages.reserve(system_prompt.empty() ? 1 : 2);\n\n    if (!system_prompt.empty()) {\n        owned_messages.emplace_back(system_prompt);\n        messages.push_back({\"system\", owned_messages.back().c_str()});\n    }\n\n    owned_messages.emplace_back(user_prompt);\n    messages.push_back({\"user\", owned_messages.back().c_str()});\n\n    std::size_t estimated_size = 4096;\n    for (const auto& message : owned_messages) {\n        estimated_size += message.size() * 2;\n    }\n\n    std::vector<char> formatted_prompt(estimated_size);\n    int actual_len = llama_chat_apply_template(tmpl,\n                                               messages.data(),\n                                               messages.size(),\n                                               true,\n                                               formatted_prompt.data(),\n                                               static_cast<int32_t>(formatted_prompt.size()));\n    if (actual_len < 0) {\n        return false;\n    }\n\n    if (actual_len >= static_cast<int>(formatted_prompt.size())) {\n        formatted_prompt.resize(static_cast<std::size_t>(actual_len) + 1);\n        actual_len = llama_chat_apply_template(tmpl,\n                                               messages.data(),\n                                               messages.size(),\n                                               true,\n                                               formatted_prompt.data(),\n                                               static_cast<int32_t>(formatted_prompt.size()));\n        if (actual_len < 0 || actual_len >= static_cast<int>(formatted_prompt.size())) {\n            return false;\n        }\n    }\n\n    final_prompt.assign(formatted_prompt.data(), static_cast<std::size_t>(actual_len));\n    return true;\n}\n\nbool tokenize_prompt(const llama_vocab* vocab,\n                     const std::string& final_prompt,\n                     std::vector<llama_token>& prompt_tokens,\n                     int& n_prompt,\n                     const std::shared_ptr<spdlog::logger>& logger)\n{\n    n_prompt = -llama_tokenize(vocab,\n                               final_prompt.c_str(),\n                               final_prompt.size(),\n                               nullptr,\n                               0,\n                               true,\n                               true);\n    if (n_prompt <= 0) {\n        if (logger) {\n            logger->error(\"Failed to determine token count for prompt\");\n        }\n        return false;\n    }\n\n    prompt_tokens.resize(static_cast<size_t>(n_prompt));\n    if (llama_tokenize(vocab,\n                       final_prompt.c_str(),\n                       final_prompt.size(),\n                       prompt_tokens.data(),\n                       prompt_tokens.size(),\n                       true,\n                       true) < 0) {\n        if (logger) {\n            logger->error(\"Tokenization failed for prompt\");\n        }\n        return false;\n    }\n\n    return true;\n}\n\nstd::string run_generation_loop(llama_context* ctx,\n                                llama_sampler* smpl,\n                                std::vector<llama_token>& prompt_tokens,\n                                int n_prompt,\n                                int max_tokens,\n                                const std::shared_ptr<spdlog::logger>& logger,\n                                const llama_vocab* vocab)\n{\n    const int ctx_n_ctx = static_cast<int>(llama_n_ctx(ctx));\n    int ctx_n_batch = static_cast<int>(llama_n_batch(ctx));\n    if (ctx_n_batch <= 0) {\n        ctx_n_batch = ctx_n_ctx;\n    }\n\n    const int prompt_budget = prompt_token_budget(ctx_n_ctx, max_tokens);\n    if (prompt_budget > 0 && n_prompt > prompt_budget) {\n        const int overflow = n_prompt - prompt_budget;\n        if (overflow > 0 && overflow < n_prompt) {\n            if (logger) {\n                logger->warn(\"Prompt tokens ({}) exceed prompt budget ({}) by {}; truncating oldest tokens\",\n                             n_prompt, prompt_budget, overflow);\n            }\n            prompt_tokens.erase(prompt_tokens.begin(),\n                                prompt_tokens.begin() + overflow);\n            n_prompt = prompt_budget;\n        }\n    }\n\n    int n_pos = 0;\n    while (n_pos < n_prompt) {\n        const int chunk = std::min(ctx_n_batch, n_prompt - n_pos);\n        llama_batch batch = llama_batch_get_one(prompt_tokens.data() + n_pos, chunk);\n        if (llama_decode(ctx, batch)) {\n            if (logger) {\n                logger->warn(\"llama_decode returned non-zero status during prompt eval; aborting generation\");\n            }\n            return std::string();\n        }\n        n_pos += chunk;\n    }\n\n    std::string output;\n    int generated_tokens = 0;\n    while (generated_tokens < max_tokens) {\n        llama_token new_token_id = llama_sampler_sample(smpl, ctx, -1);\n        if (llama_vocab_is_eog(vocab, new_token_id)) {\n            break;\n        }\n\n        char buf[128];\n        int n = llama_token_to_piece(vocab, new_token_id, buf,\n                                     sizeof(buf), 0, true);\n        if (n < 0) {\n            break;\n        }\n        output.append(buf, n);\n        generated_tokens++;\n\n        llama_batch batch = llama_batch_get_one(&new_token_id, 1);\n        if (llama_decode(ctx, batch)) {\n            if (logger) {\n                logger->warn(\"llama_decode returned non-zero status; aborting generation\");\n            }\n            break;\n        }\n    }\n\n    while (!output.empty() && std::isspace(static_cast<unsigned char>(output.front()))) {\n        output.erase(output.begin());\n    }\n\n    return output;\n}\n\nstd::optional<int32_t> parse_block_count_entry(const std::vector<char>& buffer,\n                                               std::size_t bytes_read,\n                                               std::size_t key_pos,\n                                               std::string_view key)\n{\n    if (key_pos < sizeof(uint64_t)) {\n        return std::nullopt;\n    }\n\n    const uint64_t declared_len = read_le64(buffer.data() + key_pos - sizeof(uint64_t));\n    if (declared_len != key.size()) {\n        return std::nullopt;\n    }\n\n    const std::size_t type_offset = key_pos + key.size();\n    if (type_offset + sizeof(uint32_t) > bytes_read) {\n        return std::nullopt;\n    }\n\n    const uint32_t type = read_le32(buffer.data() + type_offset);\n    const std::size_t value_offset = type_offset + sizeof(uint32_t);\n    if (value_offset >= bytes_read) {\n        return std::nullopt;\n    }\n\n    const std::size_t available = bytes_read - value_offset;\n    return read_uint_value(type, buffer.data() + value_offset, available);\n}\n\nstd::optional<int32_t> extract_block_count_gguf(const std::string& model_path) {\n    gguf_init_params params{};\n    params.no_alloc = true;\n    gguf_context* ctx = gguf_init_from_file(model_path.c_str(), params);\n    if (!ctx) {\n        return std::nullopt;\n    }\n\n    auto cleanup = std::unique_ptr<gguf_context, GgufCtxDeleter>(ctx);\n    static const std::array<const char*, 6> block_keys = {\n        \"llama.block_count\",\n        \"llama.layer_count\",\n        \"llama.n_layer\",\n        \"qwen.block_count\",\n        \"qwen2.block_count\",\n        \"block_count\"\n    };\n\n    if (auto meta_val = try_block_count_keys(ctx, block_keys)) {\n        return meta_val;\n    }\n\n    if (auto inferred = infer_block_count_from_tensors(ctx)) {\n        return inferred;\n    }\n\n    return std::nullopt;\n}\n\nstd::optional<int32_t> extract_block_count(const std::string & model_path) {\n    if (const auto via_ctx = extract_block_count_gguf(model_path)) {\n        return via_ctx;\n    }\n    std::ifstream file(model_path, std::ios::binary);\n    if (!file) {\n        return std::nullopt;\n    }\n\n    constexpr std::size_t kScanBytes = 8 * 1024 * 1024; // first 8 MiB should contain metadata\n    std::vector<char> buffer(kScanBytes);\n\n    std::streamsize to_read = static_cast<std::streamsize>(buffer.size());\n    std::error_code size_ec;\n    const auto file_size = std::filesystem::file_size(model_path, size_ec);\n    if (!size_ec) {\n        to_read = static_cast<std::streamsize>(std::min<std::uintmax_t>(file_size, buffer.size()));\n    }\n\n    if (to_read <= 0 || static_cast<std::size_t>(to_read) > buffer.size()) {\n        return std::nullopt;\n    }\n\n    std::size_t bytes_read = 0;\n    if (!read_file_prefix(file, buffer, static_cast<std::size_t>(to_read), bytes_read)) {\n        return std::nullopt;\n    }\n\n    const std::string_view data(buffer.data(), bytes_read);\n    [[maybe_unused]] static const std::string_view candidate_keys[] = {\n        \"llama.block_count\",\n        \"llama.layer_count\",\n        \"llama.n_layer\",\n        \"qwen.block_count\",\n        \"qwen2.block_count\",\n        \"block_count\",\n    };\n\n    for (const auto & key : candidate_keys) {\n        std::size_t pos = data.find(key);\n        while (pos != std::string_view::npos) {\n            if (const auto parsed_value = parse_block_count_entry(buffer, bytes_read, pos, key)) {\n                return parsed_value;\n            }\n\n            pos = data.find(key, pos + 1);\n        }\n    }\n\n    return std::nullopt;\n}\n\nstruct AutoGpuLayerEstimation {\n    int32_t layers = -1;\n    std::string reason;\n};\n\n#if defined(GGML_USE_METAL)\nAutoGpuLayerEstimation estimate_gpu_layers_for_metal(const std::string & model_path,\n                                                     const MetalDeviceInfo & device_info) {\n    AutoGpuLayerEstimation result;\n\n    if (!device_info.valid()) {\n        result.layers = -1;\n        result.reason = \"no GPU memory metrics available\";\n        return result;\n    }\n\n    std::error_code ec;\n    const auto file_size = std::filesystem::file_size(model_path, ec);\n    if (ec) {\n        result.layers = -1;\n        result.reason = \"model file size unavailable\";\n        return result;\n    }\n\n    const auto block_count_opt = extract_block_count(model_path);\n    if (!block_count_opt.has_value() || block_count_opt.value() <= 0) {\n        result.layers = -1;\n        result.reason = \"model block count not found\";\n        return result;\n    }\n\n    const int32_t total_layers = block_count_opt.value();\n    const double bytes_per_layer = static_cast<double>(file_size) / static_cast<double>(total_layers);\n\n    // Prefer reported free memory, but fall back to a fraction of total RAM on unified-memory systems.\n    double approx_free = static_cast<double>(device_info.free_bytes);\n    double total_bytes = static_cast<double>(device_info.total_bytes);\n\n    if (approx_free <= 0.0) {\n        approx_free = total_bytes * 0.6; // assume we can use ~60% of total RAM when free info is missing\n    }\n\n    const double safety_reserve = std::max(total_bytes * 0.10, 512.0 * 1024.0 * 1024.0); // keep at least 10% or 512 MiB free\n    double budget_bytes = std::max(approx_free - safety_reserve, total_bytes * 0.35);    // use at least 35% of total as budget\n    budget_bytes = std::min(budget_bytes, total_bytes * 0.80);                           // never try to use more than 80% of RAM\n\n    if (budget_bytes <= 0.0 || bytes_per_layer <= 0.0) {\n        result.layers = 0;\n        result.reason = \"insufficient GPU memory budget\";\n        return result;\n    }\n\n    // Account for temporary buffers / fragmentation.\n    const double overhead_factor = 1.20;\n    int32_t estimated_layers = static_cast<int32_t>(std::floor(budget_bytes / (bytes_per_layer * overhead_factor)));\n    estimated_layers = std::clamp<int32_t>(estimated_layers, 1, total_layers);\n\n    result.layers = estimated_layers;\n    if (estimated_layers == 0) {\n        result.reason = \"model layers larger than available GPU headroom\";\n    } else {\n        result.reason = \"estimated from GPU memory headroom\";\n    }\n\n    return result;\n}\n#endif // defined(GGML_USE_METAL)\n\nnamespace {\n\nstruct LayerMetrics {\n    int32_t total_layers{0};\n    double bytes_per_layer{0.0};\n};\n\nbool populate_layer_metrics(const std::string& model_path,\n                            AutoGpuLayerEstimation& result,\n                            LayerMetrics& metrics)\n{\n    std::error_code ec;\n    const auto file_size = std::filesystem::file_size(model_path, ec);\n    if (ec) {\n        result.layers = -1;\n        result.reason = \"model file size unavailable\";\n        return false;\n    }\n\n    const auto block_count_opt = extract_block_count(model_path);\n    if (!block_count_opt.has_value() || block_count_opt.value() <= 0) {\n        result.layers = -1;\n        result.reason = \"model block count not found\";\n        return false;\n    }\n\n    metrics.total_layers = block_count_opt.value();\n    metrics.bytes_per_layer =\n        static_cast<double>(file_size) / static_cast<double>(metrics.total_layers);\n    return true;\n}\n\nstruct CudaBudget {\n    double approx_free{0.0};\n    double usable_total{0.0};\n    double budget_bytes{0.0};\n};\n\nbool compute_cuda_budget(const Utils::CudaMemoryInfo& memory_info,\n                         double bytes_per_layer,\n                         AutoGpuLayerEstimation& result,\n                         CudaBudget& budget)\n{\n    if (!memory_info.valid()) {\n        result.layers = -1;\n        result.reason = \"CUDA memory metrics unavailable\";\n        return false;\n    }\n\n    budget.approx_free = static_cast<double>(memory_info.free_bytes);\n    double total_bytes = static_cast<double>(memory_info.total_bytes);\n    if (total_bytes <= 0.0) {\n        total_bytes = budget.approx_free;\n    }\n\n    budget.usable_total = std::max(total_bytes, budget.approx_free);\n    if (budget.usable_total <= 0.0) {\n        result.layers = 0;\n        result.reason = \"CUDA memory metrics invalid\";\n        return false;\n    }\n\n    if (budget.approx_free <= 0.0) {\n        budget.approx_free = budget.usable_total * 0.80;\n    } else if (budget.approx_free > budget.usable_total) {\n        budget.approx_free = budget.usable_total;\n    }\n\n    if (budget.approx_free <= 0.0 || bytes_per_layer <= 0.0) {\n        result.layers = 0;\n        result.reason = \"insufficient CUDA memory metrics\";\n        return false;\n    }\n\n    const double safety_reserve =\n        std::max(budget.usable_total * 0.05, 192.0 * 1024.0 * 1024.0);\n    budget.budget_bytes = budget.approx_free - safety_reserve;\n    if (budget.budget_bytes <= 0.0) {\n        budget.budget_bytes = budget.approx_free * 0.75;\n    }\n\n    const double max_budget = std::min(budget.approx_free * 0.98, budget.usable_total * 0.90);\n    const double min_budget = budget.usable_total * 0.45;\n    budget.budget_bytes = std::clamp(budget.budget_bytes, min_budget, max_budget);\n    return true;\n}\n\nbool finalize_cuda_estimate(const LayerMetrics& metrics,\n                            const CudaBudget& budget,\n                            AutoGpuLayerEstimation& result)\n{\n    constexpr double overhead_factor = 1.08;\n    const double denominator = metrics.bytes_per_layer * overhead_factor;\n    if (denominator <= 0.0) {\n        result.layers = 0;\n        result.reason = \"invalid CUDA layer parameters\";\n        return false;\n    }\n\n    int32_t estimated_layers =\n        static_cast<int32_t>(std::floor(budget.budget_bytes / denominator));\n    if (estimated_layers <= 0) {\n        result.layers = 0;\n        result.reason = \"insufficient CUDA memory budget\";\n        return false;\n    }\n\n    result.layers = std::clamp<int32_t>(estimated_layers, 1, metrics.total_layers);\n    result.reason = \"estimated from CUDA memory headroom\";\n    return true;\n}\n\n} // namespace\n\n[[maybe_unused]] AutoGpuLayerEstimation estimate_gpu_layers_for_cuda(const std::string & model_path,\n                                                                     const Utils::CudaMemoryInfo & memory_info) {\n    AutoGpuLayerEstimation result;\n\n    LayerMetrics metrics;\n    if (!populate_layer_metrics(model_path, result, metrics)) {\n        return result;\n    }\n\n    CudaBudget budget;\n    if (!compute_cuda_budget(memory_info, metrics.bytes_per_layer, result, budget)) {\n        return result;\n    }\n\n    if (!finalize_cuda_estimate(metrics, budget, result)) {\n        return result;\n    }\n\n    return result;\n}\n\nenum class PreferredBackend {\n    Auto,\n    Cpu,\n    Cuda,\n    Vulkan\n};\n\n[[maybe_unused]] PreferredBackend detect_preferred_backend() {\n    const char* env = std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\");\n    if (!env || *env == '\\0') {\n        return PreferredBackend::Auto;\n    }\n    std::string value(env);\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    if (value == \"cuda\") {\n        return PreferredBackend::Cuda;\n    }\n    if (value == \"vulkan\") {\n        return PreferredBackend::Vulkan;\n    }\n    if (value == \"cpu\") {\n        return PreferredBackend::Cpu;\n    }\n    return PreferredBackend::Auto;\n}\n\n#ifdef GGML_USE_METAL\nint determine_metal_layers(const std::string& model_path,\n                           const std::shared_ptr<spdlog::logger>& logger) {\n    int gpu_layers = resolve_gpu_layer_override();\n    if (gpu_layers == INT_MIN) {\n        const MetalDeviceInfo device_info = query_primary_gpu_device();\n        const auto estimation = estimate_gpu_layers_for_metal(model_path, device_info);\n\n        gpu_layers = (estimation.layers >= 0) ? estimation.layers : -1;\n\n        if (logger) {\n            const double to_mib = 1024.0 * 1024.0;\n            logger->info(\n                \"Metal device '{}' total {:.1f} MiB, free {:.1f} MiB -> n_gpu_layers={} ({})\",\n                device_info.name.empty() ? \"GPU\" : device_info.name,\n                device_info.total_bytes / to_mib,\n                device_info.free_bytes / to_mib,\n                gpu_layers_to_string(gpu_layers),\n                estimation.reason\n            );\n        }\n    } else if (logger) {\n        logger->info(\"Using Metal backend with explicit n_gpu_layers override={}\",\n                     gpu_layers_to_string(gpu_layers));\n    }\n\n    return gpu_layers;\n}\n#else\nbool apply_cpu_backend(llama_model_params& params,\n                       PreferredBackend backend_pref,\n                       const std::shared_ptr<spdlog::logger>& logger) {\n    if (backend_pref != PreferredBackend::Cpu) {\n        return false;\n    }\n    params.n_gpu_layers = 0;\n    set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n    if (logger) {\n        logger->info(\"GPU backend disabled via AI_FILE_SORTER_GPU_BACKEND=cpu\");\n    }\n    return true;\n}\n\nbool apply_vulkan_override(llama_model_params& params,\n                           int override_layers,\n                           const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (override_layers == INT_MIN) {\n        return false;\n    }\n\n    if (override_layers <= 0) {\n        params.n_gpu_layers = 0;\n        if (logger) {\n            logger->info(\"Vulkan backend requested but AI_FILE_SORTER_N_GPU_LAYERS <= 0; using CPU instead.\");\n        }\n        return true;\n    }\n\n    params.n_gpu_layers = override_layers;\n    if (logger) {\n        logger->info(\"Using Vulkan backend with explicit n_gpu_layers override={}\",\n                     gpu_layers_to_string(override_layers));\n    }\n    return true;\n}\n\nUtils::CudaMemoryInfo cap_integrated_gpu_memory(const BackendMemoryInfo& backend_memory,\n                                                const std::shared_ptr<spdlog::logger>& logger)\n{\n    Utils::CudaMemoryInfo adjusted = backend_memory.memory;\n    if (!backend_memory.is_integrated) {\n        return adjusted;\n    }\n\n    constexpr size_t igpu_cap_bytes = static_cast<size_t>(4ULL) * 1024ULL * 1024ULL * 1024ULL; // 4 GiB\n    adjusted.free_bytes = std::min(adjusted.free_bytes, igpu_cap_bytes);\n    adjusted.total_bytes = std::min(adjusted.total_bytes, igpu_cap_bytes);\n    if (logger) {\n        const double to_mib = 1024.0 * 1024.0;\n        logger->info(\"Vulkan device reported as integrated GPU; capping usable memory to {:.1f} MiB\",\n                     igpu_cap_bytes / to_mib);\n    }\n    return adjusted;\n}\n\nvoid log_vulkan_estimation(const Utils::CudaMemoryInfo& memory,\n                           const BackendMemoryInfo& original,\n                           const AutoGpuLayerEstimation& estimation,\n                           int resolved_layers,\n                           const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (!logger) {\n        return;\n    }\n    const double to_mib = 1024.0 * 1024.0;\n    const char* device_label = original.name.empty() ? \"Vulkan device\" : original.name.c_str();\n    logger->info(\n        \"{} total {:.1f} MiB, free {:.1f} MiB -> n_gpu_layers={} ({})\",\n        device_label,\n        memory.total_bytes / to_mib,\n        memory.free_bytes / to_mib,\n        gpu_layers_to_string(resolved_layers),\n        estimation.reason.empty() ? \"auto-estimated\" : estimation.reason);\n}\n\nbool finalize_vulkan_layers(const AutoGpuLayerEstimation& estimation,\n                            const Utils::CudaMemoryInfo& memory,\n                            llama_model_params& params,\n                            const BackendMemoryInfo& original,\n                            const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (estimation.layers > 0) {\n        params.n_gpu_layers = estimation.layers;\n        log_vulkan_estimation(memory, original, estimation, params.n_gpu_layers, logger);\n        return true;\n    }\n\n    params.n_gpu_layers = -1;\n    if (logger) {\n        logger->warn(\n            \"Vulkan estimator could not determine n_gpu_layers ({}); leaving llama.cpp auto (-1).\",\n            estimation.reason.empty() ? \"no detail\" : estimation.reason);\n    }\n    return true;\n}\n\nbool apply_vulkan_backend(const std::string& model_path,\n                          llama_model_params& params,\n                          const std::shared_ptr<spdlog::logger>& logger) {\n    load_ggml_backends_once(logger);\n    set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n\n    if (!resolve_backend_available(\"Vulkan\")) {\n        params.n_gpu_layers = 0;\n        set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n        set_env_var(\"LLAMA_ARG_DEVICE\", \"cpu\");\n        if (logger) {\n            logger->warn(\"Vulkan backend unavailable; using CPU backend.\");\n        }\n        return false;\n    }\n\n    const auto vk_memory = resolve_backend_memory(\"vulkan\");\n    if (apply_vulkan_override(params, resolve_gpu_layer_override(), logger)) {\n        return true;\n    }\n\n    if (!vk_memory.has_value()) {\n        params.n_gpu_layers = 0;\n        set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n        set_env_var(\"LLAMA_ARG_DEVICE\", \"cpu\");\n        if (logger) {\n            logger->warn(\"Vulkan backend memory metrics unavailable; using CPU backend.\");\n        }\n        return false;\n    }\n\n    Utils::CudaMemoryInfo adjusted = cap_integrated_gpu_memory(*vk_memory, logger);\n    const auto estimation = estimate_gpu_layers_for_cuda(model_path, adjusted);\n    finalize_vulkan_layers(estimation, adjusted, params, *vk_memory, logger);\n    return true;\n}\n\nbool handle_cuda_forced_off(bool cuda_forced_off,\n                            PreferredBackend backend_pref,\n                            llama_model_params& params,\n                            const std::shared_ptr<spdlog::logger>& logger) {\n    if (!cuda_forced_off) {\n        return false;\n    }\n    params.n_gpu_layers = 0;\n    set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n    if (logger) {\n        logger->info(\"CUDA disabled via GGML_DISABLE_CUDA environment override.\");\n        if (backend_pref == PreferredBackend::Cuda) {\n            logger->warn(\"AI_FILE_SORTER_GPU_BACKEND=cuda but GGML_DISABLE_CUDA forces CPU fallback.\");\n        }\n    }\n    return true;\n}\n\nvoid disable_cuda_backend(llama_model_params& params,\n                          const std::shared_ptr<spdlog::logger>& logger,\n                          const std::string& reason)\n{\n    params.n_gpu_layers = 0;\n    set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n    if (logger) {\n        logger->info(\"CUDA backend disabled: {}\", reason);\n    }\n}\n\nbool ensure_cuda_available(llama_model_params& params,\n                           const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (Utils::is_cuda_available()) {\n        return true;\n    }\n    disable_cuda_backend(params, logger, \"CUDA backend unavailable; using CPU backend\");\n    std::cout << \"No supported GPU backend detected. Running on CPU.\\n\";\n    return false;\n}\n\nbool apply_ngl_override(int override_layers,\n                        llama_model_params& params,\n                        const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (override_layers == INT_MIN) {\n        return false;\n    }\n\n    if (override_layers <= 0) {\n        disable_cuda_backend(\n            params,\n            logger,\n            fmt::format(\"AI_FILE_SORTER_N_GPU_LAYERS={} forcing CPU fallback\", override_layers));\n        return true;\n    }\n\n    params.n_gpu_layers = override_layers;\n    if (logger) {\n        logger->info(\"Using explicit CUDA n_gpu_layers override {}\",\n                     gpu_layers_to_string(override_layers));\n    }\n    std::cout << \"ngl override: \" << params.n_gpu_layers << std::endl;\n    return true;\n}\n\nstruct NglEstimationResult {\n    int candidate_layers{0};\n    int heuristic_layers{0};\n};\n\nNglEstimationResult estimate_ngl_from_cuda_info(const std::string& model_path,\n                                               const std::shared_ptr<spdlog::logger>& logger)\n{\n    NglEstimationResult result;\n    AutoGpuLayerEstimation estimation{};\n    std::optional<Utils::CudaMemoryInfo> cuda_info = Utils::query_cuda_memory();\n\n    if (!cuda_info.has_value()) {\n        if (logger) {\n            logger->warn(\"Unable to query CUDA memory information, falling back to heuristic\");\n        }\n        return result;\n    }\n\n    estimation = estimate_gpu_layers_for_cuda(model_path, *cuda_info);\n    result.heuristic_layers = Utils::compute_ngl_from_cuda_memory(*cuda_info);\n\n    int candidate_layers = estimation.layers > 0 ? estimation.layers : 0;\n    if (result.heuristic_layers > 0) {\n        candidate_layers = std::max(candidate_layers, result.heuristic_layers);\n    }\n    result.candidate_layers = candidate_layers;\n\n    if (logger) {\n        if (estimation.layers > 0 && estimation.layers != candidate_layers) {\n            logger->info(\"CUDA estimator suggested {} layers, but heuristic floor kept {}\",\n                         estimation.layers, candidate_layers);\n        }\n        const double to_mib = 1024.0 * 1024.0;\n        logger->info(\n            \"CUDA device total {:.1f} MiB, free {:.1f} MiB -> estimator={}, heuristic={}, chosen={} ({})\",\n            cuda_info->total_bytes / to_mib,\n            cuda_info->free_bytes / to_mib,\n            gpu_layers_to_string(estimation.layers),\n            gpu_layers_to_string(result.heuristic_layers),\n            gpu_layers_to_string(candidate_layers),\n            estimation.reason.empty() ? \"no estimation detail\" : estimation.reason);\n    }\n\n    return result;\n}\n\nint fallback_ngl(int heuristic_layers, const std::shared_ptr<spdlog::logger>& logger)\n{\n    if (heuristic_layers > 0) {\n        return heuristic_layers;\n    }\n\n    const int fallback = Utils::determine_ngl_cuda();\n    if (fallback > 0 && logger) {\n        logger->info(\"Using heuristic CUDA fallback -> n_gpu_layers={}\",\n                     gpu_layers_to_string(fallback));\n    }\n    return fallback;\n}\n\nbool configure_cuda_backend(const std::string& model_path,\n                            llama_model_params& params,\n                            const std::shared_ptr<spdlog::logger>& logger) {\n    if (!ensure_cuda_available(params, logger)) {\n        return false;\n    }\n\n    const int override_layers = resolve_gpu_layer_override();\n    if (apply_ngl_override(override_layers, params, logger)) {\n        return true;\n    }\n\n    const NglEstimationResult estimation = estimate_ngl_from_cuda_info(model_path, logger);\n    int ngl = estimation.candidate_layers;\n    if (ngl <= 0) {\n        ngl = fallback_ngl(estimation.heuristic_layers, logger);\n    }\n\n    if (ngl > 0) {\n        params.n_gpu_layers = ngl;\n        std::cout << \"ngl: \" << params.n_gpu_layers << std::endl;\n    } else {\n        disable_cuda_backend(params, logger, \"CUDA not usable after estimation; falling back to CPU.\");\n        std::cout << \"CUDA not usable, falling back to CPU.\\n\";\n    }\n    return true;\n}\n#endif\n\n} // namespace\n\n\nvoid silent_logger(enum ggml_log_level, const char *, void *) {}\n\n\nvoid llama_debug_logger(enum ggml_log_level level, const char *text, void *user_data) {\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level >= GGML_LOG_LEVEL_ERROR ? spdlog::level::err : spdlog::level::debug,\n                    \"[llama.cpp] {}\", text);\n    } else {\n        std::fprintf(stderr, \"[llama.cpp] %s\", text);\n    }\n}\n\nbool llama_logs_enabled_from_env()\n{\n    const char* env = std::getenv(\"AI_FILE_SORTER_LLAMA_LOGS\");\n    if (!env || env[0] == '\\0') {\n        env = std::getenv(\"LLAMA_CPP_DEBUG_LOGS\");\n    }\n    if (!env || env[0] == '\\0') {\n        return false;\n    }\n\n    std::string value{env};\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value != \"0\" && value != \"false\" && value != \"off\" && value != \"no\";\n}\n\n\nLocalLLMClient::LocalLLMClient(const std::string& model_path,\n                               FallbackDecisionCallback fallback_decision_callback)\n    : model_path(model_path),\n      fallback_decision_callback_(std::move(fallback_decision_callback))\n{\n    auto logger = Logger::get_logger(\"core_logger\");\n    if (logger) {\n        logger->info(\"Initializing local LLM client with model '{}'\", model_path);\n    }\n\n    configure_llama_logging(logger);\n    load_ggml_backends_once(logger);\n\n    const int context_length = std::clamp(resolve_context_length(), 512, 8192);\n    llama_model_params model_params = prepare_model_params(logger);\n\n    if (logger) {\n        logger->info(\"Configured context length {} token(s) for local LLM\", context_length);\n    }\n\n    model_params = load_model_or_throw(model_params, logger);\n    configure_context(context_length, model_params);\n}\n\n\nvoid LocalLLMClient::configure_llama_logging(const std::shared_ptr<spdlog::logger>& logger) const\n{\n    if (llama_logs_enabled_from_env()) {\n        llama_log_set(llama_debug_logger, nullptr);\n        if (logger) {\n            logger->info(\"Enabled detailed llama.cpp logging via environment configuration\");\n        }\n    } else {\n        llama_log_set(silent_logger, nullptr);\n    }\n}\n\n\nllama_model_params build_model_params_for_path(const std::string& model_path,\n                                               const std::shared_ptr<spdlog::logger>& logger) {\n    load_ggml_backends_once(logger);\n    llama_model_params model_params = llama_model_default_params();\n\n#ifdef GGML_USE_METAL\n    const char* backend_env = std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\");\n    if (backend_env) {\n        std::string value(backend_env);\n        std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n            return static_cast<char>(std::tolower(c));\n        });\n        if (value == \"cpu\") {\n            if (logger) {\n                logger->info(\"AI_FILE_SORTER_GPU_BACKEND=cpu set; disabling Metal and using CPU backend.\");\n            }\n            model_params.n_gpu_layers = 0;\n            return model_params;\n        }\n    }\n\n    if (!metal_backend_available(logger)) {\n        model_params.n_gpu_layers = 0;\n        return model_params;\n    }\n\n    model_params.n_gpu_layers = determine_metal_layers(model_path, logger);\n#else\n    const PreferredBackend backend_pref = detect_preferred_backend();\n    const char* disable_env = std::getenv(\"GGML_DISABLE_CUDA\");\n    const bool cuda_forced_off = disable_env && disable_env[0] != '\\0' && disable_env[0] != '0';\n\n    if (apply_cpu_backend(model_params, backend_pref, logger)) {\n        return model_params;\n    }\n\n    if (backend_pref == PreferredBackend::Vulkan) {\n        apply_vulkan_backend(model_path, model_params, logger);\n        return model_params;\n    }\n\n    if (handle_cuda_forced_off(cuda_forced_off, backend_pref, model_params, logger)) {\n        return model_params;\n    }\n\n    const bool prefer_vulkan = (backend_pref == PreferredBackend::Vulkan) ||\n                               (backend_pref == PreferredBackend::Auto);\n\n    if (prefer_vulkan) {\n        // Vulkan is the primary backend; keep CUDA disabled and steer llama.cpp to Vulkan.\n        set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n        set_env_var(\"LLAMA_ARG_DEVICE\", \"vulkan\");\n        apply_vulkan_backend(model_path, model_params, logger);\n        return model_params;\n    }\n\n    // CUDA requested explicitly.\n    if (handle_cuda_forced_off(cuda_forced_off, backend_pref, model_params, logger)) {\n        return model_params;\n    }\n\n    const bool cudaConfigured = configure_cuda_backend(model_path, model_params, logger);\n    if (!cudaConfigured) {\n        if (logger) {\n            logger->warn(\"CUDA backend explicitly requested but unavailable; attempting Vulkan fallback.\");\n        }\n        set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n        set_env_var(\"LLAMA_ARG_DEVICE\", \"vulkan\");\n        apply_vulkan_backend(model_path, model_params, logger);\n        return model_params;\n    }\n#endif\n\n    return model_params;\n}\n\nllama_model_params LocalLLMClient::prepare_model_params(const std::shared_ptr<spdlog::logger>& logger)\n{\n    return build_model_params_for_path(model_path, logger);\n}\n\n#if defined(AI_FILE_SORTER_TEST_BUILD) && !defined(GGML_USE_METAL)\nnamespace {\n\nPreferredBackend to_internal_backend(LocalLLMTestAccess::BackendPreference preference) {\n    switch (preference) {\n        case LocalLLMTestAccess::BackendPreference::Cpu: return PreferredBackend::Cpu;\n        case LocalLLMTestAccess::BackendPreference::Cuda: return PreferredBackend::Cuda;\n        case LocalLLMTestAccess::BackendPreference::Vulkan: return PreferredBackend::Vulkan;\n        case LocalLLMTestAccess::BackendPreference::Auto:\n        default:\n            return PreferredBackend::Auto;\n    }\n}\n\nLocalLLMTestAccess::BackendPreference to_external_backend(PreferredBackend preference) {\n    switch (preference) {\n        case PreferredBackend::Cpu: return LocalLLMTestAccess::BackendPreference::Cpu;\n        case PreferredBackend::Cuda: return LocalLLMTestAccess::BackendPreference::Cuda;\n        case PreferredBackend::Vulkan: return LocalLLMTestAccess::BackendPreference::Vulkan;\n        case PreferredBackend::Auto:\n        default:\n            return LocalLLMTestAccess::BackendPreference::Auto;\n    }\n}\n\n} // namespace\n\nnamespace LocalLLMTestAccess {\n\nBackendPreference detect_preferred_backend() {\n    return to_external_backend(::detect_preferred_backend());\n}\n\nbool apply_cpu_backend(llama_model_params& params, BackendPreference preference) {\n    return ::apply_cpu_backend(params, to_internal_backend(preference), nullptr);\n}\n\nbool apply_vulkan_backend(const std::string& model_path, llama_model_params& params) {\n    return ::apply_vulkan_backend(model_path, params, nullptr);\n}\n\nbool handle_cuda_forced_off(bool cuda_forced_off,\n                            BackendPreference preference,\n                            llama_model_params& params) {\n    return ::handle_cuda_forced_off(cuda_forced_off, to_internal_backend(preference), params, nullptr);\n}\n\nbool configure_cuda_backend(const std::string& model_path, llama_model_params& params) {\n    return ::configure_cuda_backend(model_path, params, nullptr);\n}\n\nllama_model_params prepare_model_params_for_testing(const std::string& model_path) {\n    return ::build_model_params_for_path(model_path, nullptr);\n}\n\n} // namespace LocalLLMTestAccess\n#endif // AI_FILE_SORTER_TEST_BUILD && !GGML_USE_METAL\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nnamespace LocalLLMTestAccess {\n\nstd::string sanitize_output_for_testing(const std::string& output) {\n    return sanitize_categorization_output(output);\n}\n\n} // namespace LocalLLMTestAccess\n#endif\n\n\nllama_model_params LocalLLMClient::load_model_or_throw(llama_model_params model_params,\n                                                       const std::shared_ptr<spdlog::logger>& logger)\n{\n    auto try_load = [&](const llama_model_params& params) {\n        model = llama_model_load_from_file(model_path.c_str(), params);\n        if (!model) {\n            return false;\n        }\n        if (logger) {\n            logger->info(\"Loaded local model '{}'\", model_path);\n        }\n        vocab = llama_model_get_vocab(model);\n        return true;\n    };\n\n    if (try_load(model_params)) {\n        return model_params;\n    }\n\n    if (model_params.n_gpu_layers != 0) {\n        if (logger) {\n            logger->warn(\"Failed to load model with GPU backend; retrying on CPU.\");\n        }\n        if (!allow_gpu_fallback(fallback_decision_callback_, logger, \"model load failure\")) {\n            if (logger) {\n                logger->warn(\"GPU fallback declined during model load; aborting.\");\n            }\n            throw std::runtime_error(\"GPU backend failed to initialize and CPU fallback was declined.\");\n        }\n        notify_status(Status::GpuFallbackToCpu);\n        set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n        set_env_var(\"LLAMA_ARG_DEVICE\", \"cpu\");\n        model_params.n_gpu_layers = 0;\n        if (try_load(model_params)) {\n            return model_params;\n        }\n    }\n\n    if (logger) {\n        logger->error(\"Failed to load model from '{}'\", model_path);\n    }\n    throw std::runtime_error(\"Failed to load model\");\n}\n\n\nvoid LocalLLMClient::configure_context(int context_length, const llama_model_params& model_params)\n{\n    ctx_params = llama_context_default_params();\n    ctx_params.n_ctx = context_length;\n    ctx_params.n_batch = context_length;\n#ifdef GGML_USE_METAL\n    if (model_params.n_gpu_layers != 0) {\n        ctx_params.offload_kqv = true;\n    }\n#else\n    (void)model_params;\n#endif\n}\n\n\nstd::string LocalLLMClient::make_prompt(const std::string& file_name,\n                                        const std::string& file_path,\n                                        FileType file_type,\n                                        const std::string& consistency_context)\n{\n    std::ostringstream prompt;\n    prompt << (file_type == FileType::File ? \"Categorize this file.\\n\" : \"Categorize this directory.\\n\");\n    if (!file_path.empty()) {\n        prompt << \"Full path: \" << file_path << \"\\n\";\n    }\n    prompt << (file_type == FileType::File ? \"File name: \" : \"Directory name: \")\n           << file_name << \"\\n\";\n\n    if (!consistency_context.empty()) {\n        prompt << \"\\n\" << consistency_context << \"\\n\";\n    }\n\n    return prompt.str();\n}\n\n\nstd::string LocalLLMClient::generate_response(const std::string& prompt,\n                                              int n_predict,\n                                              bool apply_sanitizer,\n                                              const std::string& system_prompt)\n{\n    auto logger = Logger::get_logger(\"core_logger\");\n    if (logger) {\n        logger->debug(\"Generating response with prompt length {} chars target {} tokens\", prompt.size(), n_predict);\n    }\n\n    struct ContextAttempt {\n        int n_ctx;\n        int n_batch;\n    };\n\n    auto build_context_attempts = [](int n_ctx, int n_batch) {\n        std::vector<ContextAttempt> attempts;\n        auto add_attempt = [&](int ctx, int batch) {\n            ctx = std::max(ctx, 512);\n            batch = std::clamp(batch, 1, ctx);\n            if (ctx > n_ctx || batch > n_batch) {\n                return;\n            }\n            if (ctx == n_ctx && batch == n_batch) {\n                return;\n            }\n            for (const auto& existing : attempts) {\n                if (existing.n_ctx == ctx && existing.n_batch == batch) {\n                    return;\n                }\n            }\n            attempts.push_back({ctx, batch});\n        };\n\n        add_attempt(std::min(n_ctx, 2048), std::min(n_batch, 1024));\n        add_attempt(std::min(n_ctx, 1024), std::min(n_batch, 512));\n        add_attempt(std::min(n_ctx, 512), std::min(n_batch, 256));\n        return attempts;\n    };\n\n    auto try_init_context = [&](const llama_context_params& base_params,\n                                int n_ctx,\n                                int n_batch,\n                                llama_context_params& resolved_params) -> llama_context* {\n        llama_context_params attempt = base_params;\n        attempt.n_ctx = n_ctx;\n        attempt.n_batch = std::min(n_batch, n_ctx);\n        auto* ctx = llama_init_from_model(model, attempt);\n        if (ctx) {\n            resolved_params = attempt;\n        }\n        return ctx;\n    };\n\n    auto init_context_with_retries = [&](const llama_context_params& base_params,\n                                         bool cpu_attempt,\n                                         llama_context_params& resolved_params) -> llama_context* {\n        auto* ctx = try_init_context(base_params, base_params.n_ctx, base_params.n_batch, resolved_params);\n        if (ctx) {\n            return ctx;\n        }\n        if (logger) {\n            logger->warn(\"Failed to initialize llama context (n_ctx={}, n_batch={}); retrying with smaller buffers{}\",\n                         base_params.n_ctx,\n                         base_params.n_batch,\n                         cpu_attempt ? \" on CPU\" : \"\");\n        }\n        for (const auto& attempt : build_context_attempts(base_params.n_ctx, base_params.n_batch)) {\n            if (logger) {\n                logger->warn(\"Retrying llama context init with n_ctx={}, n_batch={}{}\",\n                             attempt.n_ctx,\n                             attempt.n_batch,\n                             cpu_attempt ? \" on CPU\" : \"\");\n            }\n            ctx = try_init_context(base_params, attempt.n_ctx, attempt.n_batch, resolved_params);\n            if (ctx) {\n                return ctx;\n            }\n        }\n        return nullptr;\n    };\n\n    bool allow_fallback = true;\n    for (;;) {\n        llama_context* ctx = nullptr;\n        llama_sampler* smpl = nullptr;\n        try {\n            llama_context_params resolved_params = ctx_params;\n            llama_context_params base_params = ctx_params;\n            ctx = init_context_with_retries(base_params, false, resolved_params);\n\n            if (!ctx && !is_cpu_backend_requested()) {\n                if (!allow_gpu_fallback(fallback_decision_callback_, logger, \"context initialization failure\")) {\n                    allow_fallback = false;\n                    throw std::runtime_error(\"GPU backend failed during context initialization and CPU fallback was declined.\");\n                }\n                if (logger) {\n                    logger->warn(\"Context init failed on GPU; reloading model on CPU and retrying.\");\n                }\n                notify_status(Status::GpuFallbackToCpu);\n                llama_model_params cpu_params = llama_model_default_params();\n                cpu_params.n_gpu_layers = 0;\n                set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n                set_env_var(\"LLAMA_ARG_DEVICE\", \"cpu\");\n                set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n\n                llama_model* old_model = model;\n                llama_model* cpu_model = llama_model_load_from_file(model_path.c_str(), cpu_params);\n                if (!cpu_model) {\n                    if (logger) {\n                        logger->error(\"Failed to reload model on CPU after context init failure\");\n                    }\n                } else {\n                    if (old_model) {\n                        llama_model_free(old_model);\n                    }\n                    model = cpu_model;\n                    vocab = llama_model_get_vocab(model);\n#ifdef GGML_USE_METAL\n                    base_params = ctx_params;\n                    base_params.offload_kqv = false;\n#else\n                    base_params = ctx_params;\n#endif\n                    resolved_params = base_params;\n                    ctx = init_context_with_retries(base_params, true, resolved_params);\n                }\n            }\n\n            if (!ctx) {\n                if (logger) {\n                    logger->error(\"Failed to initialize llama context\");\n                }\n                return \"\";\n            }\n\n            ctx_params = resolved_params;\n\n            smpl = llama_sampler_chain_init(llama_sampler_chain_default_params());\n            llama_sampler_chain_add(smpl, llama_sampler_init_min_p(0.05f, 1));\n            llama_sampler_chain_add(smpl, llama_sampler_init_temp(0.8f));\n            llama_sampler_chain_add(smpl, llama_sampler_init_dist(LLAMA_DEFAULT_SEED));\n\n            std::vector<llama_token> prompt_tokens;\n            int n_prompt = 0;\n            std::string working_prompt = prompt;\n            std::string final_prompt;\n            const int context_budget = prompt_token_budget(static_cast<int>(resolved_params.n_ctx), n_predict);\n            for (int shrink_attempt = 0;; ++shrink_attempt) {\n                if (!format_prompt(model, system_prompt, working_prompt, final_prompt)) {\n                    if (logger) {\n                        logger->error(\"Failed to apply chat template to prompt\");\n                    }\n                    llama_free(ctx);\n                    llama_sampler_free(smpl);\n                    return \"\";\n                }\n\n                if (!tokenize_prompt(vocab, final_prompt, prompt_tokens, n_prompt, logger)) {\n                    llama_free(ctx);\n                    llama_sampler_free(smpl);\n                    return \"\";\n                }\n\n                if (context_budget <= 0 || n_prompt <= context_budget) {\n                    break;\n                }\n\n                const std::string trimmed_prompt = shrink_user_prompt_for_context(working_prompt, shrink_attempt);\n                if (trimmed_prompt == working_prompt) {\n                    if (logger) {\n                        logger->warn(\"Prompt tokens ({}) still exceed prompt budget ({}); proceeding with token truncation\",\n                                     n_prompt,\n                                     context_budget);\n                    }\n                    break;\n                }\n\n                if (logger) {\n                    logger->warn(\"Prompt tokens ({}) exceed prompt budget ({}); shrinking user prompt and retrying\",\n                                 n_prompt,\n                                 context_budget);\n                }\n                working_prompt = trimmed_prompt;\n            }\n\n            std::string output = run_generation_loop(ctx,\n                                                     smpl,\n                                                     prompt_tokens,\n                                                     n_prompt,\n                                                     n_predict,\n                                                     logger,\n                                                     vocab);\n\n            llama_sampler_reset(smpl);\n            llama_free(ctx);\n            llama_sampler_free(smpl);\n\n            if (logger) {\n                logger->debug(\"Generation complete, produced {} character(s)\", output.size());\n            }\n\n            if (apply_sanitizer) {\n                return sanitize_output(output);\n            }\n            return output;\n        } catch (const std::exception& ex) {\n            if (ctx) {\n                llama_free(ctx);\n            }\n            if (smpl) {\n                llama_sampler_free(smpl);\n            }\n\n            if (allow_fallback && !is_cpu_backend_requested()) {\n                if (!allow_gpu_fallback(fallback_decision_callback_, logger, \"generation failure\")) {\n                    allow_fallback = false;\n                    throw std::runtime_error(\"GPU backend failed during generation and CPU fallback was declined.\");\n                }\n                allow_fallback = false;\n                if (logger) {\n                    logger->warn(\"LLM generation failed on GPU ({}); retrying on CPU.\", ex.what());\n                }\n                notify_status(Status::GpuFallbackToCpu);\n\n                llama_model_params cpu_params = llama_model_default_params();\n                cpu_params.n_gpu_layers = 0;\n                set_env_var(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n                set_env_var(\"LLAMA_ARG_DEVICE\", \"cpu\");\n                set_env_var(\"GGML_DISABLE_CUDA\", \"1\");\n\n                llama_model* old_model = model;\n                llama_model* cpu_model = llama_model_load_from_file(model_path.c_str(), cpu_params);\n                if (!cpu_model) {\n                    if (logger) {\n                        logger->error(\"Failed to reload model on CPU after GPU error\");\n                    }\n                } else {\n                    if (old_model) {\n                        llama_model_free(old_model);\n                    }\n                    model = cpu_model;\n                    vocab = llama_model_get_vocab(model);\n#ifdef GGML_USE_METAL\n                    ctx_params.offload_kqv = false;\n#endif\n                    continue;\n                }\n            }\n\n            if (logger) {\n                logger->error(\"LLM generation failed: {}\", ex.what());\n            }\n            throw;\n        }\n    }\n}\n\n\nstd::string LocalLLMClient::categorize_file(const std::string& file_name,\n                                            const std::string& file_path,\n                                            FileType file_type,\n                                            const std::string& consistency_context)\n{\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        if (!file_path.empty()) {\n            logger->debug(\"Requesting local categorization for '{}' ({}) at '{}'\",\n                          file_name, to_string(file_type), file_path);\n        } else {\n            logger->debug(\"Requesting local categorization for '{}' ({})\", file_name, to_string(file_type));\n        }\n    }\n    std::string prompt = make_prompt(file_name, file_path, file_type, consistency_context);\n    const std::string system_prompt = categorization_system_prompt();\n    if (prompt_logging_enabled) {\n        std::cout << \"\\n[DEV][PROMPT] Categorization request\\n\"\n                  << \"[system]\\n\" << system_prompt << \"\\n\"\n                  << \"[user]\\n\" << prompt << \"\\n\";\n    }\n    std::string response = generate_response(prompt, 64, true, system_prompt);\n    if (prompt_logging_enabled) {\n        std::cout << \"[DEV][RESPONSE] Categorization reply\\n\" << response << \"\\n\";\n    }\n    return response;\n}\n\n\nstd::string LocalLLMClient::complete_prompt(const std::string& prompt,\n                                            int max_tokens)\n{\n    const int capped = max_tokens > 0 ? max_tokens : 256;\n    return generate_response(prompt, capped, false);\n}\n\n\nstd::string LocalLLMClient::sanitize_output(const std::string& output) {\n    return sanitize_categorization_output(output);\n}\n\n\n\nLocalLLMClient::~LocalLLMClient() {\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->debug(\"Destroying LocalLLMClient for model '{}'\", model_path);\n    }\n    if (model) llama_model_free(model);\n}\n\nvoid LocalLLMClient::set_prompt_logging_enabled(bool enabled)\n{\n    prompt_logging_enabled = enabled;\n}\n\nvoid LocalLLMClient::set_status_callback(StatusCallback callback)\n{\n    status_callback_ = std::move(callback);\n}\n\nvoid LocalLLMClient::set_fallback_decision_callback(FallbackDecisionCallback callback)\n{\n    fallback_decision_callback_ = std::move(callback);\n}\n\nvoid LocalLLMClient::notify_status(Status status) const\n{\n    if (status_callback_) {\n        status_callback_(status);\n    }\n}\n"
  },
  {
    "path": "app/lib/Logger.cpp",
    "content": "#include \"constants.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n#include <cstdlib>\n#include <string>\n#include <filesystem>\n#include <chrono>\n\n\nstd::string Logger::get_log_directory()\n{\n#ifdef _WIN32\n    return get_windows_log_directory();\n#else\n    return get_xdg_cache_home();\n#endif\n}\n\n\nstd::string Logger::get_xdg_cache_home()\n{\n    const char* xdg_cache_home = std::getenv(\"XDG_CACHE_HOME\");\n    if (xdg_cache_home && *xdg_cache_home) {\n        return std::string(xdg_cache_home) + \"/\" + APP_NAME_DIR + \"/my_app/logs\";\n    }\n\n    const char* home = std::getenv(\"HOME\");\n    if (home && *home) {\n        return std::string(home) + \"/.cache/\" + APP_NAME_DIR + \"/logs\";\n    }\n    throw std::runtime_error(\"Failed to determine XDG_CACHE_HOME or HOME environment variable.\");\n}\n\n\nstd::string Logger::get_windows_log_directory() {\n    const char* appdata = std::getenv(\"APPDATA\");\n    if (appdata && *appdata) {\n        return std::string(appdata) + \"\\\\\" + APP_NAME_DIR + \"\\\\logs\";\n    }\n    throw std::runtime_error(\"Failed to determine APPDATA environment variable.\");\n}\n\n\nvoid Logger::setup_loggers()\n{\n    std::string log_dir = get_log_directory();\n    Utils::ensure_directory_exists(log_dir);\n\n    auto core_log_path = log_dir + \"/core.log\";\n    auto db_log_path = log_dir + \"/db.log\";\n    auto ui_log_path = log_dir + \"/ui.log\";\n    \n    auto core_console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();\n    auto core_file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(core_log_path, 1048576 * 5, 3);\n\n    auto db_console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();\n    auto db_file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(db_log_path, 1048576 * 5, 3);\n\n    auto ui_console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();\n    auto ui_file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(ui_log_path, 1048576 * 5, 3);\n\n    auto core_logger = std::make_shared<spdlog::logger>(\"core_logger\", spdlog::sinks_init_list{core_console_sink, core_file_sink});\n    auto db_logger = std::make_shared<spdlog::logger>(\"db_logger\", spdlog::sinks_init_list{db_console_sink, db_file_sink});\n    auto ui_logger = std::make_shared<spdlog::logger>(\"ui_logger\", spdlog::sinks_init_list{ui_console_sink, ui_file_sink});\n\n    spdlog::register_logger(core_logger);\n    spdlog::register_logger(db_logger);\n    spdlog::register_logger(ui_logger);\n\n    core_logger->set_level(spdlog::level::debug);\n    db_logger->set_level(spdlog::level::debug);\n    ui_logger->set_level(spdlog::level::debug);\n\n    core_logger->flush_on(spdlog::level::info);\n    db_logger->flush_on(spdlog::level::info);\n    ui_logger->flush_on(spdlog::level::info);\n\n    spdlog::flush_every(std::chrono::seconds(2));\n    spdlog::set_level(spdlog::level::debug);\n    spdlog::info(\"Loggers initialized.\");\n}\n\n\nstd::shared_ptr<spdlog::logger> Logger::get_logger(const std::string &name) {\n    return spdlog::get(name);\n}\n"
  },
  {
    "path": "app/lib/MainApp.cpp",
    "content": "#include \"MainApp.hpp\"\n#include \"AppInfo.hpp\"\n\n#include \"CategorizationSession.hpp\"\n#include \"DialogUtils.hpp\"\n#include \"ErrorMessages.hpp\"\n#include \"LLMClient.hpp\"\n#include \"GeminiClient.hpp\"\n#include \"LLMSelectionDialog.hpp\"\n#include \"Logger.hpp\"\n#include \"MainAppEditActions.hpp\"\n#include \"MainAppHelpActions.hpp\"\n#include \"Updater.hpp\"\n#include \"TranslationManager.hpp\"\n#include \"Utils.hpp\"\n#include \"Types.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"MainAppUiBuilder.hpp\"\n#include \"SuitabilityBenchmarkDialog.hpp\"\n#include \"UiTranslator.hpp\"\n#include \"UpdaterBuildConfig.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"ImageRenameMetadataService.hpp\"\n#include \"MediaRenameMetadataService.hpp\"\n#include \"SupportCodeManager.hpp\"\n#include \"WhitelistManagerDialog.hpp\"\n#include \"UndoManager.hpp\"\n#ifdef AI_FILE_SORTER_TEST_BUILD\n#include \"MainAppTestAccess.hpp\"\n#endif\n\n#include <QAction>\n#include <QActionGroup>\n#include <QApplication>\n#include <QBoxLayout>\n#include <QCheckBox>\n#include <QCloseEvent>\n#include <QDialogButtonBox>\n#include <QDockWidget>\n#include <QHBoxLayout>\n#include <QAbstractItemView>\n#include <QFileDialog>\n#include <QFileSystemModel>\n#include <QFile>\n#include <QHeaderView>\n#include <QInputDialog>\n#include <QKeySequence>\n#include <QByteArray>\n#include <QLabel>\n#include <QLineEdit>\n#include <QMenu>\n#include <QMenuBar>\n#include <QMessageBox>\n#include <QMetaObject>\n#include <QSignalBlocker>\n#include <QPushButton>\n#include <QRadioButton>\n#include <QComboBox>\n#include <QStandardItem>\n#include <QStandardItemModel>\n#include <QCoreApplication>\n#include <QStatusBar>\n#include <QToolButton>\n#include <QTreeView>\n#include <QVBoxLayout>\n#include <QSizePolicy>\n#include <QDialog>\n#include <QWidget>\n#include <QIcon>\n#include <QDir>\n#include <QStyle>\n#include <QEvent>\n#include <QStackedWidget>\n#include <QThread>\n#include <QTimer>\n#include <QtGlobal>\n\n#include <chrono>\n#include <filesystem>\n#include <algorithm>\n#include <cctype>\n#include <cstdlib>\n#include <exception>\n#include <optional>\n#include <functional>\n#include <memory>\n#include <sstream>\n#include <thread>\n#include <unordered_set>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n\n#include <fmt/format.h>\n#include <LocalLLMClient.hpp>\n\nusing namespace std::chrono_literals;\n\nnamespace {\n\nstd::string trim_ws_copy(const std::string& value) {\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    const auto start = value.find_first_not_of(whitespace);\n    if (start == std::string::npos) {\n        return std::string();\n    }\n    const auto end = value.find_last_not_of(whitespace);\n    return value.substr(start, end - start + 1);\n}\n\nstd::string expand_user_path(const std::string& value) {\n    if (value.empty() || value.front() != '~') {\n        return value;\n    }\n    QString home = QDir::homePath();\n    if (home.isEmpty()) {\n        return value;\n    }\n    if (value.size() == 1) {\n        return home.toUtf8().toStdString();\n    }\n    const char next = value[1];\n    if (next == '/' || next == '\\\\') {\n        QString expanded = home + QString::fromUtf8(value.c_str() + 1);\n        return expanded.toUtf8().toStdString();\n    }\n    return value;\n}\n\nstd::string normalize_directory_path(const std::string& value) {\n    const std::string trimmed = trim_ws_copy(value);\n    if (trimmed.empty()) {\n        return trimmed;\n    }\n    const std::string expanded = expand_user_path(trimmed);\n    const std::filesystem::path fs_path = Utils::utf8_to_path(expanded).lexically_normal();\n    std::string normalized = Utils::path_to_utf8(fs_path);\n    if (fs_path.has_relative_path()) {\n        while (normalized.size() > 1 &&\n               (normalized.back() == '/' || normalized.back() == '\\\\')) {\n            normalized.pop_back();\n        }\n    }\n    return normalized;\n}\n\nstd::string resolve_document_prompt_name(const std::string& original_name,\n                                         const std::string& suggested_name) {\n    return suggested_name.empty() ? original_name : suggested_name;\n}\n\nstd::string build_document_prompt_path(const std::string& full_path,\n                                       const std::string& prompt_name,\n                                       const std::string& summary) {\n    const auto entry_path = Utils::utf8_to_path(full_path);\n    const std::string effective_name =\n        prompt_name.empty() ? Utils::path_to_utf8(entry_path.filename()) : prompt_name;\n    std::string prompt_path = Utils::path_to_utf8(\n        entry_path.parent_path() / Utils::utf8_to_path(effective_name));\n    if (!summary.empty()) {\n        prompt_path += \"\\nDocument summary: \" + summary;\n    }\n    return prompt_path;\n}\n\nvoid schedule_next_support_prompt(Settings& settings, int total_files) {\n    settings.set_next_support_prompt_threshold(total_files + 50);\n    settings.save();\n}\n\nvoid maybe_show_support_prompt(Settings& settings,\n                               bool& prompt_active,\n                               std::function<MainApp::SupportPromptResult(int)> show_prompt) {\n    if (prompt_active) {\n        return;\n    }\n\n    if (SupportCodeManager(Utils::utf8_to_path(settings.get_config_dir())).is_prompt_permanently_disabled()) {\n        return;\n    }\n\n    const int total = settings.get_total_categorized_files();\n    int threshold = settings.get_next_support_prompt_threshold();\n    if (threshold <= 0) {\n        const int base = std::max(total, 0);\n        threshold = ((base / 50) + 1) * 50;\n        settings.set_next_support_prompt_threshold(threshold);\n        settings.save();\n    }\n\n    if (total < threshold || total == 0) {\n        return;\n    }\n\n    prompt_active = true;\n    MainApp::SupportPromptResult result = MainApp::SupportPromptResult::NotSure;\n    if (show_prompt) {\n        result = show_prompt(total);\n    }\n    prompt_active = false;\n\n    if (result == MainApp::SupportPromptResult::Support) {\n        return;\n    }\n\n    schedule_next_support_prompt(settings, total);\n}\n\nvoid record_categorized_metrics_impl(Settings& settings,\n                                     bool& prompt_active,\n                                     int count,\n                                     std::function<MainApp::SupportPromptResult(int)> show_prompt) {\n    if (count <= 0) {\n        return;\n    }\n\n    settings.add_categorized_files(count);\n    settings.save();\n    maybe_show_support_prompt(settings, prompt_active, std::move(show_prompt));\n}\n\nstd::string to_utf8(const QString& value)\n{\n    const QByteArray bytes = value.toUtf8();\n    return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));\n}\n\nstd::string to_lower_copy(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(),\n                   [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });\n    return value;\n}\n\nbool should_offer_visual_cpu_fallback(const std::string& reason) {\n    const std::string lowered = to_lower_copy(reason);\n    static const char* kRetryableMarkers[] = {\n        \"failed to create llama_context\",\n        \"mtmd_helper_eval_chunks failed\",\n        \"out of memory\",\n        \"not enough memory\",\n        \"gpu memory\",\n        \"vk_error_out_of_device_memory\",\n        \"vk_error_out_of_host_memory\",\n        \"cuda error out of memory\",\n        \"cuda_error_out_of_memory\"\n    };\n\n    for (const char* marker : kRetryableMarkers) {\n        if (lowered.find(marker) != std::string::npos) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstruct VisualLlmPaths {\n    std::filesystem::path model_path;\n    std::filesystem::path mmproj_path;\n};\n\nbool default_text_llm_files_available()\n{\n    static const char* kEnvVars[] = {\n        \"LOCAL_LLM_3B_DOWNLOAD_URL\",\n        \"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\",\n        \"LOCAL_LLM_7B_DOWNLOAD_URL\"\n    };\n\n    for (const char* env_key : kEnvVars) {\n        const char* env_url = std::getenv(env_key);\n        if (!env_url || *env_url == '\\0') {\n            continue;\n        }\n\n        try {\n            const std::filesystem::path path =\n                Utils::make_default_path_to_file_from_download_url(env_url);\n            std::error_code ec;\n            if (!path.empty() && std::filesystem::exists(path, ec)) {\n                return true;\n            }\n        } catch (...) {\n            continue;\n        }\n    }\n\n    return false;\n}\n\nstd::optional<std::filesystem::path> resolve_mmproj_path(const std::filesystem::path& primary) {\n    if (std::filesystem::exists(primary)) {\n        return primary;\n    }\n\n    const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination());\n    static const char* kAltMmprojNames[] = {\n        \"mmproj-model-f16.gguf\",\n        \"llava-v1.6-mistral-7b-mmproj-f16.gguf\"\n    };\n    for (const char* alt_name : kAltMmprojNames) {\n        const auto candidate = llm_dir / alt_name;\n        if (std::filesystem::exists(candidate)) {\n            return candidate;\n        }\n    }\n\n    return std::nullopt;\n}\n\nstd::optional<VisualLlmPaths> resolve_visual_llm_paths(std::string* error) {\n    const char* model_url = std::getenv(\"LLAVA_MODEL_URL\");\n    const char* mmproj_url = std::getenv(\"LLAVA_MMPROJ_URL\");\n    if (!model_url || !*model_url || !mmproj_url || !*mmproj_url) {\n        if (error) {\n            *error = \"Missing visual LLM download URLs. Check LLAVA_MODEL_URL and LLAVA_MMPROJ_URL.\";\n        }\n        return std::nullopt;\n    }\n\n    const auto model_path = std::filesystem::path(\n        Utils::make_default_path_to_file_from_download_url(model_url));\n    if (!std::filesystem::exists(model_path)) {\n        if (error) {\n            *error = \"Visual LLM model file is missing: \" + model_path.string();\n        }\n        return std::nullopt;\n    }\n\n    const auto mmproj_primary = std::filesystem::path(\n        Utils::make_default_path_to_file_from_download_url(mmproj_url));\n    const auto mmproj_path = resolve_mmproj_path(mmproj_primary);\n    if (!mmproj_path) {\n        if (error) {\n            *error = \"Visual LLM mmproj file is missing: \" + mmproj_primary.string();\n        }\n        return std::nullopt;\n    }\n\n    return VisualLlmPaths{model_path, *mmproj_path};\n}\n\nbool should_use_visual_gpu() {\n    const char* backend = std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\");\n    if (!backend || !*backend) {\n        return true;\n    }\n    std::string value = backend;\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value != \"cpu\";\n}\n\nstd::optional<bool> read_env_bool(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value || value[0] == '\\0') {\n        return std::nullopt;\n    }\n    std::string lowered = value;\n    std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    if (lowered == \"1\" || lowered == \"true\" || lowered == \"yes\" || lowered == \"on\") {\n        return true;\n    }\n    if (lowered == \"0\" || lowered == \"false\" || lowered == \"no\" || lowered == \"off\") {\n        return false;\n    }\n    return std::nullopt;\n}\n\nstd::optional<int> read_env_int(const char* key) {\n    const char* value = std::getenv(key);\n    if (!value || value[0] == '\\0') {\n        return std::nullopt;\n    }\n    char* end_ptr = nullptr;\n    long parsed = std::strtol(value, &end_ptr, 10);\n    if (end_ptr == value || (end_ptr && *end_ptr != '\\0')) {\n        return std::nullopt;\n    }\n    if (parsed <= 0 || parsed > 100000) {\n        return std::nullopt;\n    }\n    return static_cast<int>(parsed);\n}\n\nint resolve_local_context_tokens() {\n    if (auto parsed = read_env_int(\"AI_FILE_SORTER_CTX_TOKENS\")) {\n        return *parsed;\n    }\n    if (auto parsed = read_env_int(\"LLAMA_CPP_MAX_CONTEXT\")) {\n        return *parsed;\n    }\n    return 2048;\n}\n\nsize_t resolve_document_char_budget(bool using_local_llm, int max_output_tokens) {\n    int context_tokens = using_local_llm ? resolve_local_context_tokens() : 4096;\n    context_tokens = std::clamp(context_tokens, 512, 8192);\n    const int reserve_tokens = std::max(192, context_tokens / 6);\n    const int output_tokens = std::clamp(max_output_tokens, 0, context_tokens / 2);\n    const int prompt_tokens = std::max(256, context_tokens - reserve_tokens - output_tokens);\n    const size_t chars_per_token = using_local_llm ? 2 : 4;\n    return static_cast<size_t>(prompt_tokens) * chars_per_token;\n}\n\nvoid split_entries_for_analysis(const std::vector<FileEntry>& files,\n                                bool analyze_images,\n                                bool analyze_documents,\n                                bool process_images_only,\n                                bool process_documents_only,\n                                bool rename_images_only,\n                                bool rename_documents_only,\n                                bool categorize_files,\n                                bool use_full_path_keys,\n                                const std::unordered_set<std::string>& renamed_files,\n                                std::vector<FileEntry>& image_entries,\n                                std::vector<FileEntry>& document_entries,\n                                std::vector<FileEntry>& other_entries) {\n    image_entries.clear();\n    document_entries.clear();\n    other_entries.clear();\n    image_entries.reserve(files.size());\n    document_entries.reserve(files.size());\n    other_entries.reserve(files.size());\n\n    const bool restrict_types = process_images_only || process_documents_only;\n    const bool allow_images = !restrict_types || process_images_only;\n    const bool allow_documents = !restrict_types || process_documents_only;\n    const bool allow_other_files = categorize_files && !restrict_types;\n\n    for (const auto& entry : files) {\n        const std::string entry_key = use_full_path_keys ? entry.full_path : entry.file_name;\n        if (entry.type == FileType::Directory) {\n            if (!restrict_types) {\n                other_entries.push_back(entry);\n            }\n            continue;\n        }\n        const bool is_image_entry = entry.type == FileType::File &&\n                                    LlavaImageAnalyzer::is_supported_image(entry.full_path);\n        const bool is_document_entry = entry.type == FileType::File &&\n                                       DocumentTextAnalyzer::is_supported_document(entry.full_path);\n\n        if (is_image_entry) {\n            if (!allow_images) {\n                continue;\n            }\n            if (analyze_images) {\n                const bool already_renamed = renamed_files.contains(entry_key);\n                if (already_renamed) {\n                    if (rename_images_only) {\n                        continue;\n                    }\n                    // Already-renamed images skip vision analysis and use filename/path categorization.\n                    other_entries.push_back(entry);\n                } else {\n                    image_entries.push_back(entry);\n                }\n            } else if (allow_other_files) {\n                other_entries.push_back(entry);\n            }\n            continue;\n        }\n\n        if (is_document_entry) {\n            if (!allow_documents) {\n                continue;\n            }\n            if (analyze_documents) {\n                const bool already_renamed = renamed_files.contains(entry_key);\n                if (already_renamed) {\n                    if (rename_documents_only) {\n                        continue;\n                    }\n                    // Already-renamed documents skip content analysis and use filename/path categorization.\n                    other_entries.push_back(entry);\n                } else {\n                    document_entries.push_back(entry);\n                }\n            } else if (allow_other_files) {\n                other_entries.push_back(entry);\n            }\n            continue;\n        }\n\n        if (allow_other_files) {\n            other_entries.push_back(entry);\n        }\n    }\n}\n\nvoid sync_disclosure_button(QToolButton* button, bool expanded)\n{\n    if (!button) {\n        return;\n    }\n    Q_UNUSED(expanded);\n    button->update();\n}\n\n} // namespace\n\nMainApp::MainApp(Settings& settings, bool development_mode, QWidget* parent)\n    : QMainWindow(parent),\n      settings(settings),\n      db_manager(settings.get_config_dir()),\n      core_logger(Logger::get_logger(\"core_logger\")),\n      ui_logger(Logger::get_logger(\"ui_logger\")),\n      whitelist_store(settings.get_config_dir()),\n      categorization_service(settings, db_manager, core_logger),\n      consistency_pass_service(db_manager, core_logger),\n      results_coordinator(dirscanner),\n      undo_manager_(settings.get_config_dir() + \"/undo\"),\n      development_mode_(development_mode),\n      development_prompt_logging_enabled_(development_mode ? settings.get_development_prompt_logging() : false)\n{\n    TranslationManager::instance().initialize_for_app(qApp, settings.get_language());\n    initialize_whitelists();\n\n    using_local_llm = !is_remote_choice(settings.get_llm_choice());\n\n    MainAppUiBuilder ui_builder;\n    ui_builder.build(*this);\n    ui_translator_ = std::make_unique<UiTranslator>(ui_builder.build_translator_dependencies(*this));\n    retranslate_ui();\n    setup_file_explorer();\n    connect_signals();\n    connect_edit_actions();\n#if !defined(AI_FILE_SORTER_TEST_BUILD)\n    start_updater();\n#endif\n    load_settings();\n    set_app_icon();\n}\n\n\nMainApp::~MainApp() = default;\n\n\nvoid MainApp::run()\n{\n    show();\n#if !defined(AI_FILE_SORTER_TEST_BUILD)\n    maybe_show_suitability_benchmark();\n#endif\n}\n\n\nvoid MainApp::shutdown()\n{\n    stop_running_analysis();\n    save_settings();\n}\n\n\nvoid MainApp::setup_file_explorer()\n{\n    create_file_explorer_dock();\n    setup_file_system_model();\n    setup_file_explorer_view();\n    connect_file_explorer_signals();\n    apply_file_explorer_preferences();\n}\n\nvoid MainApp::create_file_explorer_dock()\n{\n    file_explorer_dock = new QDockWidget(tr(\"File Explorer\"), this);\n    file_explorer_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);\n    addDockWidget(Qt::LeftDockWidgetArea, file_explorer_dock);\n}\n\nvoid MainApp::setup_file_system_model()\n{\n    if (!file_explorer_dock) {\n        return;\n    }\n\n    file_system_model = new QFileSystemModel(file_explorer_dock);\n    file_system_model->setRootPath(QDir::rootPath());\n    file_system_model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Drives | QDir::AllDirs);\n}\n\nvoid MainApp::setup_file_explorer_view()\n{\n    if (!file_explorer_dock || !file_system_model) {\n        return;\n    }\n\n    file_explorer_view = new QTreeView(file_explorer_dock);\n    file_explorer_view->setModel(file_system_model);\n    const QString root_path = file_system_model->rootPath();\n    file_explorer_view->setRootIndex(file_system_model->index(root_path));\n\n    const QModelIndex home_index = file_system_model->index(QDir::homePath());\n    if (home_index.isValid()) {\n        file_explorer_view->setCurrentIndex(home_index);\n        file_explorer_view->scrollTo(home_index);\n    }\n\n    file_explorer_view->setHeaderHidden(false);\n    file_explorer_view->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    file_explorer_view->header()->setSectionResizeMode(QHeaderView::ResizeToContents);\n    file_explorer_view->setColumnHidden(1, true);\n    file_explorer_view->setColumnHidden(2, true);\n    file_explorer_view->setColumnHidden(3, true);\n    file_explorer_view->setExpandsOnDoubleClick(true);\n\n    file_explorer_dock->setWidget(file_explorer_view);\n}\n\nvoid MainApp::connect_file_explorer_signals()\n{\n    if (!file_explorer_view || !file_explorer_view->selectionModel()) {\n        return;\n    }\n\n    connect(file_explorer_view->selectionModel(), &QItemSelectionModel::currentChanged,\n            this, [this](const QModelIndex& current, const QModelIndex&) {\n                if (!file_system_model || suppress_explorer_sync_) {\n                    return;\n                }\n                if (!current.isValid() || !file_system_model->isDir(current)) {\n                    return;\n                }\n                const QString path = file_system_model->filePath(current);\n                if (path_entry && path_entry->text() == path) {\n                    update_folder_contents(path);\n                } else {\n                    on_directory_selected(path, true);\n                }\n            });\n\n    if (file_explorer_dock) {\n        connect(file_explorer_dock, &QDockWidget::visibilityChanged, this, [this](bool) {\n            update_results_view_mode();\n        });\n    }\n}\n\nvoid MainApp::apply_file_explorer_preferences()\n{\n    if (!file_explorer_dock) {\n        return;\n    }\n\n    const bool show_explorer = settings.get_show_file_explorer();\n    if (file_explorer_menu_action) {\n        file_explorer_menu_action->setChecked(show_explorer);\n    }\n    if (consistency_pass_action) {\n        consistency_pass_action->setChecked(settings.get_consistency_pass_enabled());\n    }\n\n    file_explorer_dock->setVisible(show_explorer);\n    update_results_view_mode();\n}\n\n\nvoid MainApp::connect_signals()\n{\n    connect(analyze_button, &QPushButton::clicked, this, &MainApp::on_analyze_clicked);\n    connect(browse_button, &QPushButton::clicked, this, [this]() {\n        const QString directory = QFileDialog::getExistingDirectory(this, tr(\"Select Directory\"), path_entry->text());\n        if (!directory.isEmpty()) {\n            on_directory_selected(directory);\n        }\n    });\n\n    connect(path_entry, &QLineEdit::returnPressed, this, [this]() {\n        const QString folder = path_entry->text();\n        if (QDir(folder).exists()) {\n            on_directory_selected(folder);\n        } else {\n            show_error_dialog(ERR_INVALID_PATH);\n        }\n    });\n\n    connect_folder_contents_signals();\n    connect_checkbox_signals();\n    connect_whitelist_signals();\n}\n\nvoid MainApp::connect_folder_contents_signals()\n{\n    if (!folder_contents_view || !folder_contents_model || !folder_contents_view->selectionModel()) {\n        return;\n    }\n    folder_contents_view->setExpandsOnDoubleClick(true);\n\n    connect(folder_contents_view->selectionModel(), &QItemSelectionModel::currentChanged,\n            this, [this](const QModelIndex& current, const QModelIndex&) {\n                if (suppress_folder_view_sync_) {\n                    return;\n                }\n                if (!folder_contents_model || !current.isValid()) {\n                    return;\n                }\n                if (!folder_contents_model->isDir(current)) {\n                    return;\n                }\n                on_directory_selected(folder_contents_model->filePath(current), true);\n            });\n\n    connect(folder_contents_model, &QFileSystemModel::directoryLoaded,\n            this, [this](const QString& path) {\n                if (!folder_contents_view || !folder_contents_model) {\n                    return;\n                }\n                if (folder_contents_model->rootPath() == path) {\n                    folder_contents_view->resizeColumnToContents(0);\n                }\n            });\n}\n\nvoid MainApp::connect_checkbox_signals()\n{\n    connect(use_subcategories_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n        settings.set_use_subcategories(checked);\n        if (categorization_dialog) {\n            categorization_dialog->set_show_subcategory_column(checked);\n        }\n    });\n\n    if (categorization_style_refined_radio) {\n        connect(categorization_style_refined_radio, &QRadioButton::toggled, this, [this](bool checked) {\n            if (checked) {\n                set_categorization_style(false);\n                settings.set_use_consistency_hints(false);\n            } else if (categorization_style_consistent_radio &&\n                       !categorization_style_consistent_radio->isChecked()) {\n                set_categorization_style(true);\n                settings.set_use_consistency_hints(true);\n            }\n        });\n    }\n\n    if (categorization_style_consistent_radio) {\n        connect(categorization_style_consistent_radio, &QRadioButton::toggled, this, [this](bool checked) {\n            if (checked) {\n                set_categorization_style(true);\n                settings.set_use_consistency_hints(true);\n            } else if (categorization_style_refined_radio &&\n                       !categorization_style_refined_radio->isChecked()) {\n                set_categorization_style(false);\n                settings.set_use_consistency_hints(false);\n            }\n        });\n    }\n\n    connect(categorize_files_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n        ensure_one_checkbox_active(categorize_files_checkbox);\n        update_file_scan_option(FileScanOptions::Files, checked);\n        settings.set_categorize_files(checked);\n    });\n\n    connect(categorize_directories_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n        ensure_one_checkbox_active(categorize_directories_checkbox);\n        update_file_scan_option(FileScanOptions::Directories, checked);\n        settings.set_categorize_directories(checked);\n    });\n\n    if (include_subdirectories_checkbox) {\n        connect(include_subdirectories_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_include_subdirectories(checked);\n            if (checked && categorize_directories_checkbox && categorize_directories_checkbox->isChecked()) {\n                QSignalBlocker blocker(categorize_directories_checkbox);\n                categorize_directories_checkbox->setChecked(false);\n                update_file_scan_option(FileScanOptions::Directories, false);\n                settings.set_categorize_directories(false);\n            }\n            update_image_only_controls();\n        });\n    }\n\n    if (analyze_images_checkbox) {\n        connect(analyze_images_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            handle_image_analysis_toggle(checked);\n        });\n    }\n\n    if (process_images_only_checkbox) {\n        connect(process_images_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_process_images_only(checked);\n            update_image_only_controls();\n        });\n    }\n\n    if (add_image_date_to_category_checkbox) {\n        connect(add_image_date_to_category_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_add_image_date_to_category(checked);\n        });\n    }\n\n    if (add_image_date_place_to_filename_checkbox) {\n        connect(add_image_date_place_to_filename_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_add_image_date_place_to_filename(checked);\n        });\n    }\n\n    if (add_audio_video_metadata_to_filename_checkbox) {\n        connect(add_audio_video_metadata_to_filename_checkbox,\n                &QCheckBox::toggled,\n                this,\n                [this](bool checked) { settings.set_add_audio_video_metadata_to_filename(checked); });\n    }\n\n    if (offer_rename_images_checkbox) {\n        connect(offer_rename_images_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (!checked && rename_images_only_checkbox && rename_images_only_checkbox->isChecked()) {\n                QSignalBlocker blocker(rename_images_only_checkbox);\n                rename_images_only_checkbox->setChecked(false);\n            }\n            settings.set_offer_rename_images(checked);\n            if (add_image_date_place_to_filename_checkbox) {\n                settings.set_add_image_date_place_to_filename(\n                    add_image_date_place_to_filename_checkbox->isChecked());\n            }\n            if (rename_images_only_checkbox) {\n                settings.set_rename_images_only(rename_images_only_checkbox->isChecked());\n            }\n            update_image_analysis_controls();\n        });\n    }\n\n    if (rename_images_only_checkbox) {\n        connect(rename_images_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (checked && offer_rename_images_checkbox && !offer_rename_images_checkbox->isChecked()) {\n                QSignalBlocker blocker(offer_rename_images_checkbox);\n                offer_rename_images_checkbox->setChecked(true);\n            }\n            settings.set_rename_images_only(checked);\n            if (offer_rename_images_checkbox) {\n                settings.set_offer_rename_images(offer_rename_images_checkbox->isChecked());\n            }\n            update_image_analysis_controls();\n        });\n    }\n\n    if (image_options_toggle_button) {\n        connect(image_options_toggle_button, &QToolButton::toggled, this, [this](bool) {\n            settings.set_image_options_expanded(image_options_toggle_button->isChecked());\n            update_image_analysis_controls();\n        });\n    }\n\n    if (analyze_documents_checkbox) {\n        connect(analyze_documents_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_analyze_documents_by_content(checked);\n            update_document_analysis_controls();\n        });\n    }\n\n    if (process_documents_only_checkbox) {\n        connect(process_documents_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_process_documents_only(checked);\n            update_document_analysis_controls();\n        });\n    }\n\n    if (offer_rename_documents_checkbox) {\n        connect(offer_rename_documents_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (!checked && rename_documents_only_checkbox && rename_documents_only_checkbox->isChecked()) {\n                QSignalBlocker blocker(rename_documents_only_checkbox);\n                rename_documents_only_checkbox->setChecked(false);\n            }\n            settings.set_offer_rename_documents(checked);\n            if (rename_documents_only_checkbox) {\n                settings.set_rename_documents_only(rename_documents_only_checkbox->isChecked());\n            }\n            update_document_analysis_controls();\n        });\n    }\n\n    if (rename_documents_only_checkbox) {\n        connect(rename_documents_only_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            if (checked && offer_rename_documents_checkbox && !offer_rename_documents_checkbox->isChecked()) {\n                QSignalBlocker blocker(offer_rename_documents_checkbox);\n                offer_rename_documents_checkbox->setChecked(true);\n            }\n            settings.set_rename_documents_only(checked);\n            if (offer_rename_documents_checkbox) {\n                settings.set_offer_rename_documents(offer_rename_documents_checkbox->isChecked());\n            }\n            update_document_analysis_controls();\n        });\n    }\n\n    if (add_document_date_to_category_checkbox) {\n        connect(add_document_date_to_category_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n            settings.set_add_document_date_to_category(checked);\n        });\n    }\n\n    if (document_options_toggle_button) {\n        connect(document_options_toggle_button, &QToolButton::toggled, this, [this](bool) {\n            settings.set_document_options_expanded(document_options_toggle_button->isChecked());\n            update_document_analysis_controls();\n        });\n    }\n}\n\nvoid MainApp::connect_whitelist_signals()\n{\n    connect(use_whitelist_checkbox, &QCheckBox::toggled, this, [this](bool checked) {\n        if (whitelist_selector) {\n            whitelist_selector->setEnabled(checked);\n        }\n        settings.set_use_whitelist(checked);\n        apply_whitelist_to_selector();\n    });\n\n    connect(whitelist_selector, &QComboBox::currentTextChanged, this, [this](const QString& name) {\n        settings.set_active_whitelist(name.toStdString());\n        if (auto entry = whitelist_store.get(name.toStdString())) {\n            settings.set_allowed_categories(entry->categories);\n            settings.set_allowed_subcategories(entry->subcategories);\n        }\n    });\n}\n\n\nvoid MainApp::connect_edit_actions()\n{\n    path_entry->setContextMenuPolicy(Qt::DefaultContextMenu);\n}\n\n\nvoid MainApp::start_updater()\n{\n    if (!UpdaterBuildConfig::update_checks_enabled()) {\n        return;\n    }\n    auto* updater = new Updater(settings);\n    updater->begin();\n}\n\n\nvoid MainApp::set_app_icon()\n{\n    const QString icon_path = QStringLiteral(\":/net/quicknode/AIFileSorter/images/app_icon_128.png\");\n    QIcon icon(icon_path);\n    if (icon.isNull()) {\n        icon = QIcon(QStringLiteral(\":/net/quicknode/AIFileSorter/images/logo.png\"));\n    }\n    if (!icon.isNull()) {\n        QApplication::setWindowIcon(icon);\n        setWindowIcon(icon);\n    }\n}\n\n\nvoid MainApp::load_settings()\n{\n    if (!settings.load()) {\n        core_logger->info(\"Failed to load settings, using defaults.\");\n    }\n    if (development_mode_) {\n        development_prompt_logging_enabled_ = settings.get_development_prompt_logging();\n    } else {\n        development_prompt_logging_enabled_ = false;\n    }\n    apply_development_logging();\n    TranslationManager::instance().set_language(settings.get_language());\n    sync_settings_to_ui();\n    retranslate_ui();\n}\n\n\nvoid MainApp::save_settings()\n{\n    sync_ui_to_settings();\n    settings.save();\n}\n\n\nvoid MainApp::sync_settings_to_ui()\n{\n    restore_tree_settings();\n    restore_sort_folder_state();\n    restore_file_scan_options();\n    restore_file_explorer_visibility();\n    restore_development_preferences();\n\n    if (ui_translator_) {\n        ui_translator_->update_language_checks();\n    }\n}\n\nvoid MainApp::restore_tree_settings()\n{\n    use_subcategories_checkbox->setChecked(settings.get_use_subcategories());\n    set_categorization_style(settings.get_use_consistency_hints());\n    if (use_whitelist_checkbox) {\n        use_whitelist_checkbox->setChecked(settings.get_use_whitelist());\n    }\n    if (whitelist_selector) {\n        apply_whitelist_to_selector();\n    }\n    categorize_files_checkbox->setChecked(settings.get_categorize_files());\n    categorize_directories_checkbox->setChecked(settings.get_categorize_directories());\n    if (include_subdirectories_checkbox) {\n        include_subdirectories_checkbox->setChecked(settings.get_include_subdirectories());\n    }\n    if (analyze_images_checkbox) {\n        QSignalBlocker blocker(analyze_images_checkbox);\n        analyze_images_checkbox->setChecked(settings.get_analyze_images_by_content());\n    }\n    if (process_images_only_checkbox) {\n        QSignalBlocker blocker(process_images_only_checkbox);\n        process_images_only_checkbox->setChecked(settings.get_process_images_only());\n    }\n    if (add_image_date_place_to_filename_checkbox) {\n        QSignalBlocker blocker(add_image_date_place_to_filename_checkbox);\n        add_image_date_place_to_filename_checkbox->setChecked(\n            settings.get_add_image_date_place_to_filename());\n    }\n    if (add_audio_video_metadata_to_filename_checkbox) {\n        QSignalBlocker blocker(add_audio_video_metadata_to_filename_checkbox);\n        add_audio_video_metadata_to_filename_checkbox->setChecked(\n            settings.get_add_audio_video_metadata_to_filename());\n    }\n    if (add_image_date_to_category_checkbox) {\n        QSignalBlocker blocker(add_image_date_to_category_checkbox);\n        add_image_date_to_category_checkbox->setChecked(\n            settings.get_add_image_date_to_category());\n    }\n    if (offer_rename_images_checkbox) {\n        QSignalBlocker blocker(offer_rename_images_checkbox);\n        offer_rename_images_checkbox->setChecked(settings.get_offer_rename_images());\n    }\n    if (rename_images_only_checkbox) {\n        QSignalBlocker blocker(rename_images_only_checkbox);\n        rename_images_only_checkbox->setChecked(settings.get_rename_images_only());\n    }\n    if (image_options_toggle_button) {\n        const bool expand_images = settings.get_image_options_expanded();\n        QSignalBlocker blocker(image_options_toggle_button);\n        image_options_toggle_button->setChecked(expand_images);\n    }\n    if (analyze_documents_checkbox) {\n        QSignalBlocker blocker(analyze_documents_checkbox);\n        analyze_documents_checkbox->setChecked(settings.get_analyze_documents_by_content());\n    }\n    if (process_documents_only_checkbox) {\n        QSignalBlocker blocker(process_documents_only_checkbox);\n        process_documents_only_checkbox->setChecked(settings.get_process_documents_only());\n    }\n    if (offer_rename_documents_checkbox) {\n        QSignalBlocker blocker(offer_rename_documents_checkbox);\n        offer_rename_documents_checkbox->setChecked(settings.get_offer_rename_documents());\n    }\n    if (rename_documents_only_checkbox) {\n        QSignalBlocker blocker(rename_documents_only_checkbox);\n        rename_documents_only_checkbox->setChecked(settings.get_rename_documents_only());\n    }\n    if (add_document_date_to_category_checkbox) {\n        QSignalBlocker blocker(add_document_date_to_category_checkbox);\n        add_document_date_to_category_checkbox->setChecked(settings.get_add_document_date_to_category());\n    }\n    if (document_options_toggle_button) {\n        const bool expand_documents = settings.get_document_options_expanded();\n        QSignalBlocker blocker(document_options_toggle_button);\n        document_options_toggle_button->setChecked(expand_documents);\n    }\n    update_image_analysis_controls();\n    update_document_analysis_controls();\n}\n\nvoid MainApp::restore_sort_folder_state()\n{\n    const QString stored_folder = QString::fromStdString(settings.get_sort_folder());\n    QString effective_folder = stored_folder;\n\n    if (effective_folder.isEmpty() || !QDir(effective_folder).exists()) {\n        effective_folder = QDir::homePath();\n    }\n\n    path_entry->setText(effective_folder);\n\n    if (!effective_folder.isEmpty() && QDir(effective_folder).exists()) {\n        statusBar()->showMessage(tr(\"Loaded folder %1\").arg(effective_folder), 3000);\n        status_is_ready_ = false;\n        update_folder_contents(effective_folder);\n        focus_file_explorer_on_path(effective_folder);\n    } else if (!stored_folder.isEmpty()) {\n        core_logger->warn(\"Sort folder path is invalid: {}\", stored_folder.toStdString());\n    }\n}\n\nvoid MainApp::restore_file_scan_options()\n{\n    file_scan_options = FileScanOptions::None;\n    if (settings.get_categorize_files()) {\n        file_scan_options = file_scan_options | FileScanOptions::Files;\n    }\n    if (settings.get_categorize_directories()) {\n        file_scan_options = file_scan_options | FileScanOptions::Directories;\n    }\n}\n\nvoid MainApp::restore_file_explorer_visibility()\n{\n    const bool show_explorer = settings.get_show_file_explorer();\n    if (file_explorer_dock) {\n        file_explorer_dock->setVisible(show_explorer);\n    }\n    if (file_explorer_menu_action) {\n        file_explorer_menu_action->setChecked(show_explorer);\n    }\n    update_results_view_mode();\n}\n\nvoid MainApp::restore_development_preferences()\n{\n    if (!development_mode_ || !development_prompt_logging_action) {\n        return;\n    }\n\n    QSignalBlocker blocker(development_prompt_logging_action);\n    development_prompt_logging_action->setChecked(development_prompt_logging_enabled_);\n}\n\n\nvoid MainApp::sync_ui_to_settings()\n{\n    settings.set_use_subcategories(use_subcategories_checkbox->isChecked());\n    if (categorization_style_consistent_radio) {\n        settings.set_use_consistency_hints(categorization_style_consistent_radio->isChecked());\n    }\n    if (use_whitelist_checkbox) {\n        settings.set_use_whitelist(use_whitelist_checkbox->isChecked());\n    }\n    if (whitelist_selector) {\n        settings.set_active_whitelist(whitelist_selector->currentText().toStdString());\n    }\n    settings.set_categorize_files(categorize_files_checkbox->isChecked());\n    settings.set_categorize_directories(categorize_directories_checkbox->isChecked());\n    if (include_subdirectories_checkbox) {\n        settings.set_include_subdirectories(include_subdirectories_checkbox->isChecked());\n    }\n    if (analyze_images_checkbox) {\n        settings.set_analyze_images_by_content(analyze_images_checkbox->isChecked());\n    }\n    if (process_images_only_checkbox) {\n        settings.set_process_images_only(process_images_only_checkbox->isChecked());\n    }\n    if (add_image_date_place_to_filename_checkbox) {\n        settings.set_add_image_date_place_to_filename(\n            add_image_date_place_to_filename_checkbox->isChecked());\n    }\n    if (add_audio_video_metadata_to_filename_checkbox) {\n        settings.set_add_audio_video_metadata_to_filename(\n            add_audio_video_metadata_to_filename_checkbox->isChecked());\n    }\n    if (add_image_date_to_category_checkbox) {\n        settings.set_add_image_date_to_category(\n            add_image_date_to_category_checkbox->isChecked());\n    }\n    if (offer_rename_images_checkbox) {\n        settings.set_offer_rename_images(offer_rename_images_checkbox->isChecked());\n    }\n    if (rename_images_only_checkbox) {\n        settings.set_rename_images_only(rename_images_only_checkbox->isChecked());\n    }\n    if (analyze_documents_checkbox) {\n        settings.set_analyze_documents_by_content(analyze_documents_checkbox->isChecked());\n    }\n    if (process_documents_only_checkbox) {\n        settings.set_process_documents_only(process_documents_only_checkbox->isChecked());\n    }\n    if (offer_rename_documents_checkbox) {\n        settings.set_offer_rename_documents(offer_rename_documents_checkbox->isChecked());\n    }\n    if (rename_documents_only_checkbox) {\n        settings.set_rename_documents_only(rename_documents_only_checkbox->isChecked());\n    }\n    if (add_document_date_to_category_checkbox) {\n        settings.set_add_document_date_to_category(add_document_date_to_category_checkbox->isChecked());\n    }\n    const QByteArray folder_bytes = path_entry->text().toUtf8();\n    settings.set_sort_folder(std::string(folder_bytes.constData(), static_cast<std::size_t>(folder_bytes.size())));\n    if (file_explorer_menu_action) {\n        settings.set_show_file_explorer(file_explorer_menu_action->isChecked());\n    }\n    if (consistency_pass_action) {\n        settings.set_consistency_pass_enabled(consistency_pass_action->isChecked());\n    }\n    if (development_mode_ && development_prompt_logging_action) {\n        const bool checked = development_prompt_logging_action->isChecked();\n        development_prompt_logging_enabled_ = checked;\n        settings.set_development_prompt_logging(checked);\n        apply_development_logging();\n    }\n    if (language_group) {\n        if (QAction* checked = language_group->checkedAction()) {\n            settings.set_language(static_cast<Language>(checked->data().toInt()));\n        }\n    }\n}\n\nvoid MainApp::retranslate_ui()\n{\n    if (!ui_translator_) {\n        return;\n    }\n\n    UiTranslator::State state{\n        .analysis_in_progress = analysis_in_progress_,\n        .stop_analysis_requested = stop_analysis.load(),\n        .status_is_ready = status_is_ready_\n    };\n    ui_translator_->retranslate_all(state);\n}\n\n#if defined(AI_FILE_SORTER_TEST_BUILD)\n\nQString MainAppTestAccess::analyze_button_text(const MainApp& app) {\n    return app.analyze_button ? app.analyze_button->text() : QString();\n}\n\nQString MainAppTestAccess::path_label_text(const MainApp& app) {\n    return app.path_label ? app.path_label->text() : QString();\n}\n\nQCheckBox* MainAppTestAccess::categorize_files_checkbox(MainApp& app) {\n    return app.categorize_files_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::analyze_images_checkbox(MainApp& app) {\n    return app.analyze_images_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::process_images_only_checkbox(MainApp& app) {\n    return app.process_images_only_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::add_image_date_to_category_checkbox(MainApp& app) {\n    return app.add_image_date_to_category_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::add_image_date_place_to_filename_checkbox(MainApp& app) {\n    return app.add_image_date_place_to_filename_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(MainApp& app) {\n    return app.add_audio_video_metadata_to_filename_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::offer_rename_images_checkbox(MainApp& app) {\n    return app.offer_rename_images_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::rename_images_only_checkbox(MainApp& app) {\n    return app.rename_images_only_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::analyze_documents_checkbox(MainApp& app) {\n    return app.analyze_documents_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::process_documents_only_checkbox(MainApp& app) {\n    return app.process_documents_only_checkbox;\n}\n\nQCheckBox* MainAppTestAccess::rename_documents_only_checkbox(MainApp& app) {\n    return app.rename_documents_only_checkbox;\n}\n\nQToolButton* MainAppTestAccess::image_options_toggle_button(MainApp& app) {\n    return app.image_options_toggle_button;\n}\n\nQToolButton* MainAppTestAccess::document_options_toggle_button(MainApp& app) {\n    return app.document_options_toggle_button;\n}\n\nvoid MainAppTestAccess::split_entries_for_analysis(const std::vector<FileEntry>& files,\n                                                   bool analyze_images,\n                                                   bool analyze_documents,\n                                                   bool process_images_only,\n                                                   bool process_documents_only,\n                                                   bool rename_images_only,\n                                                   bool rename_documents_only,\n                                                   bool categorize_files,\n                                                   bool use_full_path_keys,\n                                                   const std::unordered_set<std::string>& renamed_files,\n                                                   std::vector<FileEntry>& image_entries,\n                                                   std::vector<FileEntry>& document_entries,\n                                                   std::vector<FileEntry>& other_entries) {\n    ::split_entries_for_analysis(files,\n                                 analyze_images,\n                                 analyze_documents,\n                                 process_images_only,\n                                 process_documents_only,\n                                 rename_images_only,\n                                 rename_documents_only,\n                                 categorize_files,\n                                 use_full_path_keys,\n                                 renamed_files,\n                                 image_entries,\n                                 document_entries,\n                                 other_entries);\n}\n\nvoid MainAppTestAccess::set_visual_llm_available_probe(MainApp& app, std::function<bool()> probe) {\n    app.visual_llm_available_probe_ = std::move(probe);\n}\n\nvoid MainAppTestAccess::set_llm_selection_runner(MainApp& app, std::function<void()> runner) {\n    app.llm_selection_runner_override_ = std::move(runner);\n}\n\nvoid MainAppTestAccess::set_image_analysis_prompt_override(MainApp& app, std::function<bool()> prompt) {\n    app.image_analysis_prompt_override_ = std::move(prompt);\n}\n\nbool MainAppTestAccess::should_offer_visual_cpu_fallback(const std::string& reason) {\n    return ::should_offer_visual_cpu_fallback(reason);\n}\n\nstd::string MainAppTestAccess::resolve_document_prompt_name(const std::string& original_name,\n                                                            const std::string& suggested_name) {\n    return ::resolve_document_prompt_name(original_name, suggested_name);\n}\n\nstd::string MainAppTestAccess::build_document_prompt_path(const std::string& full_path,\n                                                          const std::string& prompt_name,\n                                                          const std::string& summary) {\n    return ::build_document_prompt_path(full_path, prompt_name, summary);\n}\n\nvoid MainAppTestAccess::trigger_retranslate(MainApp& app) {\n    app.retranslate_ui();\n}\n\nvoid MainAppTestAccess::add_categorized_files(MainApp& app, int count) {\n    app.record_categorized_metrics(count);\n}\n\nvoid MainAppTestAccess::simulate_support_prompt(Settings& settings,\n                                                bool& prompt_state,\n                                                int count,\n                                                std::function<SimulatedSupportResult(int)> callback) {\n    const auto config_dir = Utils::utf8_to_path(settings.get_config_dir());\n    auto convert = [config_dir, cb = std::move(callback)](int total) -> MainApp::SupportPromptResult {\n        if (!cb) {\n            return MainApp::SupportPromptResult::NotSure;\n        }\n        switch (cb(total)) {\n            case SimulatedSupportResult::Support:\n                if (SupportCodeManager(config_dir).force_disable_prompt_for_testing()) {\n                    return MainApp::SupportPromptResult::Support;\n                }\n                return MainApp::SupportPromptResult::NotSure;\n            case SimulatedSupportResult::NotSure:\n            default:\n                return MainApp::SupportPromptResult::NotSure;\n        }\n    };\n\n    record_categorized_metrics_impl(settings, prompt_state, count, convert);\n}\n\n#endif // AI_FILE_SORTER_TEST_BUILD\n\nvoid MainApp::on_language_selected(Language language)\n{\n    settings.set_language(language);\n    TranslationManager::instance().set_language(language);\n    if (ui_translator_) {\n        ui_translator_->update_language_checks();\n    }\n    retranslate_ui();\n\n    if (categorization_dialog) {\n        QCoreApplication::postEvent(\n            categorization_dialog.get(),\n            new QEvent(QEvent::LanguageChange));\n    }\n    if (progress_dialog) {\n        QCoreApplication::postEvent(\n            progress_dialog.get(),\n            new QEvent(QEvent::LanguageChange));\n    }\n}\n\nvoid MainApp::on_category_language_selected(CategoryLanguage language)\n{\n    settings.set_category_language(language);\n    if (ui_translator_) {\n        ui_translator_->update_language_checks();\n    }\n}\n\n\nvoid MainApp::on_analyze_clicked()\n{\n    if (analyze_thread.joinable()) {\n        stop_running_analysis();\n        update_analyze_button_state(false);\n        statusBar()->showMessage(tr(\"Analysis cancelled\"), 4000);\n        status_is_ready_ = false;\n        return;\n    }\n\n    const std::string folder_path = get_folder_path();\n    if (!Utils::is_valid_directory(folder_path.c_str())) {\n        show_error_dialog(ERR_INVALID_PATH);\n        core_logger->warn(\"User supplied invalid directory '{}'\", folder_path);\n        return;\n    }\n\n    if (!using_local_llm) {\n        if (!Utils::is_network_available()) {\n            show_error_dialog(ERR_NO_INTERNET_CONNECTION);\n            core_logger->warn(\"Network unavailable when attempting to analyze '{}'\", folder_path);\n            return;\n        }\n        std::string credential_error;\n        if (!categorization_service.ensure_remote_credentials(&credential_error)) {\n            show_error_dialog(credential_error.empty()\n                                  ? \"Remote model credentials are missing or invalid. Please configure your API key and try again.\"\n                                  : credential_error);\n            return;\n        }\n    }\n\n    if (!ensure_folder_categorization_style(folder_path)) {\n        return;\n    }\n\n    stop_analysis = false;\n    text_cpu_fallback_choice_.reset();\n    update_analyze_button_state(true);\n\n    const bool show_subcategory = use_subcategories_checkbox->isChecked();\n    progress_dialog = std::make_unique<CategorizationProgressDialog>(this, this, show_subcategory);\n    progress_dialog->show();\n\n    analyze_thread = std::thread([this]() {\n        try {\n            perform_analysis();\n        } catch (const std::exception& ex) {\n            core_logger->error(\"Exception during analysis: {}\", ex.what());\n            run_on_ui([this, message = std::string(\"Analysis error: \") + ex.what()]() {\n                handle_analysis_failure(message);\n            });\n        }\n    });\n}\n\n\nvoid MainApp::on_directory_selected(const QString& path, bool user_initiated)\n{\n    path_entry->setText(path);\n    statusBar()->showMessage(tr(\"Folder selected: %1\").arg(path), 3000);\n    status_is_ready_ = false;\n\n    if (!user_initiated) {\n        focus_file_explorer_on_path(path);\n    }\n\n    update_folder_contents(path);\n}\n\nvoid MainApp::set_categorization_style(bool use_consistency)\n{\n    if (!categorization_style_refined_radio || !categorization_style_consistent_radio) {\n        return;\n    }\n\n    QSignalBlocker blocker_refined(categorization_style_refined_radio);\n    QSignalBlocker blocker_consistent(categorization_style_consistent_radio);\n    categorization_style_refined_radio->setChecked(!use_consistency);\n    categorization_style_consistent_radio->setChecked(use_consistency);\n}\n\nvoid MainApp::apply_whitelist_to_selector()\n{\n    if (!whitelist_selector) {\n        return;\n    }\n    auto names = whitelist_store.list_names();\n    if (names.empty()) {\n        whitelist_store.ensure_default_from_legacy(settings.get_allowed_categories(),\n                                                   settings.get_allowed_subcategories());\n        whitelist_store.save();\n        names = whitelist_store.list_names();\n    }\n    const QString current_active = QString::fromStdString(settings.get_active_whitelist());\n    whitelist_selector->blockSignals(true);\n    whitelist_selector->clear();\n    for (const auto& name : names) {\n        whitelist_selector->addItem(QString::fromStdString(name));\n    }\n    whitelist_selector->setEnabled(use_whitelist_checkbox && use_whitelist_checkbox->isChecked());\n    int idx = whitelist_selector->findText(current_active);\n    if (idx < 0 && !names.empty()) {\n        const QString def = QString::fromStdString(whitelist_store.default_name());\n        idx = whitelist_selector->findText(def);\n        if (idx < 0) {\n            idx = 0;\n        }\n    }\n    if (idx >= 0) {\n        whitelist_selector->setCurrentIndex(idx);\n        const QString chosen = whitelist_selector->itemText(idx);\n        settings.set_active_whitelist(chosen.toStdString());\n        if (auto entry = whitelist_store.get(chosen.toStdString())) {\n            settings.set_allowed_categories(entry->categories);\n            settings.set_allowed_subcategories(entry->subcategories);\n        }\n    }\n    whitelist_selector->blockSignals(false);\n}\n\nvoid MainApp::show_whitelist_manager()\n{\n    if (!whitelist_dialog) {\n        whitelist_dialog = std::make_unique<WhitelistManagerDialog>(whitelist_store, this);\n        whitelist_dialog->set_on_lists_changed([this]() {\n            whitelist_store.load();\n            whitelist_store.save();\n            apply_whitelist_to_selector();\n        });\n    }\n    whitelist_dialog->show();\n    whitelist_dialog->raise();\n    whitelist_dialog->activateWindow();\n}\n\nvoid MainApp::initialize_whitelists()\n{\n    whitelist_store.initialize_from_settings(settings);\n}\n\nbool MainApp::ensure_folder_categorization_style(const std::string& folder_path)\n{\n    const bool desired = settings.get_use_consistency_hints();\n    const bool recursive = settings.get_include_subdirectories();\n    if (!db_manager.has_categorization_style_conflict(folder_path, desired, recursive)) {\n        return true;\n    }\n\n    const auto style_label = [](bool value) -> QString {\n        return value ? tr(\"More consistent\") : tr(\"More refined\");\n    };\n\n    QMessageBox box(this);\n    box.setIcon(QMessageBox::Question);\n    box.setWindowTitle(tr(\"Recategorize folder?\"));\n    box.setText(tr(\"This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?\")\n                    .arg(style_label(!desired), style_label(desired)));\n    QPushButton* recategorize_button = box.addButton(tr(\"Recategorize\"), QMessageBox::AcceptRole);\n    box.addButton(tr(\"Keep existing\"), QMessageBox::RejectRole);\n    QPushButton* cancel_button = box.addButton(QMessageBox::Cancel);\n    box.exec();\n\n    if (box.clickedButton() == cancel_button) {\n        return false;\n    }\n\n    if (box.clickedButton() == recategorize_button) {\n        if (!db_manager.clear_directory_categorizations(folder_path, recursive)) {\n            show_error_dialog(tr(\"Failed to reset cached categorization for this folder.\").toStdString());\n            return false;\n        }\n    }\n\n    return true;\n}\n\n\nvoid MainApp::ensure_one_checkbox_active(QCheckBox* changed_checkbox)\n{\n    if (!categorize_files_checkbox || !categorize_directories_checkbox) {\n        return;\n    }\n\n    const bool include_subdirs_active = include_subdirectories_checkbox &&\n                                        include_subdirectories_checkbox->isChecked();\n    if (include_subdirs_active &&\n        !categorize_files_checkbox->isChecked() &&\n        !categorize_directories_checkbox->isChecked()) {\n        return;\n    }\n\n    if (!categorize_files_checkbox->isChecked() && !categorize_directories_checkbox->isChecked()) {\n        QCheckBox* other = (changed_checkbox == categorize_files_checkbox)\n                               ? categorize_directories_checkbox\n                               : categorize_files_checkbox;\n        other->setChecked(true);\n    }\n}\n\n\nvoid MainApp::update_file_scan_option(FileScanOptions option, bool enabled)\n{\n    if (enabled) {\n        file_scan_options = file_scan_options | option;\n    } else {\n        file_scan_options = file_scan_options & ~option;\n    }\n}\n\nFileScanOptions MainApp::effective_scan_options() const\n{\n    const bool analyze_images = settings.get_analyze_images_by_content();\n    const bool analyze_documents = settings.get_analyze_documents_by_content();\n    const bool images_only = analyze_images && settings.get_process_images_only();\n    const bool documents_only = analyze_documents && settings.get_process_documents_only();\n    if (images_only || documents_only) {\n        return FileScanOptions::Files;\n    }\n    FileScanOptions options = file_scan_options;\n    if (analyze_images || analyze_documents) {\n        options = options | FileScanOptions::Files;\n    }\n    if (settings.get_include_subdirectories() && has_flag(options, FileScanOptions::Files)) {\n        options = options | FileScanOptions::Recursive;\n    }\n    return options;\n}\n\nbool MainApp::visual_llm_files_available() const\n{\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    if (visual_llm_available_probe_) {\n        return visual_llm_available_probe_();\n    }\n#endif\n    const char* model_url = std::getenv(\"LLAVA_MODEL_URL\");\n    const char* mmproj_url = std::getenv(\"LLAVA_MMPROJ_URL\");\n    if (!model_url || *model_url == '\\0' || !mmproj_url || *mmproj_url == '\\0') {\n        return false;\n    }\n\n    const auto model_path = std::filesystem::path(\n        Utils::make_default_path_to_file_from_download_url(model_url));\n    const auto mmproj_path = std::filesystem::path(\n        Utils::make_default_path_to_file_from_download_url(mmproj_url));\n\n    if (!std::filesystem::exists(model_path)) {\n        return false;\n    }\n\n    if (std::filesystem::exists(mmproj_path)) {\n        return true;\n    }\n\n    const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination());\n    static const char* kAltMmprojNames[] = {\n        \"mmproj-model-f16.gguf\",\n        \"llava-v1.6-mistral-7b-mmproj-f16.gguf\"\n    };\n    for (const char* alt_name : kAltMmprojNames) {\n        if (std::filesystem::exists(llm_dir / alt_name)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nvoid MainApp::update_image_analysis_controls()\n{\n    if (!analyze_images_checkbox ||\n        !process_images_only_checkbox ||\n        !add_image_date_to_category_checkbox ||\n        !add_image_date_place_to_filename_checkbox ||\n        !offer_rename_images_checkbox ||\n        !rename_images_only_checkbox) {\n        return;\n    }\n\n    const bool analysis_enabled = analyze_images_checkbox->isChecked();\n    const bool rename_only = analysis_enabled && rename_images_only_checkbox->isChecked();\n    process_images_only_checkbox->setEnabled(analysis_enabled);\n    offer_rename_images_checkbox->setEnabled(analysis_enabled);\n    rename_images_only_checkbox->setEnabled(analysis_enabled);\n    add_image_date_to_category_checkbox->setEnabled(analysis_enabled && !rename_only);\n    add_image_date_place_to_filename_checkbox->setEnabled(\n        analysis_enabled && offer_rename_images_checkbox->isChecked());\n    if (image_options_toggle_button) {\n        image_options_toggle_button->setEnabled(analysis_enabled);\n        const bool expanded = image_options_toggle_button->isChecked();\n        sync_disclosure_button(image_options_toggle_button, expanded);\n        if (image_options_container) {\n            image_options_container->setVisible(analysis_enabled && expanded);\n        }\n    } else if (image_options_container) {\n        image_options_container->setVisible(analysis_enabled);\n    }\n\n    if (analysis_enabled &&\n        rename_images_only_checkbox->isChecked() &&\n        !offer_rename_images_checkbox->isChecked()) {\n        QSignalBlocker blocker(offer_rename_images_checkbox);\n        offer_rename_images_checkbox->setChecked(true);\n    }\n\n    update_image_only_controls();\n}\n\nvoid MainApp::update_image_only_controls()\n{\n    if (!process_images_only_checkbox && !process_documents_only_checkbox) {\n        return;\n    }\n\n    const bool analyze_images = analyze_images_checkbox && analyze_images_checkbox->isChecked();\n    const bool analyze_documents = analyze_documents_checkbox && analyze_documents_checkbox->isChecked();\n    const bool images_only_active = process_images_only_checkbox &&\n                                    analyze_images &&\n                                    process_images_only_checkbox->isChecked();\n    const bool documents_only_active = process_documents_only_checkbox &&\n                                       analyze_documents &&\n                                       process_documents_only_checkbox->isChecked();\n    const bool rename_images_active = rename_images_only_checkbox &&\n                                      analyze_images &&\n                                      rename_images_only_checkbox->isChecked();\n    const bool rename_documents_active = rename_documents_only_checkbox &&\n                                         analyze_documents &&\n                                         rename_documents_only_checkbox->isChecked();\n\n    const bool restrict_types = images_only_active || documents_only_active;\n    const bool allow_images = !restrict_types || images_only_active;\n    const bool allow_documents = !restrict_types || documents_only_active;\n    const bool allow_other_files = !restrict_types;\n    const bool images_rename_only = allow_images ? rename_images_active : true;\n    const bool documents_rename_only = allow_documents ? rename_documents_active : true;\n    const bool disable_files_categorization =\n        !allow_other_files && images_rename_only && documents_rename_only;\n    const bool include_subdirs_active = include_subdirectories_checkbox &&\n                                        include_subdirectories_checkbox->isChecked();\n    const bool disable_directories_categorization = restrict_types || include_subdirs_active;\n\n    if (use_subcategories_checkbox) {\n        use_subcategories_checkbox->setEnabled(!disable_files_categorization);\n    }\n    if (categorize_files_checkbox) {\n        categorize_files_checkbox->setEnabled(!disable_files_categorization);\n    }\n    if (categorize_directories_checkbox) {\n        categorize_directories_checkbox->setEnabled(!disable_directories_categorization);\n    }\n    if (categorization_style_heading) {\n        categorization_style_heading->setEnabled(!disable_files_categorization);\n    }\n    if (categorization_style_refined_radio) {\n        categorization_style_refined_radio->setEnabled(!disable_files_categorization);\n    }\n    if (categorization_style_consistent_radio) {\n        categorization_style_consistent_radio->setEnabled(!disable_files_categorization);\n    }\n    if (use_whitelist_checkbox) {\n        use_whitelist_checkbox->setEnabled(!disable_files_categorization);\n    }\n    if (whitelist_selector) {\n        const bool whitelist_enabled = !disable_files_categorization &&\n                                       use_whitelist_checkbox &&\n                                       use_whitelist_checkbox->isChecked();\n        whitelist_selector->setEnabled(whitelist_enabled);\n    }\n}\n\nvoid MainApp::update_document_analysis_controls()\n{\n    if (!analyze_documents_checkbox ||\n        !process_documents_only_checkbox ||\n        !offer_rename_documents_checkbox ||\n        !rename_documents_only_checkbox ||\n        !add_document_date_to_category_checkbox) {\n        return;\n    }\n\n    const bool analysis_enabled = analyze_documents_checkbox->isChecked();\n    process_documents_only_checkbox->setEnabled(analysis_enabled);\n    offer_rename_documents_checkbox->setEnabled(analysis_enabled);\n    rename_documents_only_checkbox->setEnabled(analysis_enabled);\n\n    const bool rename_only = analysis_enabled && rename_documents_only_checkbox->isChecked();\n    add_document_date_to_category_checkbox->setEnabled(analysis_enabled && !rename_only);\n\n    if (analysis_enabled &&\n        rename_documents_only_checkbox->isChecked() &&\n        !offer_rename_documents_checkbox->isChecked()) {\n        QSignalBlocker blocker(offer_rename_documents_checkbox);\n        offer_rename_documents_checkbox->setChecked(true);\n    }\n\n    if (document_options_toggle_button) {\n        document_options_toggle_button->setEnabled(analysis_enabled);\n        const bool expanded = document_options_toggle_button->isChecked();\n        sync_disclosure_button(document_options_toggle_button, expanded);\n        if (document_options_container) {\n            document_options_container->setVisible(analysis_enabled && expanded);\n        }\n    } else if (document_options_container) {\n        document_options_container->setVisible(analysis_enabled);\n    }\n\n    update_image_only_controls();\n}\n\nvoid MainApp::run_llm_selection_dialog_for_visual()\n{\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    if (llm_selection_runner_override_) {\n        llm_selection_runner_override_();\n        return;\n    }\n#endif\n    show_llm_selection_dialog();\n}\n\nvoid MainApp::handle_image_analysis_toggle(bool checked)\n{\n    if (!analyze_images_checkbox) {\n        return;\n    }\n\n    if (checked && !visual_llm_files_available()) {\n        bool should_open_dialog = false;\n#ifdef AI_FILE_SORTER_TEST_BUILD\n        if (image_analysis_prompt_override_) {\n            should_open_dialog = image_analysis_prompt_override_();\n        } else\n#endif\n        {\n            QMessageBox box(this);\n            box.setIcon(QMessageBox::Information);\n            box.setWindowTitle(tr(\"Download required\"));\n            box.setText(tr(\"Image analysis requires visual LLM files. Download them now?\"));\n            QPushButton* ok_button = box.addButton(tr(\"OK\"), QMessageBox::AcceptRole);\n            box.addButton(QMessageBox::Cancel);\n            box.setDefaultButton(ok_button);\n            box.exec();\n            should_open_dialog = (box.clickedButton() == ok_button);\n        }\n\n        if (!should_open_dialog) {\n            QSignalBlocker blocker(analyze_images_checkbox);\n            analyze_images_checkbox->setChecked(false);\n            settings.set_analyze_images_by_content(false);\n            update_image_analysis_controls();\n            return;\n        }\n\n        run_llm_selection_dialog_for_visual();\n\n        if (!visual_llm_files_available()) {\n            QSignalBlocker blocker(analyze_images_checkbox);\n            analyze_images_checkbox->setChecked(false);\n            settings.set_analyze_images_by_content(false);\n            update_image_analysis_controls();\n            return;\n        }\n    }\n\n    settings.set_analyze_images_by_content(analyze_images_checkbox->isChecked());\n    update_image_analysis_controls();\n}\n\n\nvoid MainApp::update_analyze_button_state(bool analyzing)\n{\n    analysis_in_progress_ = analyzing;\n    if (analyzing) {\n        analyze_button->setText(tr(\"Stop analyzing\"));\n        statusBar()->showMessage(tr(\"Analyzing…\"));\n        status_is_ready_ = false;\n    } else {\n        analyze_button->setText(tr(\"Analyze folder\"));\n        statusBar()->showMessage(tr(\"Ready\"));\n        status_is_ready_ = true;\n    }\n}\n\nvoid MainApp::update_results_view_mode()\n{\n    if (!results_stack) {\n        return;\n    }\n\n    const bool explorer_visible = file_explorer_dock && file_explorer_dock->isVisible();\n    const int target_index = explorer_visible ? folder_view_page_index_ : tree_view_page_index_;\n    if (target_index >= 0 && target_index < results_stack->count()) {\n        results_stack->setCurrentIndex(target_index);\n    }\n\n    if (explorer_visible && path_entry) {\n        update_folder_contents(path_entry->text());\n    }\n}\n\nvoid MainApp::update_folder_contents(const QString& directory)\n{\n    if (!folder_contents_model || !folder_contents_view || directory.isEmpty()) {\n        return;\n    }\n\n    QDir dir(directory);\n    if (!dir.exists()) {\n        return;\n    }\n\n    const bool previous_flag = suppress_folder_view_sync_;\n    suppress_folder_view_sync_ = true;\n\n    const QModelIndex new_root = folder_contents_model->setRootPath(directory);\n    folder_contents_view->setRootIndex(new_root);\n    folder_contents_view->scrollTo(new_root, QAbstractItemView::PositionAtTop);\n\n    folder_contents_view->resizeColumnToContents(0);\n\n    suppress_folder_view_sync_ = previous_flag;\n}\n\nvoid MainApp::focus_file_explorer_on_path(const QString& path)\n{\n    if (!file_system_model || !file_explorer_view || path.isEmpty()) {\n        return;\n    }\n\n    const QModelIndex index = file_system_model->index(path);\n    if (!index.isValid()) {\n        return;\n    }\n\n    const bool previous_suppress = suppress_explorer_sync_;\n    suppress_explorer_sync_ = true;\n\n    file_explorer_view->setCurrentIndex(index);\n    file_explorer_view->expand(index);\n    file_explorer_view->scrollTo(index, QAbstractItemView::PositionAtCenter);\n\n    suppress_explorer_sync_ = previous_suppress;\n}\n\nvoid MainApp::record_categorized_metrics(int count)\n{\n    record_categorized_metrics_impl(\n        settings,\n        donation_prompt_active_,\n        count,\n        [this](int total) { return show_support_prompt_dialog(total); });\n}\n\nvoid MainApp::undo_last_run()\n{\n    const auto latest = undo_manager_.latest_plan_path();\n    if (!latest) {\n        show_error_dialog(\"No undo plans available.\");\n        return;\n    }\n\n    QMessageBox box(this);\n    box.setWindowTitle(tr(\"Undo last run\"));\n    box.setText(tr(\"This will attempt to move files back to their original locations based on the last run.\\n\\nPlan file: %1\")\n                    .arg(*latest));\n    box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);\n    box.setDefaultButton(QMessageBox::Cancel);\n    if (box.exec() != QMessageBox::Ok) {\n        return;\n    }\n\n    const auto res = undo_manager_.undo_plan(*latest);\n    QString summary = tr(\"Restored %1 file(s). Skipped %2.\").arg(res.restored).arg(res.skipped);\n    if (!res.details.isEmpty()) {\n        summary.append(\"\\n\");\n        summary.append(res.details.join(\"\\n\"));\n    }\n\n    QMessageBox::information(this, tr(\"Undo complete\"), summary);\n    if (ui_logger) {\n        ui_logger->info(summary.toStdString());\n    }\n    if (res.restored > 0) {\n        QFile::remove(*latest);\n    }\n}\n\nbool MainApp::perform_undo_from_plan(const QString& plan_path)\n{\n    const auto res = undo_manager_.undo_plan(plan_path);\n    QString summary = tr(\"Restored %1 file(s). Skipped %2.\").arg(res.restored).arg(res.skipped);\n    if (!res.details.isEmpty()) {\n        summary.append(\"\\n\");\n        summary.append(res.details.join(\"\\n\"));\n    }\n    QMessageBox::information(this, tr(\"Undo complete\"), summary);\n    return res.restored > 0;\n}\n\nMainApp::SupportPromptResult MainApp::show_support_prompt_dialog(int total_files)\n{\n    QMessageBox box(this);\n    box.setIcon(QMessageBox::Information);\n    box.setWindowTitle(QObject::tr(\"Support %1\").arg(app_display_name()));\n\n    const QString headline = tr(\"Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.\")\n                                 .arg(total_files);\n    const QString details = tr(\"AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. \"\n                               \"If the app saves you time or brings value, please consider supporting it so it can keep improving.\");\n    const QString code_note = tr(\"Already donated? Click \\\"I have already donated\\\" to enter your donation code and permanently disable this reminder.\");\n\n    box.setText(headline);\n    box.setInformativeText(details + QStringLiteral(\"\\n\\n\") + code_note);\n\n    auto* support_btn = box.addButton(tr(\"Donate to permanently hide the donation dialog\"), QMessageBox::ActionRole);\n    auto* later_btn = box.addButton(tr(\"I'm not yet sure\"), QMessageBox::ActionRole);\n    auto* donated_btn = box.addButton(tr(\"I have already donated\"), QMessageBox::ActionRole);\n\n    const auto apply_button_style = [](QAbstractButton* button,\n                                       const QString& background,\n                                       const QString& hover,\n                                       const QString& text_color,\n                                       int font_weight,\n                                       const QString& border) {\n        if (!button) {\n            return;\n        }\n        button->setStyleSheet(QStringLiteral(\n            \"QPushButton {\"\n            \"  background-color: %1;\"\n            \"  color: %2;\"\n            \"  padding: 6px 18px;\"\n            \"  border: %5;\"\n            \"  border-radius: 14px;\"\n            \"  font-weight: %3;\"\n            \"}\"\n            \"QPushButton:hover {\"\n            \"  background-color: %4;\"\n            \"}\"\n            \"QPushButton:pressed {\"\n            \"  background-color: %4;\"\n            \"  opacity: 0.9;\"\n            \"}\"\n        ).arg(background,\n              text_color,\n              QString::number(font_weight),\n              hover,\n              border));\n    };\n\n    apply_button_style(support_btn,\n                       QStringLiteral(\"#007aff\"),\n                       QStringLiteral(\"#005ec7\"),\n                       QStringLiteral(\"white\"),\n                       800,\n                       QStringLiteral(\"2px solid #005ec7\"));\n    const QString neutral_bg = QStringLiteral(\"#bdc3c7\");\n    const QString neutral_hover = QStringLiteral(\"#95a5a6\");\n    apply_button_style(later_btn,\n                       neutral_bg,\n                       neutral_hover,\n                       QStringLiteral(\"#1f1f1f\"),\n                       500,\n                       QStringLiteral(\"none\"));\n    apply_button_style(donated_btn,\n                       neutral_bg,\n                       neutral_hover,\n                       QStringLiteral(\"#1f1f1f\"),\n                       500,\n                       QStringLiteral(\"none\"));\n\n    if (auto* button_box = box.findChild<QDialogButtonBox*>()) {\n        button_box->setCenterButtons(true);\n        button_box->setLayoutDirection(Qt::LeftToRight);\n        if (auto* layout = qobject_cast<QBoxLayout*>(button_box->layout())) {\n            int insert_index = layout->count();\n            for (int i = 0; i < layout->count(); ++i) {\n                if (auto* item = layout->itemAt(i); item && item->widget() &&\n                    qobject_cast<QAbstractButton*>(item->widget())) {\n                    insert_index = i;\n                    break;\n                }\n            }\n\n            layout->removeWidget(support_btn);\n            layout->removeWidget(later_btn);\n            layout->removeWidget(donated_btn);\n\n            layout->insertWidget(insert_index++, support_btn);\n            layout->insertWidget(insert_index++, donated_btn);\n            layout->insertWidget(insert_index, later_btn);\n        }\n    }\n\n    support_btn->setAutoDefault(true);\n    support_btn->setDefault(true);\n    later_btn->setAutoDefault(false);\n    donated_btn->setAutoDefault(false);\n    support_btn->setFocus();\n    box.setDefaultButton(support_btn);\n    box.exec();\n\n    const QAbstractButton* clicked = box.clickedButton();\n    auto prompt_for_donation_code = [this]() -> SupportPromptResult {\n        SupportCodeManager support_codes(Utils::utf8_to_path(settings.get_config_dir()));\n        while (true) {\n            bool accepted = false;\n            const QString code = QInputDialog::getText(\n                this,\n                tr(\"Donation code\"),\n                tr(\"Enter the donation code generated after your donation.\\n\"\n                   \"A valid code will permanently hide the donation dialog.\"),\n                QLineEdit::Normal,\n                QString(),\n                &accepted);\n            if (!accepted) {\n                return SupportPromptResult::NotSure;\n            }\n\n            if (support_codes.redeem_code(to_utf8(code))) {\n                return SupportPromptResult::Support;\n            }\n\n            QMessageBox::warning(\n                this,\n                tr(\"Invalid donation code\"),\n                tr(\"The donation code is invalid. Please try again or press Cancel.\"));\n        }\n    };\n\n    if (clicked == support_btn) {\n        if (!MainAppHelpActions::open_support_page()) {\n            QMessageBox::information(\n                this,\n                tr(\"Open donation page\"),\n                tr(\"Could not open your browser automatically.\\nPlease open this link manually:\\n%1\")\n                    .arg(MainAppHelpActions::support_page_url()));\n        }\n        return prompt_for_donation_code();\n    }\n    if (clicked == donated_btn) {\n        return prompt_for_donation_code();\n    }\n    return SupportPromptResult::NotSure;\n}\n\n\nvoid MainApp::handle_analysis_finished()\n{\n    update_analyze_button_state(false);\n\n    if (analyze_thread.joinable()) {\n        analyze_thread.join();\n    }\n\n    if (progress_dialog) {\n        progress_dialog->hide();\n        progress_dialog.reset();\n    }\n\n    stop_analysis = false;\n\n    if (new_files_to_sort.empty()) {\n        handle_no_files_to_sort();\n        return;\n    }\n\n    populate_tree_view(new_files_to_sort);\n    show_results_dialog(new_files_to_sort);\n}\n\nvoid MainApp::handle_analysis_cancelled()\n{\n    update_analyze_button_state(false);\n\n    if (analyze_thread.joinable()) {\n        analyze_thread.join();\n    }\n\n    if (progress_dialog) {\n        progress_dialog->hide();\n        progress_dialog.reset();\n    }\n\n    stop_analysis = false;\n    statusBar()->showMessage(tr(\"Analysis cancelled\"), 4000);\n}\n\n\nvoid MainApp::handle_analysis_failure(const std::string& message)\n{\n    update_analyze_button_state(false);\n    if (analyze_thread.joinable()) {\n        analyze_thread.join();\n    }\n    if (progress_dialog) {\n        progress_dialog->hide();\n        progress_dialog.reset();\n    }\n    stop_analysis = false;\n    show_error_dialog(message);\n}\n\n\nvoid MainApp::handle_no_files_to_sort()\n{\n    show_error_dialog(ERR_NO_FILES_TO_CATEGORIZE);\n}\n\n\nvoid MainApp::populate_tree_view(const std::vector<CategorizedFile>& files)\n{\n    tree_model->removeRows(0, tree_model->rowCount());\n\n    for (const auto& file : files) {\n        QList<QStandardItem*> row;\n        auto* file_item = new QStandardItem(QString::fromStdString(file.file_name));\n        auto* type_item = new QStandardItem(file.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\"));\n        type_item->setData(file.type == FileType::Directory ? QStringLiteral(\"D\") : QStringLiteral(\"F\"), Qt::UserRole);\n        auto* category_item = new QStandardItem(QString::fromStdString(file.category));\n        auto* subcategory_item = new QStandardItem(QString::fromStdString(file.subcategory));\n        auto* status_item = new QStandardItem(tr(\"Ready\"));\n        status_item->setData(QStringLiteral(\"ready\"), Qt::UserRole);\n        row << file_item << type_item << category_item << subcategory_item << status_item;\n        tree_model->appendRow(row);\n    }\n}\n\n\n\nvoid MainApp::append_progress(const std::string& message)\n{\n    run_on_ui([this, message]() {\n        if (progress_dialog) {\n            progress_dialog->append_text(message);\n        }\n    });\n}\n\nvoid MainApp::configure_progress_stages(const std::vector<CategorizationProgressDialog::StagePlan>& stages)\n{\n    run_on_ui_blocking([this, stages]() {\n        if (progress_dialog) {\n            progress_dialog->configure_stages(stages);\n        }\n    });\n}\n\nvoid MainApp::set_progress_stage_items(CategorizationProgressDialog::StageId stage_id,\n                                       const std::vector<FileEntry>& items)\n{\n    run_on_ui_blocking([this, stage_id, items]() {\n        if (progress_dialog) {\n            progress_dialog->set_stage_items(stage_id, items);\n        }\n    });\n}\n\nvoid MainApp::set_progress_active_stage(CategorizationProgressDialog::StageId stage_id)\n{\n    run_on_ui_blocking([this, stage_id]() {\n        if (progress_dialog) {\n            progress_dialog->set_active_stage(stage_id);\n        }\n    });\n}\n\nvoid MainApp::mark_progress_stage_item_in_progress(CategorizationProgressDialog::StageId stage_id,\n                                                   const FileEntry& entry)\n{\n    run_on_ui_blocking([this, stage_id, entry]() {\n        if (progress_dialog) {\n            progress_dialog->mark_stage_item_in_progress(stage_id, entry);\n        }\n    });\n}\n\nvoid MainApp::mark_progress_stage_item_completed(CategorizationProgressDialog::StageId stage_id,\n                                                 const FileEntry& entry)\n{\n    run_on_ui_blocking([this, stage_id, entry]() {\n        if (progress_dialog) {\n            progress_dialog->mark_stage_item_completed(stage_id, entry);\n        }\n    });\n}\n\nbool MainApp::should_abort_analysis() const\n{\n    return stop_analysis.load();\n}\n\nvoid MainApp::prune_empty_cached_entries_for(const std::string& directory_path)\n{\n    const std::vector<CategorizedFile> cleared =\n        categorization_service.prune_empty_cached_entries(directory_path);\n    if (cleared.empty()) {\n        return;\n    }\n\n    if (core_logger) {\n        core_logger->warn(\"Cleared {} cached categorization entr{} with empty values for '{}'\",\n                          cleared.size(),\n                          cleared.size() == 1 ? \"y\" : \"ies\",\n                          directory_path);\n        for (const auto& entry : cleared) {\n            core_logger->warn(\"  - {}\", entry.file_name);\n        }\n    }\n    std::string reason = \"Cached category was empty. The item will be analyzed again.\";\n    if (!using_local_llm) {\n        reason += \" Configure your remote API key before analyzing.\";\n    }\n    notify_recategorization_reset(cleared, reason);\n}\n\nvoid MainApp::log_cached_highlights()\n{\n    if (already_categorized_files.empty()) {\n        return;\n    }\n    append_progress(to_utf8(tr(\"[ARCHIVE] Already categorized highlights:\")));\n    for (const auto& file_entry : already_categorized_files) {\n        const QString type_label = file_entry.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\");\n        const QString sub = file_entry.subcategory.empty()\n            ? QStringLiteral(\"-\")\n            : QString::fromStdString(file_entry.subcategory);\n        append_progress(to_utf8(QStringLiteral(\"  - [%1] %2 -> %3 / %4\")\n                                    .arg(type_label,\n                                         QString::fromStdString(file_entry.file_name),\n                                         QString::fromStdString(file_entry.category),\n                                         sub)));\n    }\n}\n\nvoid MainApp::log_pending_queue()\n{\n    if (!progress_dialog) {\n        return;\n    }\n\n    if (files_to_categorize.empty()) {\n        append_progress(to_utf8(tr(\"[DONE] No files to categorize.\")));\n        return;\n    }\n\n    append_progress(to_utf8(tr(\"[QUEUE] Items waiting for categorization:\")));\n    for (const auto& file_entry : files_to_categorize) {\n        const QString type_label = file_entry.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\");\n        append_progress(to_utf8(QStringLiteral(\"  - [%1] %2\")\n                                    .arg(type_label, QString::fromStdString(file_entry.file_name))));\n    }\n}\n\nvoid MainApp::perform_analysis()\n{\n    const std::string directory_path = get_folder_path();\n    core_logger->info(\"Starting analysis for directory '{}'\", directory_path);\n\n    bool stop_requested = false;\n    auto update_stop = [this, &stop_requested]() {\n        if (!stop_requested && should_abort_analysis()) {\n            stop_requested = true;\n        }\n        return stop_requested;\n    };\n\n    append_progress(to_utf8(tr(\"[SCAN] Exploring %1\")\n                                .arg(QString::fromStdString(directory_path))));\n    update_stop();\n\n    try {\n        prune_empty_cached_entries_for(directory_path);\n        const bool analyze_images = settings.get_analyze_images_by_content();\n        const bool analyze_documents = settings.get_analyze_documents_by_content();\n        const bool process_images_only = analyze_images && settings.get_process_images_only();\n        const bool process_documents_only = analyze_documents && settings.get_process_documents_only();\n        const bool rename_images_only = analyze_images && settings.get_rename_images_only();\n        const bool rename_documents_only = analyze_documents && settings.get_rename_documents_only();\n        const bool allow_image_renames = settings.get_offer_rename_images();\n        const bool allow_document_renames = settings.get_offer_rename_documents();\n        const bool offer_image_renames = analyze_images && allow_image_renames;\n        const bool offer_document_renames = analyze_documents && allow_document_renames;\n        const bool wants_visual_rename = analyze_images && allow_image_renames && !rename_images_only;\n        const bool wants_document_rename = analyze_documents && allow_document_renames && !rename_documents_only;\n        const bool add_image_date_place_prefixes =\n            analyze_images &&\n            allow_image_renames &&\n            settings.get_add_image_date_place_to_filename();\n        const bool add_image_date_to_category =\n            analyze_images &&\n            settings.get_add_image_date_to_category();\n        const bool add_audio_video_metadata_to_filename =\n            settings.get_add_audio_video_metadata_to_filename();\n        const bool add_document_date = analyze_documents && settings.get_add_document_date_to_category();\n        const bool use_full_path_keys = settings.get_include_subdirectories();\n\n        const auto cached_entries = categorization_service.load_cached_entries(directory_path);\n        std::vector<CategorizedFile> pending_renames;\n        pending_renames.reserve(cached_entries.size());\n        std::unordered_set<std::string> renamed_files;\n        already_categorized_files.clear();\n        already_categorized_files.reserve(cached_entries.size());\n        std::vector<FileEntry> cached_image_entries_for_visual;\n        std::unordered_map<std::string, size_t> cached_visual_indices;\n        std::vector<FileEntry> cached_document_entries_for_analysis;\n        std::unordered_map<std::string, size_t> cached_document_indices;\n        std::unordered_map<std::string, std::string> cached_image_suggestions;\n        std::unordered_map<std::string, std::string> cached_document_suggestions;\n        if (wants_visual_rename) {\n            cached_image_entries_for_visual.reserve(cached_entries.size());\n            cached_visual_indices.reserve(cached_entries.size());\n        }\n        if (wants_document_rename) {\n            cached_document_entries_for_analysis.reserve(cached_entries.size());\n            cached_document_indices.reserve(cached_entries.size());\n        }\n\n        auto to_lower = [](std::string value) {\n            std::transform(value.begin(), value.end(), value.begin(),\n                           [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });\n            return value;\n        };\n        auto has_category = [](const CategorizedFile& entry) {\n            return !entry.category.empty() && !entry.subcategory.empty();\n        };\n        auto is_supported_image_entry = [](const CategorizedFile& entry) {\n            if (entry.type != FileType::File) {\n                return false;\n            }\n            const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                   Utils::utf8_to_path(entry.file_name);\n            return LlavaImageAnalyzer::is_supported_image(full_path);\n        };\n        auto is_supported_document_entry = [](const CategorizedFile& entry) {\n            if (entry.type != FileType::File) {\n                return false;\n            }\n            const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                   Utils::utf8_to_path(entry.file_name);\n            return DocumentTextAnalyzer::is_supported_document(full_path);\n        };\n        auto is_missing_category_label = [](const std::string& value) {\n            std::string trimmed = value;\n            const auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n            trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n            trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n            if (trimmed.empty()) {\n                return true;\n            }\n            std::transform(trimmed.begin(), trimmed.end(), trimmed.begin(),\n                           [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });\n            return trimmed == \"uncategorized\";\n        };\n        auto file_key = [use_full_path_keys](const CategorizedFile& entry) {\n            if (!use_full_path_keys) {\n                return entry.file_name;\n            }\n            const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                   Utils::utf8_to_path(entry.file_name);\n            return Utils::path_to_utf8(full_path);\n        };\n        auto entry_key = [use_full_path_keys](const FileEntry& entry) {\n            return use_full_path_keys ? entry.full_path : entry.file_name;\n        };\n        auto resolve_entry_for_storage = [this](const CategorizedFile& entry) {\n            const std::string canonical_category =\n                entry.canonical_category.empty() ? entry.category : entry.canonical_category;\n            const std::string canonical_subcategory =\n                entry.canonical_subcategory.empty() ? entry.subcategory : entry.canonical_subcategory;\n            if (!canonical_category.empty()) {\n                return db_manager.resolve_category(canonical_category, canonical_subcategory);\n            }\n            return db_manager.resolve_category_for_language(entry.category,\n                                                            entry.subcategory,\n                                                            settings.get_category_language());\n        };\n        auto persist_rename_only_progress = [this, &is_missing_category_label](const FileEntry& entry,\n                                                                              const std::string& suggested_name) {\n            // Persist rename-only progress during analysis to avoid losing rename suggestions on crash.\n            const auto entry_path = Utils::utf8_to_path(entry.full_path);\n            const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path());\n            const auto cached_entry = db_manager.get_categorized_file(dir_path, entry.file_name, entry.type);\n\n            std::string category;\n            std::string subcategory;\n            bool used_consistency = false;\n            DatabaseManager::ResolvedCategory resolved{0, \"\", \"\"};\n\n            if (cached_entry) {\n                category = cached_entry->category;\n                subcategory = cached_entry->subcategory;\n                if (is_missing_category_label(category)) {\n                    category.clear();\n                }\n                if (is_missing_category_label(subcategory)) {\n                    subcategory.clear();\n                }\n                if (!category.empty()) {\n                    resolved.category = category;\n                    resolved.subcategory = subcategory;\n                    resolved.taxonomy_id = cached_entry->taxonomy_id;\n                }\n                used_consistency = cached_entry->used_consistency_hints;\n            }\n\n            const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n            db_manager.insert_or_update_file_with_categorization(\n                entry.file_name,\n                file_type_label,\n                dir_path,\n                resolved,\n                used_consistency,\n                suggested_name,\n                true);\n        };\n        auto persist_llm_suggestion_progress = [this, &is_missing_category_label](const FileEntry& entry,\n                                                                                  const std::string& suggested_name) {\n            if (suggested_name.empty()) {\n                return;\n            }\n            const auto entry_path = Utils::utf8_to_path(entry.full_path);\n            const std::string dir_path = Utils::path_to_utf8(entry_path.parent_path());\n            const auto cached_entry = db_manager.get_categorized_file(dir_path, entry.file_name, entry.type);\n\n            std::string category;\n            std::string subcategory;\n            bool used_consistency = false;\n            bool rename_applied = false;\n            DatabaseManager::ResolvedCategory resolved{0, \"\", \"\"};\n\n            if (cached_entry) {\n                category = cached_entry->category;\n                subcategory = cached_entry->subcategory;\n                if (is_missing_category_label(category)) {\n                    category.clear();\n                }\n                if (is_missing_category_label(subcategory)) {\n                    subcategory.clear();\n                }\n                if (!category.empty()) {\n                    resolved.category = category;\n                    resolved.subcategory = subcategory;\n                    resolved.taxonomy_id = cached_entry->taxonomy_id;\n                }\n                used_consistency = cached_entry->used_consistency_hints;\n                rename_applied = cached_entry->rename_applied;\n            }\n\n            const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n            db_manager.insert_or_update_file_with_categorization(\n                entry.file_name,\n                file_type_label,\n                dir_path,\n                resolved,\n                used_consistency,\n                suggested_name,\n                false,\n                rename_applied);\n        };\n        auto persist_cached_suggestion = [this, &resolve_entry_for_storage](const CategorizedFile& entry,\n                                                const std::string& suggested_name) {\n            DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry);\n            const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n            db_manager.insert_or_update_file_with_categorization(\n                entry.file_name,\n                file_type_label,\n                entry.file_path,\n                resolved,\n                entry.used_consistency_hints,\n                suggested_name,\n                entry.rename_only,\n                entry.rename_applied);\n        };\n        auto persist_analysis_results = [this, &is_missing_category_label, &resolve_entry_for_storage](const std::vector<CategorizedFile>& entries) {\n            for (const auto& entry : entries) {\n                std::string category = entry.category;\n                std::string subcategory = entry.subcategory;\n                if (is_missing_category_label(category)) {\n                    category.clear();\n                }\n                if (is_missing_category_label(subcategory)) {\n                    subcategory.clear();\n                }\n                if (category.empty() && subcategory.empty() && entry.suggested_name.empty()) {\n                    continue;\n                }\n\n                DatabaseManager::ResolvedCategory resolved{0, \"\", \"\"};\n                if (!category.empty()) {\n                    resolved = resolve_entry_for_storage(entry);\n                }\n\n                const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n                db_manager.insert_or_update_file_with_categorization(\n                    entry.file_name,\n                    file_type_label,\n                    entry.file_path,\n                    resolved,\n                    entry.used_consistency_hints,\n                    entry.suggested_name,\n                    entry.rename_only,\n                    entry.rename_applied);\n            }\n        };\n\n        for (const auto& cached_entry : cached_entries) {\n            auto entry = cached_entry;\n            const bool is_image_entry = is_supported_image_entry(entry);\n            const bool is_document_entry = is_supported_document_entry(entry);\n            const bool allow_entry_renames =\n                (is_image_entry && allow_image_renames) ||\n                (is_document_entry && allow_document_renames);\n            const bool suggested_matches = !entry.suggested_name.empty() &&\n                                           to_lower(entry.suggested_name) == to_lower(entry.file_name);\n            const bool already_renamed = entry.rename_applied || suggested_matches;\n            if (already_renamed) {\n                renamed_files.insert(file_key(entry));\n            }\n            if (entry.rename_only && !has_category(entry)) {\n                if (!allow_entry_renames) {\n                    continue;\n                }\n                if (!already_renamed) {\n                    pending_renames.push_back(entry);\n                    if (is_image_entry && !rename_images_only && !entry.suggested_name.empty()) {\n                        cached_image_suggestions.emplace(file_key(entry), entry.suggested_name);\n                    }\n                    if (is_document_entry && !rename_documents_only && !entry.suggested_name.empty()) {\n                        cached_document_suggestions.emplace(file_key(entry), entry.suggested_name);\n                    }\n                }\n                continue;\n            }\n            if (!has_category(entry)) {\n                if (!entry.suggested_name.empty()) {\n                    if (is_image_entry) {\n                        cached_image_suggestions.emplace(file_key(entry), entry.suggested_name);\n                    }\n                    if (is_document_entry) {\n                        cached_document_suggestions.emplace(file_key(entry), entry.suggested_name);\n                    }\n                    if (!already_renamed &&\n                        allow_entry_renames &&\n                        ((rename_images_only && analyze_images && is_image_entry) ||\n                         (rename_documents_only && analyze_documents && is_document_entry))) {\n                        CategorizedFile adjusted = entry;\n                        adjusted.rename_only = true;\n                        pending_renames.push_back(std::move(adjusted));\n                    }\n                }\n                continue;\n            }\n            if (!allow_entry_renames) {\n                entry.suggested_name.clear();\n                entry.rename_only = false;\n            }\n            if (rename_images_only && analyze_images && is_image_entry) {\n                if (!already_renamed && entry.suggested_name.empty()) {\n                    continue;\n                }\n                CategorizedFile adjusted = entry;\n                adjusted.rename_only = true;\n                already_categorized_files.push_back(std::move(adjusted));\n                continue;\n            }\n            if (rename_documents_only && analyze_documents && is_document_entry) {\n                if (!already_renamed && entry.suggested_name.empty()) {\n                    continue;\n                }\n                CategorizedFile adjusted = entry;\n                adjusted.rename_only = true;\n                already_categorized_files.push_back(std::move(adjusted));\n                continue;\n            }\n            if (wants_visual_rename && is_image_entry && entry.suggested_name.empty() && !already_renamed) {\n                const auto entry_index = already_categorized_files.size();\n                already_categorized_files.push_back(entry);\n                cached_visual_indices.emplace(file_key(entry), entry_index);\n                const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                       Utils::utf8_to_path(entry.file_name);\n                cached_image_entries_for_visual.push_back(\n                    FileEntry{Utils::path_to_utf8(full_path), entry.file_name, entry.type});\n                continue;\n            }\n            if (wants_document_rename && is_document_entry && entry.suggested_name.empty() && !already_renamed) {\n                const auto entry_index = already_categorized_files.size();\n                already_categorized_files.push_back(entry);\n                cached_document_indices.emplace(file_key(entry), entry_index);\n                const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                       Utils::utf8_to_path(entry.file_name);\n                cached_document_entries_for_analysis.push_back(\n                    FileEntry{Utils::path_to_utf8(full_path), entry.file_name, entry.type});\n                continue;\n            }\n            already_categorized_files.push_back(entry);\n        }\n\n        if (process_images_only || process_documents_only) {\n            const bool allow_images = process_images_only;\n            const bool allow_documents = process_documents_only;\n            auto filter_entries = [&](std::vector<CategorizedFile>& entries) {\n                entries.erase(\n                    std::remove_if(entries.begin(),\n                                   entries.end(),\n                                   [&](const CategorizedFile& entry) {\n                                       if (entry.type != FileType::File) {\n                                           return true;\n                                       }\n                                       const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                                              Utils::utf8_to_path(entry.file_name);\n                                       const bool is_image = LlavaImageAnalyzer::is_supported_image(full_path);\n                                       const bool is_document = DocumentTextAnalyzer::is_supported_document(full_path);\n                                       if (is_image && allow_images) {\n                                           return false;\n                                       }\n                                       if (is_document && allow_documents) {\n                                           return false;\n                                       }\n                                       return true;\n                                   }),\n                    entries.end());\n            };\n            filter_entries(already_categorized_files);\n            filter_entries(pending_renames);\n            if (!cached_visual_indices.empty()) {\n                for (size_t index = 0; index < already_categorized_files.size(); ++index) {\n                    auto it = cached_visual_indices.find(file_key(already_categorized_files[index]));\n                    if (it != cached_visual_indices.end()) {\n                        it->second = index;\n                    }\n                }\n            }\n            if (!cached_document_indices.empty()) {\n                for (size_t index = 0; index < already_categorized_files.size(); ++index) {\n                    auto it = cached_document_indices.find(file_key(already_categorized_files[index]));\n                    if (it != cached_document_indices.end()) {\n                        it->second = index;\n                    }\n                }\n            }\n        }\n\n        update_stop();\n\n        log_cached_highlights();\n\n        auto cached_file_names = results_coordinator.extract_file_names(already_categorized_files,\n                                                                        use_full_path_keys);\n        if ((rename_images_only || rename_documents_only) && !pending_renames.empty()) {\n            for (const auto& entry : pending_renames) {\n                cached_file_names.insert(file_key(entry));\n            }\n        }\n        const auto scan_options = effective_scan_options();\n        files_to_categorize = results_coordinator.find_files_to_categorize(directory_path,\n                                                                           scan_options,\n                                                                           cached_file_names,\n                                                                           use_full_path_keys);\n        if (process_images_only || process_documents_only) {\n            const bool allow_images = process_images_only;\n            const bool allow_documents = process_documents_only;\n            files_to_categorize.erase(\n                std::remove_if(files_to_categorize.begin(),\n                               files_to_categorize.end(),\n                               [&](const FileEntry& entry) {\n                                   if (entry.type != FileType::File) {\n                                       return true;\n                                   }\n                                   const bool is_image = LlavaImageAnalyzer::is_supported_image(entry.full_path);\n                                   const bool is_document = DocumentTextAnalyzer::is_supported_document(entry.full_path);\n                                   if (is_image && allow_images) {\n                                       return false;\n                                   }\n                                   if (is_document && allow_documents) {\n                                       return false;\n                                   }\n                                   return true;\n                               }),\n                files_to_categorize.end());\n        }\n        core_logger->debug(\"Found {} item(s) pending categorization in '{}'.\",\n                           files_to_categorize.size(), directory_path);\n\n        log_pending_queue();\n        update_stop();\n\n        append_progress(to_utf8(tr(\"[PROCESS] Letting the AI do its magic...\")));\n\n        std::vector<FileEntry> image_entries;\n        std::vector<FileEntry> document_entries;\n        std::vector<FileEntry> other_entries;\n        split_entries_for_analysis(files_to_categorize,\n                                   analyze_images,\n                                   analyze_documents,\n                                   process_images_only,\n                                   process_documents_only,\n                                   rename_images_only,\n                                   rename_documents_only,\n                                   settings.get_categorize_files(),\n                                   use_full_path_keys,\n                                   renamed_files,\n                                   image_entries,\n                                   document_entries,\n                                   other_entries);\n        if (!cached_image_entries_for_visual.empty()) {\n            image_entries.insert(image_entries.end(),\n                                 cached_image_entries_for_visual.begin(),\n                                 cached_image_entries_for_visual.end());\n        }\n        if (!cached_document_entries_for_analysis.empty()) {\n            document_entries.insert(document_entries.end(),\n                                    cached_document_entries_for_analysis.begin(),\n                                    cached_document_entries_for_analysis.end());\n        }\n\n        using ProgressStageId = CategorizationProgressDialog::StageId;\n\n        std::vector<FileEntry> image_stage_entries;\n        image_stage_entries.reserve(image_entries.size());\n        for (const auto& entry : image_entries) {\n            const bool already_renamed = renamed_files.contains(entry_key(entry));\n            if (already_renamed && rename_images_only) {\n                continue;\n            }\n            image_stage_entries.push_back(entry);\n        }\n\n        std::vector<FileEntry> document_stage_entries;\n        document_stage_entries.reserve(document_entries.size());\n        for (const auto& entry : document_entries) {\n            const bool already_renamed = renamed_files.contains(entry_key(entry));\n            if (already_renamed && rename_documents_only) {\n                continue;\n            }\n            document_stage_entries.push_back(entry);\n        }\n\n        std::vector<FileEntry> planned_categorization_entries;\n        std::unordered_set<std::string> planned_categorization_seen;\n        planned_categorization_entries.reserve(other_entries.size() +\n                                               image_entries.size() +\n                                               document_entries.size());\n        auto append_planned_categorization_entry = [&](const FileEntry& entry) {\n            const std::string key = entry_key(entry);\n            if (planned_categorization_seen.contains(key)) {\n                return;\n            }\n            planned_categorization_seen.insert(key);\n            planned_categorization_entries.push_back(entry);\n        };\n\n        for (const auto& entry : other_entries) {\n            append_planned_categorization_entry(entry);\n        }\n        if (!rename_images_only) {\n            for (const auto& entry : image_entries) {\n                if (cached_visual_indices.contains(entry_key(entry))) {\n                    continue;\n                }\n                append_planned_categorization_entry(entry);\n            }\n        }\n        if (!rename_documents_only) {\n            for (const auto& entry : document_entries) {\n                if (cached_document_indices.contains(entry_key(entry))) {\n                    continue;\n                }\n                append_planned_categorization_entry(entry);\n            }\n        }\n\n        std::vector<CategorizationProgressDialog::StagePlan> progress_stages;\n        if (!image_stage_entries.empty()) {\n            progress_stages.push_back({ProgressStageId::ImageAnalysis, image_stage_entries});\n        }\n        if (!document_stage_entries.empty()) {\n            progress_stages.push_back({ProgressStageId::DocumentAnalysis, document_stage_entries});\n        }\n        if (!planned_categorization_entries.empty()) {\n            progress_stages.push_back({ProgressStageId::Categorization, planned_categorization_entries});\n        }\n\n        configure_progress_stages(progress_stages);\n        if (!progress_stages.empty()) {\n            set_progress_active_stage(progress_stages.front().id);\n        }\n\n        struct ImageAnalysisInfo {\n            std::string suggested_name;\n            std::string prompt_name;\n            std::string prompt_path;\n        };\n\n        struct DocumentAnalysisInfo {\n            std::string suggested_name;\n            std::string prompt_name;\n            std::string prompt_path;\n        };\n\n        std::unordered_map<std::string, ImageAnalysisInfo> image_info;\n        std::vector<FileEntry> image_entries_for_llm;\n        image_entries_for_llm.reserve(image_entries.size());\n        std::vector<FileEntry> analyzed_image_entries;\n        analyzed_image_entries.reserve(image_entries.size());\n\n        std::unordered_map<std::string, DocumentAnalysisInfo> document_info;\n        std::unordered_map<std::string, std::string> image_dates;\n        std::unordered_map<std::string, std::string> document_dates;\n        std::vector<FileEntry> document_entries_for_llm;\n        document_entries_for_llm.reserve(document_entries.size());\n        std::vector<FileEntry> analyzed_document_entries;\n        analyzed_document_entries.reserve(document_entries.size());\n        std::unique_ptr<ImageRenameMetadataService> image_metadata_service;\n        std::unique_ptr<MediaRenameMetadataService> media_metadata_service;\n        std::unordered_map<std::string, std::string> media_rename_suggestions;\n        if (add_image_date_place_prefixes || add_image_date_to_category) {\n            image_metadata_service =\n                std::make_unique<ImageRenameMetadataService>(settings.get_config_dir());\n        }\n        if (add_audio_video_metadata_to_filename) {\n            media_metadata_service = std::make_unique<MediaRenameMetadataService>();\n        }\n\n        if (analyze_images && !image_entries.empty()) {\n            if (!image_stage_entries.empty()) {\n                set_progress_active_stage(ProgressStageId::ImageAnalysis);\n            }\n            auto enrich_image_suggestion = [&](const FileEntry& entry,\n                                               const std::string& raw_suggested_name) {\n                if (raw_suggested_name.empty() || !image_metadata_service) {\n                    return raw_suggested_name;\n                }\n                return image_metadata_service->enrich_suggested_name(\n                    Utils::utf8_to_path(entry.full_path),\n                    raw_suggested_name);\n            };\n            auto cache_image_date = [&](const FileEntry& entry) {\n                if (!add_image_date_to_category || !image_metadata_service) {\n                    return;\n                }\n                const std::string key = entry_key(entry);\n                if (image_dates.contains(key)) {\n                    return;\n                }\n                if (const auto date = image_metadata_service->extract_capture_date(\n                        Utils::utf8_to_path(entry.full_path))) {\n                    image_dates.emplace(key, *date);\n                }\n            };\n\n            std::string error;\n            auto visual_paths = resolve_visual_llm_paths(&error);\n            if (!visual_paths) {\n                throw std::runtime_error(error);\n            }\n\n            LlavaImageAnalyzer::Settings vision_settings;\n            vision_settings.use_gpu = should_use_visual_gpu();\n            const auto visual_gpu_override = read_env_bool(\"AI_FILE_SORTER_VISUAL_USE_GPU\");\n            if (visual_gpu_override.has_value()) {\n                vision_settings.use_gpu = *visual_gpu_override;\n            }\n            vision_settings.batch_progress = [this](int current_batch, int total_batches) {\n                if (total_batches <= 0 || current_batch <= 0) {\n                    return;\n                }\n                const double percent = (static_cast<double>(current_batch) /\n                                        static_cast<double>(total_batches)) * 100.0;\n                append_progress(to_utf8(tr(\"[VISION] Decoding image batch %1/%2 (%3%)\")\n                                            .arg(current_batch)\n                                            .arg(total_batches)\n                                            .arg(percent, 0, 'f', 2)));\n            };\n            vision_settings.log_visual_output = should_log_prompts();\n\n            const bool allow_visual_cpu_fallback = vision_settings.use_gpu && !visual_gpu_override.has_value();\n            std::optional<bool> visual_cpu_fallback_choice;\n            bool visual_cpu_fallback_active = false;\n\n            auto should_retry_on_cpu = [](const std::exception& ex) {\n                return should_offer_visual_cpu_fallback(ex.what());\n            };\n\n            auto prompt_visual_cpu_fallback = [this]() -> bool {\n                auto show_dialog = [this]() -> bool {\n                    QMessageBox box(this);\n                    box.setIcon(QMessageBox::Question);\n                    box.setWindowTitle(tr(\"Switch image analysis to CPU?\"));\n                    box.setText(tr(\"Image analysis ran out of GPU memory.\"));\n                    box.setInformativeText(tr(\"Retry on CPU instead? Cancel will skip visual analysis and fall back to \"\n                                              \"filename-based categorization.\"));\n                    box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);\n                    box.setDefaultButton(QMessageBox::Ok);\n                    return box.exec() == QMessageBox::Ok;\n                };\n                if (QThread::currentThread() == thread()) {\n                    return show_dialog();\n                }\n                bool decision = false;\n                QMetaObject::invokeMethod(\n                    this,\n                    [&decision, show_dialog]() mutable { decision = show_dialog(); },\n                    Qt::BlockingQueuedConnection);\n                return decision;\n            };\n\n            auto update_cached_image_suggestion = [&](const FileEntry& entry,\n                                                      const std::string& suggested_name) {\n                const auto it = cached_visual_indices.find(entry_key(entry));\n                if (it == cached_visual_indices.end()) {\n                    return;\n                }\n                auto& cached_entry = already_categorized_files[it->second];\n                if (cached_entry.suggested_name == suggested_name) {\n                    return;\n                }\n                cached_entry.suggested_name = suggested_name;\n                persist_cached_suggestion(cached_entry, suggested_name);\n            };\n\n            auto handle_visual_failure = [&](const FileEntry& entry,\n                                             const std::string& reason,\n                                             bool already_renamed,\n                                             bool log_failure,\n                                             bool visual_only) {\n                if (log_failure) {\n                    append_progress(to_utf8(tr(\"[VISION-ERROR] %1 (%2)\")\n                                                .arg(QString::fromStdString(entry.file_name),\n                                                     QString::fromStdString(reason))));\n                }\n                if (!rename_images_only && !visual_only) {\n                    other_entries.push_back(entry);\n                }\n                const std::string suggested_name = already_renamed ? std::string()\n                                                                   : enrich_image_suggestion(entry, entry.file_name);\n                const std::string ui_suggested_name =\n                    (allow_image_renames || rename_images_only) ? suggested_name : std::string();\n                image_info.emplace(entry_key(entry),\n                                   ImageAnalysisInfo{ui_suggested_name, entry.file_name, entry.full_path});\n                if (rename_images_only) {\n                    persist_rename_only_progress(entry, suggested_name);\n                }\n                if (visual_only) {\n                    update_cached_image_suggestion(entry, suggested_name);\n                }\n            };\n\n            auto create_analyzer = [&]() -> std::unique_ptr<LlavaImageAnalyzer> {\n                return std::make_unique<LlavaImageAnalyzer>(\n                    visual_paths->model_path,\n                    visual_paths->mmproj_path,\n                    vision_settings);\n            };\n\n            std::unique_ptr<LlavaImageAnalyzer> analyzer;\n            bool skip_visual_analysis = false;\n            std::string skip_visual_reason;\n            try {\n                analyzer = create_analyzer();\n            } catch (const std::exception& ex) {\n                const bool retry_on_cpu = should_retry_on_cpu(ex);\n                if (core_logger) {\n                    core_logger->warn(\"Visual analyzer initialization failed (retryable_on_cpu={}): {}\",\n                                      retry_on_cpu,\n                                      ex.what());\n                }\n                if (!allow_visual_cpu_fallback) {\n                    throw;\n                }\n                if (!retry_on_cpu) {\n                    skip_visual_analysis = true;\n                    skip_visual_reason = ex.what();\n                    if (core_logger) {\n                        core_logger->warn(\"Visual analysis disabled after non-retryable initialization failure.\");\n                    }\n                } else {\n                    if (!visual_cpu_fallback_choice.has_value()) {\n                        visual_cpu_fallback_choice = prompt_visual_cpu_fallback();\n                    }\n                    if (!visual_cpu_fallback_choice.value()) {\n                        skip_visual_analysis = true;\n                        skip_visual_reason = ex.what();\n                        if (core_logger) {\n                            core_logger->warn(\"Visual CPU fallback declined after initialization failure: {}\",\n                                              ex.what());\n                        }\n                    } else {\n                        append_progress(to_utf8(tr(\"[VISION] Switching visual analysis to CPU.\")));\n                        vision_settings.use_gpu = false;\n                        visual_cpu_fallback_active = true;\n                        if (core_logger) {\n                            core_logger->warn(\"Retrying visual analyzer initialization on CPU after GPU failure: {}\",\n                                              ex.what());\n                        }\n                        try {\n                            analyzer = create_analyzer();\n                            if (core_logger) {\n                                core_logger->info(\"Visual analyzer CPU fallback initialized successfully.\");\n                            }\n                        } catch (const std::exception& init_ex) {\n                            skip_visual_analysis = true;\n                            skip_visual_reason = init_ex.what();\n                            if (core_logger) {\n                                core_logger->error(\"Visual analyzer CPU fallback initialization failed: {}\",\n                                                   init_ex.what());\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (skip_visual_analysis) {\n                if (!skip_visual_reason.empty()) {\n                    if (core_logger) {\n                        core_logger->warn(\"Visual analysis disabled; falling back to filenames: {}\",\n                                          skip_visual_reason);\n                    }\n                    append_progress(to_utf8(tr(\"[VISION-ERROR] %1\")\n                                                .arg(QString::fromStdString(skip_visual_reason))));\n                }\n                append_progress(to_utf8(tr(\"[VISION] Visual analysis disabled; falling back to filenames.\")));\n                for (const auto& entry : image_entries) {\n                    if (update_stop()) {\n                        break;\n                    }\n                    const bool already_renamed = renamed_files.contains(entry_key(entry));\n                    if (already_renamed && rename_images_only) {\n                        continue;\n                    }\n                    const bool visual_only = cached_visual_indices.contains(entry_key(entry));\n                    analyzed_image_entries.push_back(entry);\n                    cache_image_date(entry);\n                    mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, entry);\n                    handle_visual_failure(entry, std::string(), already_renamed, false, visual_only);\n                    mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry);\n                }\n            } else {\n                bool stop_visual_analysis = false;\n                for (size_t index = 0; index < image_entries.size(); ++index) {\n                    const auto& entry = image_entries[index];\n                    if (update_stop()) {\n                        break;\n                    }\n                    const bool already_renamed = renamed_files.contains(entry_key(entry));\n                    if (already_renamed && rename_images_only) {\n                        continue;\n                    }\n                    const bool visual_only = cached_visual_indices.contains(entry_key(entry));\n                    const auto cached_suggestion_it = cached_image_suggestions.find(entry_key(entry));\n                    const bool has_cached_suggestion = cached_suggestion_it != cached_image_suggestions.end();\n                    analyzed_image_entries.push_back(entry);\n                    cache_image_date(entry);\n                    mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, entry);\n\n                    while (true) {\n                        try {\n                            if (has_cached_suggestion) {\n                                append_progress(to_utf8(tr(\"[VISION] Using cached suggestion for %1\")\n                                                            .arg(QString::fromStdString(entry.file_name))));\n                                const std::string prompt_name = cached_suggestion_it->second;\n                                const std::string enriched_name = enrich_image_suggestion(entry, prompt_name);\n                                const std::string suggested_name = already_renamed ? std::string()\n                                                                                   : enriched_name;\n                                const std::string ui_suggested_name =\n                                    (allow_image_renames || rename_images_only) ? suggested_name : std::string();\n                                const auto entry_path = Utils::utf8_to_path(entry.full_path);\n                                const auto prompt_path = Utils::path_to_utf8(\n                                    entry_path.parent_path() / Utils::utf8_to_path(prompt_name));\n                                image_info.emplace(entry_key(entry),\n                                                   ImageAnalysisInfo{ui_suggested_name,\n                                                                     prompt_name,\n                                                                     prompt_path});\n                                if (rename_images_only) {\n                                    persist_rename_only_progress(entry, suggested_name);\n                                }\n                                if (visual_only) {\n                                    update_cached_image_suggestion(entry, suggested_name);\n                                }\n                                if (!rename_images_only && !visual_only) {\n                                    image_entries_for_llm.push_back(entry);\n                                }\n                                mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry);\n                                break;\n                            }\n\n                            append_progress(to_utf8(tr(\"[VISION] Analyzing %1\")\n                                                        .arg(QString::fromStdString(entry.file_name))));\n                            const auto analysis = analyzer->analyze(entry.full_path);\n                            const std::string prompt_name = analysis.suggested_name;\n                            const std::string enriched_name = enrich_image_suggestion(entry, prompt_name);\n                            const auto entry_path = Utils::utf8_to_path(entry.full_path);\n                            const auto prompt_path = Utils::path_to_utf8(\n                                entry_path.parent_path() / Utils::utf8_to_path(prompt_name));\n\n                            const std::string suggested_name = already_renamed ? std::string() : enriched_name;\n                            const std::string ui_suggested_name =\n                                (allow_image_renames || rename_images_only) ? suggested_name : std::string();\n                            if (!rename_images_only) {\n                                persist_llm_suggestion_progress(entry, suggested_name);\n                            }\n                            image_info.emplace(entry_key(entry),\n                                               ImageAnalysisInfo{ui_suggested_name,\n                                                                 prompt_name,\n                                                                 prompt_path});\n                            if (rename_images_only) {\n                                persist_rename_only_progress(entry, suggested_name);\n                            }\n                            if (visual_only) {\n                                update_cached_image_suggestion(entry, suggested_name);\n                            }\n\n                            if (!rename_images_only && !visual_only) {\n                                image_entries_for_llm.push_back(entry);\n                            }\n                            mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry);\n                            break;\n                        } catch (const std::exception& ex) {\n                            const bool retry_on_cpu = should_retry_on_cpu(ex);\n                            if (!visual_cpu_fallback_active &&\n                                allow_visual_cpu_fallback &&\n                                retry_on_cpu) {\n                                if (core_logger) {\n                                    core_logger->warn(\"Visual analysis failed for '{}' with retryable GPU error: {}\",\n                                                      entry.file_name,\n                                                      ex.what());\n                                }\n                                if (!visual_cpu_fallback_choice.has_value()) {\n                                    visual_cpu_fallback_choice = prompt_visual_cpu_fallback();\n                                }\n                                if (visual_cpu_fallback_choice.value()) {\n                                    append_progress(to_utf8(tr(\"[VISION] GPU memory issue detected. Switching to CPU.\")));\n                                    vision_settings.use_gpu = false;\n                                    visual_cpu_fallback_active = true;\n                                    if (core_logger) {\n                                        core_logger->warn(\"Retrying visual analysis on CPU for '{}'.\",\n                                                          entry.file_name);\n                                    }\n                                    try {\n                                        analyzer = create_analyzer();\n                                        if (core_logger) {\n                                            core_logger->info(\"Visual analyzer CPU fallback initialized successfully; retrying '{}'.\",\n                                                              entry.file_name);\n                                        }\n                                    } catch (const std::exception& init_ex) {\n                                        if (core_logger) {\n                                            core_logger->error(\"Visual analyzer CPU fallback initialization failed for '{}': {}\",\n                                                               entry.file_name,\n                                                               init_ex.what());\n                                        }\n                                        handle_visual_failure(entry, init_ex.what(), already_renamed, true, visual_only);\n                                        append_progress(to_utf8(tr(\"[VISION] Visual analysis disabled for remaining images.\")));\n                                        stop_visual_analysis = true;\n                                    }\n                                    if (!stop_visual_analysis) {\n                                        continue;\n                                    }\n                                } else {\n                                    if (core_logger) {\n                                        core_logger->warn(\"Visual CPU fallback declined for '{}': {}\",\n                                                          entry.file_name,\n                                                          ex.what());\n                                    }\n                                    append_progress(to_utf8(tr(\"[VISION] Visual analysis disabled; falling back to filenames.\")));\n                                    handle_visual_failure(entry, ex.what(), already_renamed, true, visual_only);\n                                    stop_visual_analysis = true;\n                                }\n                            } else {\n                                if (core_logger) {\n                                    core_logger->warn(\"Visual analysis failed for '{}': {}\",\n                                                      entry.file_name,\n                                                      ex.what());\n                                }\n                                handle_visual_failure(entry, ex.what(), already_renamed, true, visual_only);\n                            }\n                            mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, entry);\n                            break;\n                        }\n                    }\n\n                    if (stop_visual_analysis) {\n                        for (size_t remaining = index + 1; remaining < image_entries.size(); ++remaining) {\n                            if (update_stop()) {\n                                break;\n                            }\n                            const auto& pending = image_entries[remaining];\n                            const bool pending_renamed = renamed_files.contains(entry_key(pending));\n                            if (pending_renamed && rename_images_only) {\n                                continue;\n                            }\n                            const bool pending_visual_only = cached_visual_indices.contains(entry_key(pending));\n                            analyzed_image_entries.push_back(pending);\n                            cache_image_date(pending);\n                            mark_progress_stage_item_in_progress(ProgressStageId::ImageAnalysis, pending);\n                            handle_visual_failure(pending, std::string(), pending_renamed, false, pending_visual_only);\n                            mark_progress_stage_item_completed(ProgressStageId::ImageAnalysis, pending);\n                        }\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (analyze_documents && !document_entries.empty()) {\n            if (!document_stage_entries.empty()) {\n                set_progress_active_stage(ProgressStageId::DocumentAnalysis);\n            }\n            auto update_cached_document_suggestion = [&](const FileEntry& entry,\n                                                         const std::string& suggested_name) {\n                const auto it = cached_document_indices.find(entry_key(entry));\n                if (it == cached_document_indices.end()) {\n                    return;\n                }\n                auto& cached_entry = already_categorized_files[it->second];\n                if (cached_entry.suggested_name == suggested_name) {\n                    return;\n                }\n                cached_entry.suggested_name = suggested_name;\n                persist_cached_suggestion(cached_entry, suggested_name);\n            };\n\n            auto handle_document_failure = [&](const FileEntry& entry,\n                                               const std::string& reason,\n                                               bool already_renamed,\n                                               bool log_failure,\n                                               bool document_only) {\n                if (log_failure) {\n                    append_progress(to_utf8(tr(\"[DOC-ERROR] %1 (%2)\")\n                                                .arg(QString::fromStdString(entry.file_name),\n                                                     QString::fromStdString(reason))));\n                    if (core_logger) {\n                        const char* fallback_action = \"falling back to filename-based categorization\";\n                        if (rename_documents_only) {\n                            fallback_action = \"keeping the original filename in rename-only mode\";\n                        } else if (document_only) {\n                            fallback_action = \"restoring the original filename as the cached suggestion\";\n                        }\n                        core_logger->warn(\"Document analysis failed for '{}': {}; {}.\",\n                                          entry.file_name,\n                                          reason,\n                                          fallback_action);\n                    }\n                }\n                if (!rename_documents_only && !document_only) {\n                    other_entries.push_back(entry);\n                }\n                const std::string suggested_name = already_renamed ? std::string() : entry.file_name;\n                const std::string ui_suggested_name =\n                    (allow_document_renames || rename_documents_only) ? suggested_name : std::string();\n                const std::string prompt_name = entry.file_name;\n                document_info.emplace(entry_key(entry),\n                                      DocumentAnalysisInfo{ui_suggested_name,\n                                                           prompt_name,\n                                                           build_document_prompt_path(entry.full_path,\n                                                                                      prompt_name,\n                                                                                      {})});\n                if (rename_documents_only) {\n                    persist_rename_only_progress(entry, suggested_name);\n                }\n                if (document_only) {\n                    update_cached_document_suggestion(entry, suggested_name);\n                }\n            };\n\n            DocumentTextAnalyzer::Settings doc_settings;\n            doc_settings.max_tokens = 256;\n            const size_t char_budget = resolve_document_char_budget(using_local_llm, doc_settings.max_tokens);\n            doc_settings.max_characters = std::min(doc_settings.max_characters, char_budget);\n            DocumentTextAnalyzer doc_analyzer(doc_settings);\n\n            auto llm = make_llm_client();\n            if (!llm) {\n                throw std::runtime_error(\"Failed to create LLM client.\");\n            }\n            llm->set_prompt_logging_enabled(should_log_prompts());\n\n            for (const auto& entry : document_entries) {\n                if (update_stop()) {\n                    break;\n                }\n                const bool already_renamed = renamed_files.contains(entry_key(entry));\n                if (already_renamed && rename_documents_only) {\n                    continue;\n                }\n                const bool document_only = cached_document_indices.contains(entry_key(entry));\n                const auto cached_suggestion_it = cached_document_suggestions.find(entry_key(entry));\n                const bool has_cached_suggestion = cached_suggestion_it != cached_document_suggestions.end();\n                if (add_document_date && !document_dates.contains(entry_key(entry))) {\n                    const auto date = DocumentTextAnalyzer::extract_creation_date(\n                        Utils::utf8_to_path(entry.full_path));\n                    if (date) {\n                        document_dates.emplace(entry_key(entry), *date);\n                    }\n                }\n                analyzed_document_entries.push_back(entry);\n                mark_progress_stage_item_in_progress(ProgressStageId::DocumentAnalysis, entry);\n\n                try {\n                    if (has_cached_suggestion) {\n                        append_progress(to_utf8(tr(\"[DOC] Using cached suggestion for %1\")\n                                                    .arg(QString::fromStdString(entry.file_name))));\n                        const std::string suggested_name = already_renamed ? std::string()\n                                                                           : cached_suggestion_it->second;\n                        const std::string ui_suggested_name =\n                            (allow_document_renames || rename_documents_only) ? suggested_name : std::string();\n                        const std::string prompt_name =\n                            resolve_document_prompt_name(entry.file_name, cached_suggestion_it->second);\n                        document_info.emplace(entry_key(entry),\n                                              DocumentAnalysisInfo{ui_suggested_name,\n                                                                   prompt_name,\n                                                                   build_document_prompt_path(entry.full_path,\n                                                                                              prompt_name,\n                                                                                              {})});\n                        if (rename_documents_only) {\n                            persist_rename_only_progress(entry, suggested_name);\n                        }\n                        if (!rename_documents_only && !document_only) {\n                            document_entries_for_llm.push_back(entry);\n                        }\n                        mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry);\n                        continue;\n                    }\n\n                    append_progress(to_utf8(tr(\"[DOC] Analyzing %1\")\n                                                .arg(QString::fromStdString(entry.file_name))));\n                    const auto analysis = doc_analyzer.analyze(Utils::utf8_to_path(entry.full_path), *llm);\n                    const std::string suggested_name = already_renamed ? std::string() : analysis.suggested_name;\n                    const std::string ui_suggested_name =\n                        (allow_document_renames || rename_documents_only) ? suggested_name : std::string();\n                    const std::string prompt_name =\n                        resolve_document_prompt_name(entry.file_name, analysis.suggested_name);\n                    const std::string prompt_path =\n                        build_document_prompt_path(entry.full_path, prompt_name, analysis.summary);\n                    if (!rename_documents_only) {\n                        persist_llm_suggestion_progress(entry, suggested_name);\n                    }\n                    document_info.emplace(entry_key(entry),\n                                          DocumentAnalysisInfo{ui_suggested_name,\n                                                               prompt_name,\n                                                               prompt_path});\n                    if (rename_documents_only) {\n                        persist_rename_only_progress(entry, suggested_name);\n                    }\n                    if (document_only) {\n                        update_cached_document_suggestion(entry, suggested_name);\n                    }\n                    if (!rename_documents_only && !document_only) {\n                        document_entries_for_llm.push_back(entry);\n                    }\n                    mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry);\n                } catch (const std::exception& ex) {\n                    handle_document_failure(entry, ex.what(), already_renamed, true, document_only);\n                    mark_progress_stage_item_completed(ProgressStageId::DocumentAnalysis, entry);\n                }\n            }\n        }\n\n        update_stop();\n\n        std::vector<FileEntry> categorization_stage_entries;\n        std::unordered_set<std::string> categorization_stage_seen;\n        categorization_stage_entries.reserve(other_entries.size() +\n                                             image_entries_for_llm.size() +\n                                             document_entries_for_llm.size());\n        auto append_categorization_stage_entry = [&](const FileEntry& entry) {\n            const std::string key = entry_key(entry);\n            if (categorization_stage_seen.contains(key)) {\n                return;\n            }\n            categorization_stage_seen.insert(key);\n            categorization_stage_entries.push_back(entry);\n        };\n\n        if (!stop_requested) {\n            for (const auto& entry : other_entries) {\n                append_categorization_stage_entry(entry);\n            }\n        }\n        for (const auto& entry : image_entries_for_llm) {\n            append_categorization_stage_entry(entry);\n        }\n        for (const auto& entry : document_entries_for_llm) {\n            append_categorization_stage_entry(entry);\n        }\n\n        set_progress_stage_items(ProgressStageId::Categorization, categorization_stage_entries);\n        if (!categorization_stage_entries.empty()) {\n            set_progress_active_stage(ProgressStageId::Categorization);\n        }\n\n        auto suggested_name_provider = [allow_image_renames,\n                                        allow_document_renames,\n                                        add_audio_video_metadata_to_filename,\n                                        &image_info,\n                                        &document_info,\n                                        &media_metadata_service,\n                                        &media_rename_suggestions,\n                                        &entry_key](const FileEntry& entry) -> std::string {\n            const std::string key = entry_key(entry);\n            if (allow_image_renames) {\n                if (const auto it = image_info.find(key); it != image_info.end()) {\n                    return it->second.suggested_name;\n                }\n            }\n            if (allow_document_renames) {\n                if (const auto it = document_info.find(key); it != document_info.end()) {\n                    return it->second.suggested_name;\n                }\n            }\n            if (add_audio_video_metadata_to_filename &&\n                media_metadata_service &&\n                entry.type == FileType::File) {\n                const auto cache_it = media_rename_suggestions.find(key);\n                if (cache_it != media_rename_suggestions.end()) {\n                    return cache_it->second;\n                }\n                std::string suggestion;\n                if (MediaRenameMetadataService::is_supported_media(Utils::utf8_to_path(entry.full_path))) {\n                    if (const auto suggested = media_metadata_service->suggest_name(\n                            Utils::utf8_to_path(entry.full_path))) {\n                        suggestion = *suggested;\n                    }\n                }\n                media_rename_suggestions.emplace(key, suggestion);\n                return suggestion;\n            }\n            return std::string();\n        };\n\n        auto apply_image_dates = [this, add_image_date_to_category, &image_dates, &file_key,\n                                  &resolve_entry_for_storage, &image_metadata_service](std::vector<CategorizedFile>& results) {\n            if (!add_image_date_to_category) {\n                return;\n            }\n            for (auto& entry : results) {\n                if (entry.type != FileType::File) {\n                    continue;\n                }\n                const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                       Utils::utf8_to_path(entry.file_name);\n                if (!LlavaImageAnalyzer::is_supported_image(full_path)) {\n                    continue;\n                }\n                const std::string key = file_key(entry);\n                auto it = image_dates.find(key);\n                if (it == image_dates.end() && image_metadata_service) {\n                    if (const auto date = image_metadata_service->extract_capture_date(full_path)) {\n                        it = image_dates.emplace(key, *date).first;\n                    }\n                }\n                if (it == image_dates.end() || it->second.empty()) {\n                    continue;\n                }\n                if (entry.category.empty()) {\n                    continue;\n                }\n                const std::string suffix = \"_\" + it->second;\n                if (entry.category.size() >= suffix.size() &&\n                    entry.category.compare(entry.category.size() - suffix.size(), suffix.size(), suffix) == 0) {\n                    continue;\n                }\n                entry.category += suffix;\n                if (entry.canonical_category.empty()) {\n                    entry.canonical_category = entry.category.substr(0, entry.category.size() - suffix.size());\n                }\n                entry.canonical_category += suffix;\n\n                DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry);\n                const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n                db_manager.insert_or_update_file_with_categorization(\n                    entry.file_name,\n                    file_type_label,\n                    entry.file_path,\n                    resolved,\n                    entry.used_consistency_hints,\n                    entry.suggested_name,\n                    entry.rename_only,\n                    entry.rename_applied);\n            }\n        };\n\n        auto apply_document_dates = [this, add_document_date, &document_dates, &file_key,\n                                     &resolve_entry_for_storage](std::vector<CategorizedFile>& results) {\n            if (!add_document_date || document_dates.empty()) {\n                return;\n            }\n            for (auto& entry : results) {\n                if (entry.type != FileType::File) {\n                    continue;\n                }\n                const auto full_path = Utils::utf8_to_path(entry.file_path) /\n                                       Utils::utf8_to_path(entry.file_name);\n                if (!DocumentTextAnalyzer::is_supported_document(full_path)) {\n                    continue;\n                }\n                const std::string key = file_key(entry);\n                auto it = document_dates.find(key);\n                if (it == document_dates.end()) {\n                    if (const auto date = DocumentTextAnalyzer::extract_creation_date(full_path)) {\n                        it = document_dates.emplace(key, *date).first;\n                    }\n                }\n                if (it == document_dates.end() || it->second.empty()) {\n                    continue;\n                }\n                if (entry.category.empty()) {\n                    continue;\n                }\n                const std::string suffix = \"_\" + it->second;\n                if (entry.category.size() >= suffix.size() &&\n                    entry.category.compare(entry.category.size() - suffix.size(), suffix.size(), suffix) == 0) {\n                    continue;\n                }\n                entry.category += suffix;\n                if (entry.canonical_category.empty()) {\n                    entry.canonical_category = entry.category.substr(0, entry.category.size() - suffix.size());\n                }\n                entry.canonical_category += suffix;\n\n                DatabaseManager::ResolvedCategory resolved = resolve_entry_for_storage(entry);\n                const std::string file_type_label = (entry.type == FileType::Directory) ? \"D\" : \"F\";\n                db_manager.insert_or_update_file_with_categorization(\n                    entry.file_name,\n                    file_type_label,\n                    entry.file_path,\n                    resolved,\n                    entry.used_consistency_hints,\n                    entry.suggested_name,\n                    entry.rename_only,\n                    entry.rename_applied);\n            }\n        };\n\n        std::vector<CategorizedFile> other_results;\n        if (!stop_requested && !other_entries.empty()) {\n            other_results = categorization_service.categorize_entries(\n                other_entries,\n                using_local_llm,\n                stop_analysis,\n                [this](const std::string& message) { append_progress(message); },\n                [this](const FileEntry& entry) {\n                    mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry);\n                    const QString type_label = entry.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\");\n                    append_progress(to_utf8(tr(\"[SORT] %1 (%2)\")\n                                                .arg(QString::fromStdString(entry.file_name), type_label)));\n                },\n                [this](const FileEntry& entry) {\n                    mark_progress_stage_item_completed(ProgressStageId::Categorization, entry);\n                },\n                [this](const CategorizedFile& entry, const std::string& reason) {\n                    notify_recategorization_reset(entry, reason);\n                },\n                [this]() { return make_llm_client(); },\n                {},\n                suggested_name_provider);\n        }\n        apply_image_dates(other_results);\n        apply_document_dates(other_results);\n        update_stop();\n\n        std::vector<CategorizedFile> image_results;\n        if (analyze_images && !analyzed_image_entries.empty()) {\n            if (rename_images_only) {\n                image_results.reserve(analyzed_image_entries.size());\n                for (const auto& entry : analyzed_image_entries) {\n                    const auto entry_path = Utils::utf8_to_path(entry.full_path);\n                    CategorizedFile result{Utils::path_to_utf8(entry_path.parent_path()),\n                                           entry.file_name,\n                                           entry.type,\n                                           \"\", \"\", 0};\n                    result.rename_only = true;\n                    if (offer_image_renames || rename_images_only) {\n                        const auto info_it = image_info.find(entry_key(entry));\n                        if (info_it != image_info.end()) {\n                            result.suggested_name = info_it->second.suggested_name;\n                        }\n                    }\n                    image_results.push_back(std::move(result));\n                }\n            } else if (!image_entries_for_llm.empty()) {\n                const bool stop_before_image_categorization = stop_requested;\n                const bool bypass_stop = stop_before_image_categorization && other_results.empty();\n                std::atomic<bool> image_stop{false};\n                std::atomic<bool>& stop_flag = bypass_stop ? image_stop : stop_analysis;\n\n                auto override_provider = [&image_info, &entry_key](const FileEntry& entry)\n                    -> std::optional<CategorizationService::PromptOverride> {\n                    const auto it = image_info.find(entry_key(entry));\n                    if (it == image_info.end()) {\n                        return std::nullopt;\n                    }\n                    return CategorizationService::PromptOverride{it->second.prompt_name, it->second.prompt_path};\n                };\n\n                image_results = categorization_service.categorize_entries(\n                    image_entries_for_llm,\n                    using_local_llm,\n                    stop_flag,\n                    [this](const std::string& message) { append_progress(message); },\n                    [this](const FileEntry& entry) {\n                        mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry);\n                        const QString type_label = entry.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\");\n                        append_progress(to_utf8(tr(\"[SORT] %1 (%2)\")\n                                                    .arg(QString::fromStdString(entry.file_name), type_label)));\n                    },\n                    [this](const FileEntry& entry) {\n                        mark_progress_stage_item_completed(ProgressStageId::Categorization, entry);\n                    },\n                    [this](const CategorizedFile& entry, const std::string& reason) {\n                        notify_recategorization_reset(entry, reason);\n                    },\n                    [this]() { return make_llm_client(); },\n                    override_provider,\n                    suggested_name_provider);\n\n                update_stop();\n            }\n        }\n        apply_image_dates(image_results);\n\n        std::vector<CategorizedFile> document_results;\n        if (analyze_documents && !analyzed_document_entries.empty()) {\n            if (rename_documents_only) {\n                document_results.reserve(analyzed_document_entries.size());\n                for (const auto& entry : analyzed_document_entries) {\n                    const auto entry_path = Utils::utf8_to_path(entry.full_path);\n                    CategorizedFile result{Utils::path_to_utf8(entry_path.parent_path()),\n                                           entry.file_name,\n                                           entry.type,\n                                           \"\", \"\", 0};\n                    result.rename_only = true;\n                    if (offer_document_renames || rename_documents_only) {\n                        const auto info_it = document_info.find(entry_key(entry));\n                        if (info_it != document_info.end()) {\n                            result.suggested_name = info_it->second.suggested_name;\n                        }\n                    }\n                    document_results.push_back(std::move(result));\n                }\n            } else if (!document_entries_for_llm.empty()) {\n                const bool stop_before_doc_categorization = stop_requested;\n                const bool bypass_stop = stop_before_doc_categorization &&\n                                         other_results.empty() &&\n                                         image_results.empty();\n                std::atomic<bool> doc_stop{false};\n                std::atomic<bool>& stop_flag = bypass_stop ? doc_stop : stop_analysis;\n\n                auto override_provider = [&document_info, &entry_key](const FileEntry& entry)\n                    -> std::optional<CategorizationService::PromptOverride> {\n                    const auto it = document_info.find(entry_key(entry));\n                    if (it == document_info.end()) {\n                        return std::nullopt;\n                    }\n                    return CategorizationService::PromptOverride{it->second.prompt_name, it->second.prompt_path};\n                };\n\n                document_results = categorization_service.categorize_entries(\n                    document_entries_for_llm,\n                    using_local_llm,\n                    stop_flag,\n                    [this](const std::string& message) { append_progress(message); },\n                    [this](const FileEntry& entry) {\n                        mark_progress_stage_item_in_progress(ProgressStageId::Categorization, entry);\n                        const QString type_label = entry.type == FileType::Directory ? tr(\"Directory\") : tr(\"File\");\n                        append_progress(to_utf8(tr(\"[SORT] %1 (%2)\")\n                                                    .arg(QString::fromStdString(entry.file_name), type_label)));\n                    },\n                    [this](const FileEntry& entry) {\n                        mark_progress_stage_item_completed(ProgressStageId::Categorization, entry);\n                    },\n                    [this](const CategorizedFile& entry, const std::string& reason) {\n                        notify_recategorization_reset(entry, reason);\n                    },\n                    [this]() { return make_llm_client(); },\n                    override_provider,\n                    suggested_name_provider);\n            }\n        }\n\n        apply_document_dates(document_results);\n\n        update_stop();\n\n        new_files_with_categories.clear();\n        new_files_with_categories.reserve(other_results.size() + image_results.size() + document_results.size());\n        new_files_with_categories.insert(new_files_with_categories.end(),\n                                         other_results.begin(),\n                                         other_results.end());\n        new_files_with_categories.insert(new_files_with_categories.end(),\n                                         image_results.begin(),\n                                         image_results.end());\n        new_files_with_categories.insert(new_files_with_categories.end(),\n                                         document_results.begin(),\n                                         document_results.end());\n\n        core_logger->info(\"Categorization produced {} new record(s).\",\n                          new_files_with_categories.size());\n\n        already_categorized_files.insert(\n            already_categorized_files.end(),\n            new_files_with_categories.begin(),\n            new_files_with_categories.end());\n\n        persist_analysis_results(new_files_with_categories);\n\n        std::vector<CategorizedFile> review_entries = already_categorized_files;\n        if ((rename_images_only || rename_documents_only) && !pending_renames.empty()) {\n            review_entries.insert(review_entries.end(),\n                                  pending_renames.begin(),\n                                  pending_renames.end());\n        }\n\n        const auto actual_files = results_coordinator.list_directory(get_folder_path(), scan_options);\n        new_files_to_sort = results_coordinator.compute_files_to_sort(get_folder_path(),\n                                                                      scan_options,\n                                                                      actual_files,\n                                                                      review_entries,\n                                                                      settings.get_include_subdirectories());\n        core_logger->debug(\"{} file(s) queued for sorting after analysis.\",\n                           new_files_to_sort.size());\n\n        const bool cancelled = stop_requested;\n        run_on_ui([this, cancelled]() {\n            if (cancelled && new_files_to_sort.empty()) {\n                handle_analysis_cancelled();\n            } else {\n                handle_analysis_finished();\n            }\n        });\n    } catch (const std::exception& ex) {\n        core_logger->error(\"Exception during analysis: {}\", ex.what());\n        const bool cancelled =\n            stop_analysis.load() ||\n            (text_cpu_fallback_choice_.has_value() && !text_cpu_fallback_choice_.value());\n        if (cancelled) {\n            run_on_ui([this]() { handle_analysis_cancelled(); });\n        } else {\n            run_on_ui([this, message = std::string(\"Analysis error: \") + ex.what()]() {\n                handle_analysis_failure(message);\n            });\n        }\n    }\n}\n\n\nvoid MainApp::run_consistency_pass()\n{\n    if (stop_analysis.load() || already_categorized_files.empty()) {\n        return;\n    }\n\n    text_cpu_fallback_choice_.reset();\n\n    auto progress_sink = [this](const std::string& message) {\n        run_on_ui([this, message]() {\n            if (progress_dialog) {\n                progress_dialog->append_text(message);\n            }\n        });\n    };\n\n    consistency_pass_service.run(\n        already_categorized_files,\n        new_files_with_categories,\n        [this]() { return make_llm_client(); },\n        stop_analysis,\n        settings.get_category_language(),\n        progress_sink);\n}\n\nvoid MainApp::handle_development_prompt_logging(bool checked)\n{\n    if (!development_mode_) {\n        if (development_prompt_logging_action) {\n            QSignalBlocker blocker(development_prompt_logging_action);\n            development_prompt_logging_action->setChecked(false);\n        }\n        development_prompt_logging_enabled_ = false;\n        apply_development_logging();\n        return;\n    }\n\n    development_prompt_logging_enabled_ = checked;\n    settings.set_development_prompt_logging(checked);\n    apply_development_logging();\n}\n\nvoid MainApp::request_stop_analysis()\n{\n    stop_analysis = true;\n    statusBar()->showMessage(tr(\"Cancelling analysis…\"), 4000);\n    status_is_ready_ = false;\n}\n\nbool MainApp::prompt_text_cpu_fallback(const std::string& reason)\n{\n    if (text_cpu_fallback_choice_.has_value()) {\n        return text_cpu_fallback_choice_.value();\n    }\n\n    auto show_dialog = [this]() -> bool {\n        QMessageBox box(this);\n        box.setIcon(QMessageBox::Question);\n        box.setWindowTitle(tr(\"Switch local AI to CPU?\"));\n        box.setText(tr(\"The local model encountered a GPU error or ran out of memory.\"));\n        box.setInformativeText(tr(\"Retry on CPU instead? Cancel will stop this analysis.\"));\n        box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);\n        box.setDefaultButton(QMessageBox::Ok);\n        return box.exec() == QMessageBox::Ok;\n    };\n\n    bool decision = false;\n    if (QThread::currentThread() == thread()) {\n        decision = show_dialog();\n    } else {\n        QMetaObject::invokeMethod(\n            this,\n            [&decision, show_dialog]() mutable { decision = show_dialog(); },\n            Qt::BlockingQueuedConnection);\n    }\n\n    text_cpu_fallback_choice_ = decision;\n\n    if (!decision) {\n        stop_analysis = true;\n        append_progress(to_utf8(tr(\"[WARN] GPU fallback to CPU declined. Cancelling analysis.\")));\n        run_on_ui([this]() { request_stop_analysis(); });\n        if (core_logger && !reason.empty()) {\n            core_logger->warn(\"GPU fallback declined: {}\", reason);\n        }\n        return false;\n    }\n\n    if (core_logger && !reason.empty()) {\n        core_logger->warn(\"GPU fallback accepted: {}\", reason);\n    }\n    return true;\n}\n\n\nvoid MainApp::stop_running_analysis()\n{\n    stop_analysis = true;\n    if (analyze_thread.joinable()) {\n        analyze_thread.join();\n    }\n    if (progress_dialog) {\n        progress_dialog->hide();\n        progress_dialog.reset();\n    }\n}\n\n\nvoid MainApp::show_llm_selection_dialog()\n{\n    try {\n        auto dialog = std::make_unique<LLMSelectionDialog>(settings, this);\n        if (dialog->exec() == QDialog::Accepted) {\n            settings.set_openai_api_key(dialog->get_openai_api_key());\n            settings.set_openai_model(dialog->get_openai_model());\n            settings.set_gemini_api_key(dialog->get_gemini_api_key());\n            settings.set_gemini_model(dialog->get_gemini_model());\n            settings.set_llm_choice(dialog->get_selected_llm_choice());\n            settings.set_llm_downloads_expanded(dialog->get_llm_downloads_expanded());\n            if (dialog->get_selected_llm_choice() == LLMChoice::Custom) {\n                settings.set_active_custom_llm_id(dialog->get_selected_custom_llm_id());\n            } else {\n                settings.set_active_custom_llm_id(\"\");\n            }\n            if (dialog->get_selected_llm_choice() == LLMChoice::Remote_Custom) {\n                settings.set_active_custom_api_id(dialog->get_selected_custom_api_id());\n            } else {\n                settings.set_active_custom_api_id(\"\");\n            }\n            using_local_llm = !is_remote_choice(settings.get_llm_choice());\n            settings.save();\n        }\n    } catch (const std::exception& ex) {\n        show_error_dialog(fmt::format(\"LLM selection error: {}\", ex.what()));\n    }\n}\n\nvoid MainApp::show_suitability_benchmark_dialog(bool /*auto_start*/)\n{\n    if (benchmark_dialog) {\n        benchmark_dialog->raise();\n        benchmark_dialog->activateWindow();\n        return;\n    }\n\n    benchmark_dialog = std::make_unique<SuitabilityBenchmarkDialog>(settings, this);\n    QObject::connect(benchmark_dialog.get(), &QDialog::finished, this, [this]() {\n        benchmark_dialog.reset();\n    });\n    benchmark_dialog->show();\n}\n\nvoid MainApp::maybe_show_suitability_benchmark()\n{\n    if (settings.get_suitability_benchmark_completed()) {\n        return;\n    }\n    if (settings.get_suitability_benchmark_suppressed()) {\n        return;\n    }\n    if (!default_text_llm_files_available() && !visual_llm_files_available()) {\n        return;\n    }\n\n    QTimer::singleShot(0, this, [this]() {\n        show_suitability_benchmark_dialog(false);\n    });\n}\n\n\nvoid MainApp::on_about_activate()\n{\n    MainAppHelpActions::show_about(this);\n}\n\nbool MainApp::should_log_prompts() const\n{\n    return development_mode_ && development_prompt_logging_enabled_;\n}\n\nvoid MainApp::apply_development_logging()\n{\n    consistency_pass_service.set_prompt_logging_enabled(should_log_prompts());\n}\n\n\nstd::unique_ptr<ILLMClient> MainApp::make_llm_client()\n{\n    const LLMChoice choice = settings.get_llm_choice();\n\n    if (choice == LLMChoice::Remote_OpenAI) {\n        const std::string api_key = settings.get_openai_api_key();\n        const std::string model = settings.get_openai_model();\n        if (api_key.empty()) {\n            throw std::runtime_error(\"OpenAI API key is missing. Please add it from Select LLM.\");\n        }\n        CategorizationSession session(api_key, model);\n        auto client = std::make_unique<LLMClient>(session.create_llm_client());\n        client->set_prompt_logging_enabled(should_log_prompts());\n        return client;\n    }\n\n    if (choice == LLMChoice::Remote_Gemini) {\n        const std::string api_key = settings.get_gemini_api_key();\n        const std::string model = settings.get_gemini_model();\n        if (api_key.empty()) {\n            throw std::runtime_error(\"Gemini API key is missing. Please add it from Select LLM.\");\n        }\n        auto client = std::make_unique<GeminiClient>(api_key, model);\n        client->set_prompt_logging_enabled(should_log_prompts());\n        return client;\n    }\n\n    if (choice == LLMChoice::Remote_Custom) {\n        const auto id = settings.get_active_custom_api_id();\n        const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id);\n        if (endpoint.id.empty() || endpoint.base_url.empty() || endpoint.model.empty()) {\n            throw std::runtime_error(\"Selected custom API endpoint is missing or invalid. Please re-select it.\");\n        }\n        auto client = std::make_unique<LLMClient>(endpoint.api_key, endpoint.model, endpoint.base_url);\n        client->set_prompt_logging_enabled(should_log_prompts());\n        return client;\n    }\n\n    if (choice == LLMChoice::Custom) {\n        const auto id = settings.get_active_custom_llm_id();\n        const CustomLLM custom = settings.find_custom_llm(id);\n        if (custom.id.empty() || custom.path.empty()) {\n            throw std::runtime_error(\"Selected custom LLM is missing or invalid. Please re-select it.\");\n        }\n        auto client = std::make_unique<LocalLLMClient>(\n            custom.path,\n            [this](const std::string& reason) { return prompt_text_cpu_fallback(reason); });\n        client->set_status_callback([this](LocalLLMClient::Status status) {\n            if (status == LocalLLMClient::Status::GpuFallbackToCpu) {\n                report_progress(to_utf8(tr(\"[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).\")));\n            }\n        });\n        client->set_prompt_logging_enabled(should_log_prompts());\n        return client;\n    }\n\n    const char* env_var = nullptr;\n    switch (choice) {\n        case LLMChoice::Local_3b:\n            env_var = \"LOCAL_LLM_3B_DOWNLOAD_URL\";\n            break;\n        case LLMChoice::Local_3b_legacy:\n            env_var = \"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\";\n            break;\n        case LLMChoice::Local_7b:\n            env_var = \"LOCAL_LLM_7B_DOWNLOAD_URL\";\n            break;\n        default:\n            break;\n    }\n\n    const char* env_url = env_var ? std::getenv(env_var) : nullptr;\n    if (!env_url) {\n        throw std::runtime_error(\"Required environment variable for selected model is not set\");\n    }\n\n    auto client = std::make_unique<LocalLLMClient>(\n        Utils::make_default_path_to_file_from_download_url(env_url),\n        [this](const std::string& reason) { return prompt_text_cpu_fallback(reason); });\n    client->set_status_callback([this](LocalLLMClient::Status status) {\n        if (status == LocalLLMClient::Status::GpuFallbackToCpu) {\n            report_progress(to_utf8(tr(\"[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).\")));\n        }\n    });\n    client->set_prompt_logging_enabled(should_log_prompts());\n    return client;\n}\n\nvoid MainApp::notify_recategorization_reset(const std::vector<CategorizedFile>& entries,\n                                            const std::string& reason)\n{\n    if (entries.empty()) {\n        return;\n    }\n\n    auto shared_entries = std::make_shared<std::vector<CategorizedFile>>(entries);\n    auto shared_reason = std::make_shared<std::string>(reason);\n\n    run_on_ui([this, shared_entries, shared_reason]() {\n        if (!progress_dialog) {\n            return;\n        }\n        for (const auto& entry : *shared_entries) {\n            const QString message = tr(\"[WARN] %1 will be re-categorized: %2\")\n                                        .arg(QString::fromStdString(entry.file_name),\n                                             QString::fromStdString(*shared_reason));\n            progress_dialog->append_text(to_utf8(message));\n        }\n    });\n}\n\nvoid MainApp::notify_recategorization_reset(const CategorizedFile& entry,\n                                            const std::string& reason)\n{\n    notify_recategorization_reset(std::vector<CategorizedFile>{entry}, reason);\n}\n\n\n\n\nvoid MainApp::show_results_dialog(const std::vector<CategorizedFile>& results)\n{\n    try {\n        const bool show_subcategory = use_subcategories_checkbox->isChecked();\n        const std::string undo_dir = settings.get_config_dir() + \"/undo\";\n        categorization_dialog = std::make_unique<CategorizationDialog>(&db_manager,\n                                                                       show_subcategory,\n                                                                       undo_dir,\n                                                                       settings.get_category_language(),\n                                                                       this);\n        categorization_dialog->show_results(results,\n                                            get_folder_path(),\n                                            settings.get_include_subdirectories(),\n                                            settings.get_offer_rename_images(),\n                                            settings.get_offer_rename_documents());\n\n        const int newly_analyzed = static_cast<int>(std::count_if(\n            results.begin(),\n            results.end(),\n            [](const CategorizedFile& file) { return !file.from_cache; }));\n        if (newly_analyzed > 0) {\n            record_categorized_metrics(newly_analyzed);\n        }\n    } catch (const std::exception& ex) {\n        if (ui_logger) {\n            ui_logger->error(\"Error showing results dialog: {}\", ex.what());\n        }\n        show_error_dialog(fmt::format(\"Failed to show results dialog: {}\", ex.what()));\n    }\n}\n\n\nvoid MainApp::show_error_dialog(const std::string& message)\n{\n    DialogUtils::show_error_dialog(this, message);\n}\n\n\nvoid MainApp::report_progress(const std::string& message)\n{\n    run_on_ui([this, message]() {\n        if (progress_dialog) {\n            progress_dialog->append_text(message);\n        }\n    });\n}\n\n\nstd::string MainApp::get_folder_path() const\n{\n    const QByteArray bytes = path_entry->text().toUtf8();\n    return normalize_directory_path(\n        std::string(bytes.constData(), static_cast<std::size_t>(bytes.size())));\n}\n\n\nvoid MainApp::run_on_ui(std::function<void()> func)\n{\n    QMetaObject::invokeMethod(\n        this,\n        [fn = std::move(func)]() mutable {\n            if (fn) {\n                fn();\n            }\n        },\n        Qt::QueuedConnection);\n}\n\nvoid MainApp::run_on_ui_blocking(std::function<void()> func)\n{\n    if (QThread::currentThread() == thread()) {\n        if (func) {\n            func();\n        }\n        return;\n    }\n\n    QMetaObject::invokeMethod(\n        this,\n        [fn = std::move(func)]() mutable {\n            if (fn) {\n                fn();\n            }\n        },\n        Qt::BlockingQueuedConnection);\n}\n\nvoid MainApp::changeEvent(QEvent* event)\n{\n    QMainWindow::changeEvent(event);\n    if (event && event->type() == QEvent::LanguageChange) {\n        retranslate_ui();\n    }\n}\n\n\nvoid MainApp::closeEvent(QCloseEvent* event)\n{\n    stop_running_analysis();\n    save_settings();\n    QMainWindow::closeEvent(event);\n}\n"
  },
  {
    "path": "app/lib/MainAppEditActions.cpp",
    "content": "#include \"MainAppEditActions.hpp\"\n\n#include <QClipboard>\n#include <QGuiApplication>\n#include <QLineEdit>\n\nvoid MainAppEditActions::on_paste(QLineEdit* line_edit)\n{\n    if (!line_edit) {\n        return;\n    }\n    const QString clipboard_text = QGuiApplication::clipboard()->text(QClipboard::Clipboard);\n    if (!clipboard_text.isEmpty()) {\n        line_edit->insert(clipboard_text);\n    }\n}\n\n\nvoid MainAppEditActions::on_copy(QLineEdit* line_edit)\n{\n    if (!line_edit) {\n        return;\n    }\n    const QString selected_text = get_selection(line_edit, false);\n    if (!selected_text.isEmpty()) {\n        copy_to_clipboard(selected_text);\n    }\n}\n\n\nvoid MainAppEditActions::on_cut(QLineEdit* line_edit)\n{\n    if (!line_edit) {\n        return;\n    }\n    const QString selected_text = get_selection(line_edit, true);\n    if (!selected_text.isEmpty()) {\n        copy_to_clipboard(selected_text);\n    }\n}\n\n\nvoid MainAppEditActions::on_delete(QLineEdit* line_edit)\n{\n    if (!line_edit) {\n        return;\n    }\n    get_selection(line_edit, true);\n}\n\n\nvoid MainAppEditActions::copy_to_clipboard(const QString& text)\n{\n    QGuiApplication::clipboard()->setText(text, QClipboard::Clipboard);\n}\n\n\nQString MainAppEditActions::get_selection(QLineEdit* line_edit, bool delete_selection)\n{\n    if (!line_edit) {\n        return {};\n    }\n\n    const QString selected_text = line_edit->selectedText();\n    if (selected_text.isEmpty()) {\n        return {};\n    }\n\n    if (delete_selection) {\n        line_edit->insert(QString());\n    }\n\n    return selected_text;\n}\n"
  },
  {
    "path": "app/lib/MainAppHelpActions.cpp",
    "content": "#include \"MainAppHelpActions.hpp\"\n#include \"AppInfo.hpp\"\n\n#include <app_version.hpp>\n\n#include <QDialog>\n#include <QDialogButtonBox>\n#include <QLabel>\n#include <QPixmap>\n#include <QTabWidget>\n#include <QVBoxLayout>\n#include <QString>\n#include <QDesktopServices>\n#include <QProcess>\n#include <QUrl>\n\nnamespace {\n\nQString support_page_url_string()\n{\n    return QStringLiteral(\"https://filesorter.app/donate/\");\n}\n\nbool open_external_url(const QUrl& url)\n{\n    if (QDesktopServices::openUrl(url)) {\n        return true;\n    }\n#if defined(Q_OS_LINUX)\n    return QProcess::startDetached(QStringLiteral(\"xdg-open\"), {url.toString(QUrl::FullyEncoded)});\n#else\n    return false;\n#endif\n}\n\n} // namespace\n\nvoid MainAppHelpActions::show_about(QWidget* parent)\n{\n    QDialog dialog(parent);\n    const QString display_name = app_display_name();\n    dialog.setWindowTitle(QObject::tr(\"About %1\").arg(display_name));\n    dialog.resize(600, 420);\n\n    auto* layout = new QVBoxLayout(&dialog);\n    auto* tabs = new QTabWidget(&dialog);\n    layout->addWidget(tabs);\n\n    // About tab\n    auto* about_tab = new QWidget(&dialog);\n    auto* about_layout = new QVBoxLayout(about_tab);\n    about_layout->setSpacing(8);\n\n    if (QPixmap logo_pix(QStringLiteral(\":/net/quicknode/AIFileSorter/images/logo.png\")); !logo_pix.isNull()) {\n        auto* logo_label = new QLabel(about_tab);\n        logo_label->setAlignment(Qt::AlignHCenter);\n        logo_label->setPixmap(logo_pix.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation));\n        about_layout->addWidget(logo_label);\n    }\n\n    auto* program_name = new QLabel(QStringLiteral(\"<h2>%1</h2>\").arg(display_name.toHtmlEscaped()), about_tab);\n    program_name->setAlignment(Qt::AlignHCenter);\n    about_layout->addWidget(program_name);\n\n    const QString version_text = QStringLiteral(\"Version: %1\").arg(QString::fromStdString(APP_VERSION.to_string()));\n    auto* version_label = new QLabel(version_text, about_tab);\n    version_label->setAlignment(Qt::AlignHCenter);\n    about_layout->addWidget(version_label);\n\n    auto* copyright_label =\n        new QLabel(QStringLiteral(\"© 2024-2026 QuickNode. All rights reserved.\"), about_tab);\n    copyright_label->setAlignment(Qt::AlignHCenter);\n    about_layout->addWidget(copyright_label);\n\n    auto* website_label = new QLabel(QStringLiteral(\n        \"<a href=\\\"https://www.filesorter.app\\\">Visit the Website</a>\"), about_tab);\n    website_label->setOpenExternalLinks(true);\n    website_label->setAlignment(Qt::AlignHCenter);\n    about_layout->addWidget(website_label);\n\n    about_layout->addStretch(1);\n    tabs->addTab(about_tab, QObject::tr(\"About\"));\n\n    // Credits tab\n    auto* credits_tab = new QWidget(&dialog);\n    auto* credits_layout = new QVBoxLayout(credits_tab);\n    credits_layout->setSpacing(8);\n\n    if (QPixmap qn_logo_pix(QStringLiteral(\":/net/quicknode/AIFileSorter/images/qn_logo.png\")); !qn_logo_pix.isNull()) {\n        auto* qn_logo = new QLabel(credits_tab);\n        qn_logo->setAlignment(Qt::AlignHCenter);\n        qn_logo->setPixmap(qn_logo_pix.scaled(160, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation));\n        credits_layout->addWidget(qn_logo);\n    }\n\n    auto* author_label = new QLabel(QStringLiteral(\"Author: hyperfield\"), credits_tab);\n    author_label->setAlignment(Qt::AlignHCenter);\n    credits_layout->addWidget(author_label);\n\n    auto* author_details = new QLabel(QStringLiteral(\n        \"Author's brand name is <a href=\\\"https://quicknode.net\\\">QN (QuickNode)</a>.<br>\"\n        \"Source code on GitHub is <a href=\\\"https://github.com/hyperfield/ai-file-sorter\\\">here</a>.\"), credits_tab);\n    author_details->setOpenExternalLinks(true);\n    author_details->setAlignment(Qt::AlignHCenter);\n    author_details->setWordWrap(true);\n    credits_layout->addWidget(author_details);\n\n    credits_layout->addStretch(1);\n    tabs->addTab(credits_tab, QObject::tr(\"Credits\"));\n\n    auto* button_box = new QDialogButtonBox(QDialogButtonBox::Close, &dialog);\n    QObject::connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::accept);\n    layout->addWidget(button_box);\n\n    dialog.exec();\n}\n\nvoid MainAppHelpActions::show_agpl_info(QWidget* parent)\n{\n    QDialog dialog(parent);\n    dialog.setWindowTitle(QObject::tr(\"About the AGPL License\"));\n    dialog.resize(520, 320);\n\n    auto* layout = new QVBoxLayout(&dialog);\n\n    auto* summary = new QLabel(QObject::tr(\n        \"AI File Sorter is distributed under the GNU Affero General Public License v3.0.\"\n        \"<br><br>\"\n        \"You can access the full source code at \"\n        \"<a href=\\\"https://github.com/hyperfield/ai-file-sorter\\\">github.com/hyperfield/ai-file-sorter</a>.\"\n        \"<br><br>\"\n        \"A full copy of the license is provided with this application and available online at \"\n        \"<a href=\\\"https://www.gnu.org/licenses/agpl-3.0.html\\\">gnu.org</a>.\"), &dialog);\n    summary->setTextFormat(Qt::RichText);\n    summary->setOpenExternalLinks(true);\n    summary->setWordWrap(true);\n    layout->addWidget(summary);\n\n    layout->addStretch(1);\n\n    auto* button_box = new QDialogButtonBox(QDialogButtonBox::Close, &dialog);\n    QObject::connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::accept);\n    layout->addWidget(button_box);\n\n    dialog.exec();\n}\n\nQString MainAppHelpActions::support_page_url()\n{\n    return support_page_url_string();\n}\n\nbool MainAppHelpActions::open_support_page()\n{\n    const QUrl donation_url(support_page_url_string());\n    return open_external_url(donation_url);\n}\n"
  },
  {
    "path": "app/lib/MainAppUiBuilder.cpp",
    "content": "#include \"MainAppUiBuilder.hpp\"\n#include \"AppInfo.hpp\"\n\n#include \"MainApp.hpp\"\n#include \"MainAppEditActions.hpp\"\n#include \"MainAppHelpActions.hpp\"\n#include \"UiTranslator.hpp\"\n#include \"Language.hpp\"\n#include \"CategoryLanguage.hpp\"\n\n#include <QAction>\n#include <QActionGroup>\n#include <QApplication>\n#include <QCoreApplication>\n#include <QAbstractItemView>\n#include <QCheckBox>\n#include <QDir>\n#include <QDockWidget>\n#include <QFileSystemModel>\n#include <QItemSelectionModel>\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QIcon>\n#include <QLinearGradient>\n#include <QComboBox>\n#include <QFontMetrics>\n#include <QKeySequence>\n#include <QLabel>\n#include <QLineEdit>\n#include <QMenu>\n#include <QMenuBar>\n#include <QMessageBox>\n#include <QObject>\n#include <QPainter>\n#include <QPainterPath>\n#include <QPaintEvent>\n#include <QPen>\n#include <QPushButton>\n#include <QRadioButton>\n#include <QSlider>\n#include <QToolButton>\n#include <QSize>\n#include <QSizePolicy>\n#include <QStackedWidget>\n#include <QStandardItemModel>\n#include <QStyle>\n#include <QStyleOption>\n#include <QTreeView>\n#include <QVBoxLayout>\n#include <QWidget>\n#include <QtGlobal>\n\n#include <algorithm>\n#include <functional>\n\nnamespace {\n\nclass DisclosureToggleButton final : public QToolButton {\npublic:\n    explicit DisclosureToggleButton(QWidget* parent = nullptr)\n        : QToolButton(parent)\n    {\n        setCheckable(true);\n        setToolButtonStyle(Qt::ToolButtonIconOnly);\n        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n        setArrowType(Qt::NoArrow);\n        setAutoRaise(true);\n        setFixedSize(QSize(14, 14));\n    }\n\nprotected:\n    void paintEvent(QPaintEvent*) override\n    {\n        QPainter painter(this);\n        QStyleOption option;\n        option.initFrom(this);\n        option.rect = rect();\n        option.state |= QStyle::State_Children;\n        if (isChecked()) {\n            option.state |= QStyle::State_Open;\n        }\n        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, &painter, this);\n    }\n};\n\nusing MenuIconPainter = std::function<void(QPainter&, const QRectF&, bool)>;\n\nQColor with_enabled_alpha(QColor color, bool enabled, int disabled_alpha = 110)\n{\n    if (!enabled) {\n        color.setAlpha(std::min(color.alpha(), disabled_alpha));\n    }\n    return color;\n}\n\nQIcon draw_menu_icon(MainApp& app, const MenuIconPainter& painter_fn)\n{\n    int target_size = app.style()->pixelMetric(QStyle::PM_SmallIconSize);\n    if (target_size <= 0) {\n        target_size = 16;\n    }\n    const int padding = std::max(4, target_size / 4);\n    const QSize canvas_size(target_size + padding * 2, target_size + padding * 2);\n\n    QIcon icon;\n    for (QIcon::Mode mode : {QIcon::Normal, QIcon::Disabled}) {\n        const bool enabled = mode != QIcon::Disabled;\n        QPixmap canvas(canvas_size);\n        canvas.fill(Qt::transparent);\n\n        QPainter painter(&canvas);\n        painter.setRenderHint(QPainter::Antialiasing, true);\n        painter.setRenderHint(QPainter::TextAntialiasing, true);\n        painter_fn(painter, QRectF(padding, padding, target_size, target_size), enabled);\n        painter.end();\n\n        icon.addPixmap(canvas, mode);\n    }\n\n    return icon;\n}\n\nQPainterPath sparkle_path(const QPointF& center, qreal outer_radius, qreal inner_radius)\n{\n    const qreal diagonal = inner_radius * 0.72;\n    QPainterPath path;\n    path.moveTo(center.x(), center.y() - outer_radius);\n    path.lineTo(center.x() + diagonal, center.y() - diagonal);\n    path.lineTo(center.x() + outer_radius, center.y());\n    path.lineTo(center.x() + diagonal, center.y() + diagonal);\n    path.lineTo(center.x(), center.y() + outer_radius);\n    path.lineTo(center.x() - diagonal, center.y() + diagonal);\n    path.lineTo(center.x() - outer_radius, center.y());\n    path.lineTo(center.x() - diagonal, center.y() - diagonal);\n    path.closeSubpath();\n    return path;\n}\n\nvoid draw_card_label(QPainter& painter,\n                     const QRectF& card_rect,\n                     const QString& text,\n                     const QColor& color,\n                     qreal size_factor)\n{\n    QFont font = QApplication::font();\n    font.setBold(true);\n    font.setPixelSize(std::max(7, static_cast<int>(card_rect.height() * size_factor)));\n    painter.setFont(font);\n    painter.setPen(color);\n    painter.drawText(card_rect, Qt::AlignCenter, text);\n}\n\nvoid draw_translation_cards(QPainter& painter,\n                            const QRectF& rect,\n                            bool enabled,\n                            const QColor& front_start,\n                            const QColor& front_end,\n                            const QColor& front_label,\n                            const QColor& top_start,\n                            const QColor& top_end,\n                            const QColor& top_label,\n                            const QColor& bottom_start,\n                            const QColor& bottom_end,\n                            const QColor& bottom_label)\n{\n    const QRectF top_card(rect.left() + rect.width() * 0.42,\n                          rect.top() + rect.height() * 0.03,\n                          rect.width() * 0.50,\n                          rect.height() * 0.50);\n    const QRectF bottom_card(rect.left() + rect.width() * 0.36,\n                             rect.top() + rect.height() * 0.47,\n                             rect.width() * 0.50,\n                             rect.height() * 0.50);\n    const QRectF front_card(rect.left() + rect.width() * 0.04,\n                            rect.top() + rect.height() * 0.22,\n                            rect.width() * 0.50,\n                            rect.height() * 0.50);\n\n    const auto draw_card = [&](const QRectF& card,\n                               const QColor& start,\n                               const QColor& end,\n                               const QString& label,\n                               const QColor& label_color,\n                               qreal label_size) {\n        QLinearGradient gradient(card.topLeft(), card.bottomRight());\n        gradient.setColorAt(0.0, with_enabled_alpha(start, enabled));\n        gradient.setColorAt(1.0, with_enabled_alpha(end, enabled));\n        painter.setPen(Qt::NoPen);\n        painter.setBrush(gradient);\n        const qreal radius = std::max<qreal>(2.0, card.width() * 0.16);\n        painter.drawRoundedRect(card, radius, radius);\n        draw_card_label(painter, card, label, with_enabled_alpha(label_color, enabled), label_size);\n    };\n\n    draw_card(top_card,\n              top_start,\n              top_end,\n              QString(QChar(0x3042)),\n              top_label,\n              0.44);\n    draw_card(bottom_card,\n              bottom_start,\n              bottom_end,\n              QString(QChar(0x6587)),\n              bottom_label,\n              0.40);\n    draw_card(front_card,\n              front_start,\n              front_end,\n              QStringLiteral(\"A\"),\n              front_label,\n              0.54);\n}\n\nQIcon llm_menu_icon(MainApp& app)\n{\n    return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) {\n        const QPointF main_center(rect.center().x() + rect.width() * 0.06, rect.center().y() - rect.height() * 0.02);\n        const QPointF accent_center(rect.left() + rect.width() * 0.28, rect.top() + rect.height() * 0.28);\n        const qreal main_outer = rect.width() * 0.27;\n        const qreal main_inner = rect.width() * 0.12;\n        const qreal accent_outer = rect.width() * 0.13;\n        const qreal accent_inner = rect.width() * 0.06;\n\n        QLinearGradient main_gradient(main_center.x() - main_outer,\n                                      main_center.y() - main_outer,\n                                      main_center.x() + main_outer,\n                                      main_center.y() + main_outer);\n        main_gradient.setColorAt(0.0, with_enabled_alpha(QColor(\"#ffd866\"), enabled));\n        main_gradient.setColorAt(1.0, with_enabled_alpha(QColor(\"#ff6b9f\"), enabled));\n        painter.setPen(Qt::NoPen);\n        painter.setBrush(main_gradient);\n        painter.drawPath(sparkle_path(main_center, main_outer, main_inner));\n\n        painter.setBrush(with_enabled_alpha(QColor(\"#8a7cff\"), enabled));\n        painter.drawPath(sparkle_path(accent_center, accent_outer, accent_inner));\n        painter.drawEllipse(QRectF(rect.right() - rect.width() * 0.17,\n                                   rect.bottom() - rect.height() * 0.19,\n                                   rect.width() * 0.09,\n                                   rect.width() * 0.09));\n    });\n}\n\nQIcon interface_language_menu_icon(MainApp& app)\n{\n    return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) {\n        draw_translation_cards(painter,\n                               rect,\n                               enabled,\n                               QColor(\"#1a59c9\"),\n                               QColor(\"#1847b7\"),\n                               QColor(\"#d8b4fe\"),\n                               QColor(\"#6677ff\"),\n                               QColor(\"#5160e8\"),\n                               QColor(\"#bcdcff\"),\n                               QColor(\"#4fc0ff\"),\n                               QColor(\"#37a6f5\"),\n                               QColor(\"#dff7ff\"));\n    });\n}\n\nQIcon category_language_menu_icon(MainApp& app)\n{\n    return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) {\n        draw_translation_cards(painter,\n                               rect,\n                               enabled,\n                               QColor(\"#1f2937\"),\n                               QColor(\"#374151\"),\n                               QColor(\"#f9fafb\"),\n                               QColor(\"#f3f4f6\"),\n                               QColor(\"#d7dbe3\"),\n                               QColor(\"#1f2937\"),\n                               QColor(\"#6b7280\"),\n                               QColor(\"#4b5563\"),\n                               QColor(\"#f9fafb\"));\n    });\n}\n\nQPainterPath tag_path(const QRectF& rect)\n{\n    QPainterPath path;\n    path.moveTo(rect.left() + rect.width() * 0.14, rect.top() + rect.height() * 0.24);\n    path.lineTo(rect.left() + rect.width() * 0.66, rect.top() + rect.height() * 0.24);\n    path.lineTo(rect.right() - rect.width() * 0.06, rect.center().y());\n    path.lineTo(rect.left() + rect.width() * 0.66, rect.bottom() - rect.height() * 0.24);\n    path.lineTo(rect.left() + rect.width() * 0.14, rect.bottom() - rect.height() * 0.24);\n    path.closeSubpath();\n    return path;\n}\n\nQIcon whitelist_menu_icon(MainApp& app)\n{\n    return draw_menu_icon(app, [](QPainter& painter, const QRectF& rect, bool enabled) {\n        const QRectF rear_tag = rect.adjusted(rect.width() * 0.12, rect.height() * 0.06,\n                                              -rect.width() * 0.08, -rect.height() * 0.14);\n        const QRectF front_tag = rect.adjusted(rect.width() * 0.02, rect.height() * 0.16,\n                                               -rect.width() * 0.18, -rect.height() * 0.04);\n\n        painter.setPen(Qt::NoPen);\n        painter.setBrush(with_enabled_alpha(QColor(\"#f472b6\"), enabled, 95));\n        painter.drawPath(tag_path(rear_tag));\n\n        QLinearGradient gradient(front_tag.topLeft(), front_tag.bottomRight());\n        gradient.setColorAt(0.0, with_enabled_alpha(QColor(\"#ffe08a\"), enabled));\n        gradient.setColorAt(1.0, with_enabled_alpha(QColor(\"#ffc857\"), enabled));\n        painter.setBrush(gradient);\n        painter.setPen(QPen(with_enabled_alpha(QColor(\"#1f2937\"), enabled), 1.1,\n                            Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));\n        painter.drawPath(tag_path(front_tag));\n\n        painter.save();\n        painter.setCompositionMode(QPainter::CompositionMode_Clear);\n        painter.setPen(Qt::NoPen);\n        painter.setBrush(Qt::transparent);\n        painter.drawEllipse(QRectF(front_tag.left() + front_tag.width() * 0.12,\n                                   front_tag.center().y() - front_tag.height() * 0.09,\n                                   front_tag.width() * 0.13,\n                                   front_tag.width() * 0.13));\n        painter.restore();\n\n        QPainterPath check;\n        check.moveTo(front_tag.left() + front_tag.width() * 0.40, front_tag.center().y());\n        check.lineTo(front_tag.left() + front_tag.width() * 0.50, front_tag.center().y() + front_tag.height() * 0.12);\n        check.lineTo(front_tag.left() + front_tag.width() * 0.68, front_tag.center().y() - front_tag.height() * 0.12);\n        painter.setPen(QPen(with_enabled_alpha(QColor(\"#1f2937\"), enabled), 1.5,\n                            Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));\n        painter.drawPath(check);\n    });\n}\n\n} // namespace\n\nvoid MainAppUiBuilder::build(MainApp& app) {\n    build_central_panel(app);\n    build_menus(app);\n    app.analysis_in_progress_ = false;\n    app.status_is_ready_ = true;\n}\n\nvoid MainAppUiBuilder::build_central_panel(MainApp& app) {\n    app.setWindowTitle(app_display_name());\n    app.resize(1000, 800);\n\n    QWidget* central = new QWidget(&app);\n    auto* main_layout = new QVBoxLayout(central);\n    main_layout->setContentsMargins(12, 12, 12, 12);\n    main_layout->setSpacing(8);\n\n    auto* path_layout = new QHBoxLayout();\n    app.path_label = new QLabel(central);\n    app.path_entry = new QLineEdit(central);\n    app.browse_button = new QPushButton(central);\n    path_layout->addWidget(app.path_label);\n    path_layout->addWidget(app.path_entry, 1);\n    path_layout->addWidget(app.browse_button);\n    main_layout->addLayout(path_layout);\n\n    auto* options_layout = new QHBoxLayout();\n    app.use_subcategories_checkbox = new QCheckBox(central);\n    app.categorize_files_checkbox = new QCheckBox(central);\n    app.categorize_directories_checkbox = new QCheckBox(central);\n    app.include_subdirectories_checkbox = new QCheckBox(central);\n    app.categorize_files_checkbox->setChecked(true);\n    options_layout->addWidget(app.use_subcategories_checkbox);\n    options_layout->addWidget(app.categorize_files_checkbox);\n    options_layout->addWidget(app.categorize_directories_checkbox);\n    options_layout->addWidget(app.include_subdirectories_checkbox);\n    options_layout->addStretch(1);\n    main_layout->addLayout(options_layout);\n\n    auto* document_options_layout = new QVBoxLayout();\n    document_options_layout->setContentsMargins(0, 0, 0, 0);\n    document_options_layout->setSpacing(4);\n    auto* document_header_layout = new QHBoxLayout();\n    document_header_layout->setContentsMargins(0, 0, 0, 0);\n    document_header_layout->setSpacing(6);\n    app.analyze_documents_checkbox = new QCheckBox(central);\n    app.document_options_toggle_button = new DisclosureToggleButton(central);\n    app.document_options_toggle_button->setChecked(false);\n    document_header_layout->addWidget(app.analyze_documents_checkbox);\n    document_header_layout->addWidget(app.document_options_toggle_button);\n    document_header_layout->addStretch(1);\n    document_options_layout->addLayout(document_header_layout);\n\n    app.document_options_container = new QWidget(central);\n    auto* document_rename_layout = new QVBoxLayout(app.document_options_container);\n    document_rename_layout->setContentsMargins(24, 0, 0, 0);\n    document_rename_layout->setSpacing(2);\n    app.process_documents_only_checkbox = new QCheckBox(central);\n    app.offer_rename_documents_checkbox = new QCheckBox(central);\n    app.rename_documents_only_checkbox = new QCheckBox(central);\n    app.add_document_date_to_category_checkbox = new QCheckBox(central);\n    document_rename_layout->addWidget(app.process_documents_only_checkbox);\n    document_rename_layout->addWidget(app.offer_rename_documents_checkbox);\n    document_rename_layout->addWidget(app.rename_documents_only_checkbox);\n    document_rename_layout->addWidget(app.add_document_date_to_category_checkbox);\n    app.document_options_container->setVisible(false);\n    document_options_layout->addWidget(app.document_options_container);\n    main_layout->addLayout(document_options_layout);\n\n    auto* image_options_layout = new QVBoxLayout();\n    image_options_layout->setContentsMargins(0, 0, 0, 0);\n    image_options_layout->setSpacing(4);\n    auto* image_header_layout = new QHBoxLayout();\n    image_header_layout->setContentsMargins(0, 0, 0, 0);\n    image_header_layout->setSpacing(6);\n    app.analyze_images_checkbox = new QCheckBox(central);\n    app.image_options_toggle_button = new DisclosureToggleButton(central);\n    app.image_options_toggle_button->setChecked(false);\n    image_header_layout->addWidget(app.analyze_images_checkbox);\n    image_header_layout->addWidget(app.image_options_toggle_button);\n    image_header_layout->addStretch(1);\n    image_options_layout->addLayout(image_header_layout);\n\n    app.image_options_container = new QWidget(central);\n    auto* image_rename_layout = new QVBoxLayout(app.image_options_container);\n    image_rename_layout->setContentsMargins(24, 0, 0, 0);\n    image_rename_layout->setSpacing(2);\n    app.process_images_only_checkbox = new QCheckBox(central);\n    app.add_image_date_to_category_checkbox = new QCheckBox(central);\n    app.add_image_date_place_to_filename_checkbox = new QCheckBox(central);\n    app.offer_rename_images_checkbox = new QCheckBox(central);\n    app.rename_images_only_checkbox = new QCheckBox(central);\n    image_rename_layout->addWidget(app.process_images_only_checkbox);\n    image_rename_layout->addWidget(app.add_image_date_to_category_checkbox);\n    image_rename_layout->addWidget(app.add_image_date_place_to_filename_checkbox);\n    image_rename_layout->addWidget(app.offer_rename_images_checkbox);\n    image_rename_layout->addWidget(app.rename_images_only_checkbox);\n    app.image_options_container->setVisible(false);\n    image_options_layout->addWidget(app.image_options_container);\n    main_layout->addLayout(image_options_layout);\n\n    app.add_audio_video_metadata_to_filename_checkbox = new QCheckBox(central);\n    auto* audio_video_row = new QHBoxLayout();\n    audio_video_row->setContentsMargins(0, 0, 0, 0);\n    audio_video_row->addWidget(app.add_audio_video_metadata_to_filename_checkbox);\n    audio_video_row->addStretch(1);\n    main_layout->addLayout(audio_video_row);\n\n    app.categorization_style_heading = new QLabel(central);\n    app.categorization_style_refined_radio = new QRadioButton(central);\n    app.categorization_style_consistent_radio = new QRadioButton(central);\n    app.use_whitelist_checkbox = new QCheckBox(central);\n    app.whitelist_selector = new QComboBox(central);\n    app.whitelist_selector->setEnabled(false);\n    app.whitelist_selector->setMinimumContentsLength(16);\n    app.whitelist_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n    QFontMetrics fm(app.whitelist_selector->font());\n    app.whitelist_selector->setMinimumWidth(fm.horizontalAdvance(QString(16, QChar('W'))) + 5);\n\n    app.analyze_button = new QPushButton(central);\n    QIcon analyze_icon = QIcon::fromTheme(QStringLiteral(\"sparkle\"));\n    if (analyze_icon.isNull()) {\n        analyze_icon = QIcon::fromTheme(QStringLiteral(\"applications-education\"));\n    }\n    if (analyze_icon.isNull()) {\n        analyze_icon = app.style()->standardIcon(QStyle::SP_MediaPlay);\n    }\n    app.analyze_button->setIcon(analyze_icon);\n    app.analyze_button->setIconSize(QSize(20, 20));\n    app.analyze_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);\n    app.analyze_button->setMinimumWidth(160);\n    auto* analyze_layout = new QHBoxLayout();\n    auto* categorization_layout = new QVBoxLayout();\n    auto* toggle_row = new QHBoxLayout();\n    toggle_row->addWidget(app.categorization_style_refined_radio);\n    toggle_row->addWidget(app.categorization_style_consistent_radio);\n    toggle_row->addStretch();\n    categorization_layout->addWidget(app.categorization_style_heading);\n    categorization_layout->addLayout(toggle_row);\n\n    auto* whitelist_row = new QHBoxLayout();\n    whitelist_row->addWidget(app.use_whitelist_checkbox);\n    whitelist_row->addWidget(app.whitelist_selector);\n    whitelist_row->addStretch();\n\n    auto* control_block = new QVBoxLayout();\n    control_block->addLayout(categorization_layout);\n    control_block->addSpacing(4);\n    control_block->addLayout(whitelist_row);\n\n    analyze_layout->addLayout(control_block);\n    analyze_layout->addSpacing(12);\n    analyze_layout->addWidget(app.analyze_button, 0, Qt::AlignBottom | Qt::AlignRight);\n    main_layout->addLayout(analyze_layout);\n\n    app.tree_model = new QStandardItemModel(0, 5, &app);\n\n    app.results_stack = new QStackedWidget(central);\n\n    app.tree_view = new QTreeView(app.results_stack);\n    app.tree_view->setModel(app.tree_model);\n    app.tree_view->setSelectionBehavior(QAbstractItemView::SelectRows);\n    app.tree_view->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    app.tree_view->header()->setSectionResizeMode(QHeaderView::Stretch);\n    app.tree_view->setUniformRowHeights(true);\n    app.tree_view_page_index_ = app.results_stack->addWidget(app.tree_view);\n\n    app.folder_contents_model = new QFileSystemModel(app.results_stack);\n    app.folder_contents_model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);\n    app.folder_contents_model->setRootPath(QDir::homePath());\n\n    app.folder_contents_view = new QTreeView(app.results_stack);\n    app.folder_contents_view->setModel(app.folder_contents_model);\n    app.folder_contents_view->setRootIndex(app.folder_contents_model->index(QDir::homePath()));\n    app.folder_contents_view->setSelectionBehavior(QAbstractItemView::SelectRows);\n    app.folder_contents_view->setEditTriggers(QAbstractItemView::NoEditTriggers);\n    app.folder_contents_view->setRootIsDecorated(false);\n    app.folder_contents_view->setUniformRowHeights(true);\n    app.folder_contents_view->setSortingEnabled(true);\n    app.folder_contents_view->sortByColumn(0, Qt::AscendingOrder);\n    app.folder_contents_view->setAlternatingRowColors(true);\n    app.folder_view_page_index_ = app.results_stack->addWidget(app.folder_contents_view);\n\n    app.results_stack->setCurrentIndex(app.tree_view_page_index_);\n    main_layout->addWidget(app.results_stack, 1);\n\n    app.setCentralWidget(central);\n}\n\nUiTranslator::Dependencies MainAppUiBuilder::build_translator_dependencies(MainApp& app) const\n{\n    return UiTranslator::Dependencies{\n        .window = app,\n        .primary = UiTranslator::PrimaryControls{\n            app.path_label,\n            app.browse_button,\n            app.analyze_button,\n            app.use_subcategories_checkbox,\n            app.categorization_style_heading,\n            app.categorization_style_refined_radio,\n            app.categorization_style_consistent_radio,\n            app.use_whitelist_checkbox,\n            app.whitelist_selector,\n            app.categorize_files_checkbox,\n            app.categorize_directories_checkbox,\n            app.include_subdirectories_checkbox,\n            app.analyze_images_checkbox,\n            app.process_images_only_checkbox,\n            app.add_image_date_to_category_checkbox,\n            app.add_image_date_place_to_filename_checkbox,\n            app.add_audio_video_metadata_to_filename_checkbox,\n            app.offer_rename_images_checkbox,\n            app.rename_images_only_checkbox,\n            app.image_options_toggle_button,\n            app.analyze_documents_checkbox,\n            app.process_documents_only_checkbox,\n            app.offer_rename_documents_checkbox,\n            app.rename_documents_only_checkbox,\n            app.add_document_date_to_category_checkbox,\n            app.document_options_toggle_button},\n        .tree_model = app.tree_model,\n        .menus = UiTranslator::MenuControls{\n            app.file_menu,\n            app.edit_menu,\n            app.view_menu,\n            app.settings_menu,\n            app.development_menu,\n            app.development_settings_menu,\n            app.language_menu,\n            app.category_language_menu,\n            app.help_menu},\n        .actions = UiTranslator::ActionControls{\n            app.file_quit_action,\n            app.run_benchmark_action,\n            app.copy_action,\n            app.cut_action,\n            app.undo_last_run_action,\n            app.paste_action,\n            app.delete_action,\n            app.toggle_explorer_action,\n            app.toggle_llm_action,\n            app.manage_whitelists_action,\n            app.development_prompt_logging_action,\n            app.consistency_pass_action,\n            app.english_action,\n            app.dutch_action,\n            app.french_action,\n            app.german_action,\n            app.italian_action,\n            app.spanish_action,\n            app.turkish_action,\n            app.korean_action,\n            app.category_language_english,\n            app.category_language_french,\n            app.category_language_german,\n            app.category_language_italian,\n            app.category_language_dutch,\n            app.category_language_polish,\n            app.category_language_portuguese,\n            app.category_language_spanish,\n            app.category_language_turkish,\n            app.about_action,\n            app.about_qt_action,\n            app.about_agpl_action,\n            app.support_project_action},\n        .language = UiTranslator::LanguageControls{\n            app.language_group,\n            app.english_action,\n            app.dutch_action,\n            app.french_action,\n            app.german_action,\n            app.italian_action,\n            app.spanish_action,\n            app.turkish_action,\n            app.korean_action},\n        .category_language = UiTranslator::CategoryLanguageControls{\n            app.category_language_group,\n            app.category_language_dutch,\n            app.category_language_english,\n            app.category_language_french,\n            app.category_language_german,\n            app.category_language_italian,\n            app.category_language_polish,\n            app.category_language_portuguese,\n            app.category_language_spanish,\n            app.category_language_turkish},\n        .file_explorer_dock = app.file_explorer_dock,\n        .settings = app.settings,\n        .translator = [](const char* source) {\n            return QCoreApplication::translate(\"UiTranslator\", source);\n        }};\n}\n\nvoid MainAppUiBuilder::build_menus(MainApp& app) {\n    build_file_menu(app);\n    build_edit_menu(app);\n    build_view_menu(app);\n    build_settings_menu(app);\n    if (app.is_development_mode()) {\n        build_development_menu(app);\n    }\n    build_help_menu(app);\n}\n\nvoid MainAppUiBuilder::build_file_menu(MainApp& app) {\n    app.file_menu = app.menuBar()->addMenu(QString());\n    app.run_benchmark_action = app.file_menu->addAction(icon_for(app, \"view-statistics\", QStyle::SP_MediaPlay), QString());\n    QObject::connect(app.run_benchmark_action, &QAction::triggered, &app, [&app]() {\n        app.show_suitability_benchmark_dialog(false);\n    });\n    app.file_menu->addSeparator();\n    app.file_quit_action = app.file_menu->addAction(icon_for(app, \"application-exit\", QStyle::SP_DialogCloseButton), QString());\n    app.file_quit_action->setShortcut(QKeySequence::Quit);\n    app.file_quit_action->setMenuRole(QAction::QuitRole);\n    QObject::connect(app.file_quit_action, &QAction::triggered, qApp, &QApplication::quit);\n}\n\nvoid MainAppUiBuilder::build_edit_menu(MainApp& app) {\n    app.edit_menu = app.menuBar()->addMenu(QString());\n\n    app.undo_last_run_action = app.edit_menu->addAction(icon_for(app, \"edit-undo\", QStyle::SP_ArrowBack), QString());\n    QObject::connect(app.undo_last_run_action, &QAction::triggered, &app, &MainApp::undo_last_run);\n\n    app.copy_action = app.edit_menu->addAction(icon_for(app, \"edit-copy\", QStyle::SP_FileDialogContentsView), QString());\n    QObject::connect(app.copy_action, &QAction::triggered, &app, [&app]() {\n        MainAppEditActions::on_copy(app.path_entry);\n    });\n    app.copy_action->setShortcut(QKeySequence::Copy);\n\n    app.cut_action = app.edit_menu->addAction(icon_for(app, \"edit-cut\", QStyle::SP_FileDialogDetailedView), QString());\n    QObject::connect(app.cut_action, &QAction::triggered, &app, [&app]() {\n        MainAppEditActions::on_cut(app.path_entry);\n    });\n    app.cut_action->setShortcut(QKeySequence::Cut);\n\n    app.paste_action = app.edit_menu->addAction(icon_for(app, \"edit-paste\", QStyle::SP_FileDialogListView), QString());\n    QObject::connect(app.paste_action, &QAction::triggered, &app, [&app]() {\n        MainAppEditActions::on_paste(app.path_entry);\n    });\n    app.paste_action->setShortcut(QKeySequence::Paste);\n\n    app.delete_action = app.edit_menu->addAction(icon_for(app, \"edit-delete\", QStyle::SP_TrashIcon), QString());\n    QObject::connect(app.delete_action, &QAction::triggered, &app, [&app]() {\n        MainAppEditActions::on_delete(app.path_entry);\n    });\n    app.delete_action->setShortcut(QKeySequence::Delete);\n}\n\nvoid MainAppUiBuilder::build_view_menu(MainApp& app) {\n    app.view_menu = app.menuBar()->addMenu(QString());\n    app.toggle_explorer_action = app.view_menu->addAction(icon_for(app, \"system-file-manager\", QStyle::SP_DirOpenIcon), QString());\n    app.toggle_explorer_action->setCheckable(true);\n    app.toggle_explorer_action->setChecked(app.settings.get_show_file_explorer());\n    QObject::connect(app.toggle_explorer_action, &QAction::toggled, &app, [&app](bool checked) {\n        if (app.file_explorer_dock) {\n            app.file_explorer_dock->setVisible(checked);\n        }\n        app.settings.set_show_file_explorer(checked);\n        app.update_results_view_mode();\n    });\n    app.file_explorer_menu_action = app.toggle_explorer_action;\n}\n\nvoid MainAppUiBuilder::build_settings_menu(MainApp& app) {\n    app.settings_menu = app.menuBar()->addMenu(QString());\n    app.toggle_llm_action = app.settings_menu->addAction(llm_menu_icon(app), QString());\n    QObject::connect(app.toggle_llm_action, &QAction::triggered, &app, &MainApp::show_llm_selection_dialog);\n\n    app.manage_whitelists_action = app.settings_menu->addAction(whitelist_menu_icon(app), QString());\n    QObject::connect(app.manage_whitelists_action, &QAction::triggered, &app, &MainApp::show_whitelist_manager);\n\n    app.language_menu = app.settings_menu->addMenu(QString());\n    app.language_menu->setIcon(interface_language_menu_icon(app));\n    if (app.language_menu->menuAction()) {\n        app.language_menu->menuAction()->setIcon(interface_language_menu_icon(app));\n    }\n    app.language_group = new QActionGroup(&app);\n    app.language_group->setExclusive(true);\n\n    app.dutch_action = app.language_menu->addAction(QString());\n    app.dutch_action->setCheckable(true);\n    app.dutch_action->setData(static_cast<int>(Language::Dutch));\n    app.language_group->addAction(app.dutch_action);\n\n    app.english_action = app.language_menu->addAction(QString());\n    app.english_action->setCheckable(true);\n    app.english_action->setData(static_cast<int>(Language::English));\n    app.language_group->addAction(app.english_action);\n\n    app.french_action = app.language_menu->addAction(QString());\n    app.french_action->setCheckable(true);\n    app.french_action->setData(static_cast<int>(Language::French));\n    app.language_group->addAction(app.french_action);\n    app.german_action = app.language_menu->addAction(QString());\n    app.german_action->setCheckable(true);\n    app.german_action->setData(static_cast<int>(Language::German));\n    app.language_group->addAction(app.german_action);\n    app.italian_action = app.language_menu->addAction(QString());\n    app.italian_action->setCheckable(true);\n    app.italian_action->setData(static_cast<int>(Language::Italian));\n    app.language_group->addAction(app.italian_action);\n    app.korean_action = app.language_menu->addAction(QString());\n    app.korean_action->setCheckable(true);\n    app.korean_action->setData(static_cast<int>(Language::Korean));\n    app.language_group->addAction(app.korean_action);\n    app.spanish_action = app.language_menu->addAction(QString());\n    app.spanish_action->setCheckable(true);\n    app.spanish_action->setData(static_cast<int>(Language::Spanish));\n    app.language_group->addAction(app.spanish_action);\n    app.turkish_action = app.language_menu->addAction(QString());\n    app.turkish_action->setCheckable(true);\n    app.turkish_action->setData(static_cast<int>(Language::Turkish));\n    app.language_group->addAction(app.turkish_action);\n\n    QObject::connect(app.language_group, &QActionGroup::triggered, &app, [&app](QAction* action) {\n        if (!action) {\n            return;\n        }\n        const Language chosen = static_cast<Language>(action->data().toInt());\n        app.on_language_selected(chosen);\n    });\n\n    app.category_language_menu = app.settings_menu->addMenu(QString());\n    app.category_language_menu->setIcon(category_language_menu_icon(app));\n    if (app.category_language_menu->menuAction()) {\n        app.category_language_menu->menuAction()->setIcon(category_language_menu_icon(app));\n    }\n    app.category_language_group = new QActionGroup(&app);\n    app.category_language_group->setExclusive(true);\n\n    const auto add_cat_lang = [&](CategoryLanguage lang) {\n        QAction* act = app.category_language_menu->addAction(QString());\n        act->setCheckable(true);\n        act->setData(static_cast<int>(lang));\n        app.category_language_group->addAction(act);\n        return act;\n    };\n    app.category_language_dutch = add_cat_lang(CategoryLanguage::Dutch);\n    app.category_language_english = add_cat_lang(CategoryLanguage::English);\n    app.category_language_french = add_cat_lang(CategoryLanguage::French);\n    app.category_language_german = add_cat_lang(CategoryLanguage::German);\n    app.category_language_italian = add_cat_lang(CategoryLanguage::Italian);\n    app.category_language_polish = add_cat_lang(CategoryLanguage::Polish);\n    app.category_language_portuguese = add_cat_lang(CategoryLanguage::Portuguese);\n    app.category_language_spanish = add_cat_lang(CategoryLanguage::Spanish);\n    app.category_language_turkish = add_cat_lang(CategoryLanguage::Turkish);\n\n    QObject::connect(app.category_language_group, &QActionGroup::triggered, &app, [&app](QAction* action) {\n        if (!action) {\n            return;\n        }\n        const CategoryLanguage chosen = static_cast<CategoryLanguage>(action->data().toInt());\n        app.on_category_language_selected(chosen);\n    });\n}\n\nvoid MainAppUiBuilder::build_development_menu(MainApp& app) {\n    app.development_menu = app.menuBar()->addMenu(QString());\n    app.development_settings_menu = app.development_menu->addMenu(QString());\n    app.development_prompt_logging_action = app.development_settings_menu->addAction(QString());\n    app.development_prompt_logging_action->setCheckable(true);\n    app.development_prompt_logging_action->setChecked(app.development_prompt_logging_enabled_);\n    QObject::connect(app.development_prompt_logging_action, &QAction::toggled, &app, &MainApp::handle_development_prompt_logging);\n}\n\nvoid MainAppUiBuilder::build_help_menu(MainApp& app) {\n    app.help_menu = app.menuBar()->addMenu(QString());\n    if (app.help_menu && app.help_menu->menuAction()) {\n        app.help_menu->menuAction()->setMenuRole(QAction::ApplicationSpecificRole);\n    }\n\n    app.about_action = app.help_menu->addAction(icon_for(app, \"help-about\", QStyle::SP_MessageBoxInformation), QString());\n    app.about_action->setMenuRole(QAction::NoRole);\n    QObject::connect(app.about_action, &QAction::triggered, &app, &MainApp::on_about_activate);\n\n    app.about_qt_action = app.help_menu->addAction(icon_for(app, \"help-about\", QStyle::SP_MessageBoxInformation), QString());\n    app.about_qt_action->setMenuRole(QAction::NoRole);\n    QObject::connect(app.about_qt_action, &QAction::triggered, &app, [&app]() {\n        QMessageBox::aboutQt(&app);\n    });\n\n    app.about_agpl_action = app.help_menu->addAction(icon_for(app, \"help-about\", QStyle::SP_MessageBoxInformation), QString());\n    app.about_agpl_action->setMenuRole(QAction::NoRole);\n    QObject::connect(app.about_agpl_action, &QAction::triggered, &app, [&app]() {\n        MainAppHelpActions::show_agpl_info(&app);\n    });\n\n#ifdef _WIN32\n    app.support_project_action = nullptr;\n#else\n    app.support_project_action = app.help_menu->addAction(icon_for(app, \"help-donate\", QStyle::SP_DialogHelpButton), QString());\n    app.support_project_action->setMenuRole(QAction::NoRole);\n    QObject::connect(app.support_project_action, &QAction::triggered, &app, []() {\n        MainAppHelpActions::open_support_page();\n    });\n#endif\n}\n\nQIcon MainAppUiBuilder::icon_for(MainApp& app, const char* name, QStyle::StandardPixmap fallback) {\n    QIcon icon = QIcon::fromTheme(QString::fromLatin1(name));\n    if (icon.isNull()) {\n        icon = app.style()->standardIcon(fallback);\n    }\n    if (!icon.isNull()) {\n        const int targetSize = app.style()->pixelMetric(QStyle::PM_SmallIconSize);\n        if (targetSize > 0) {\n            QPixmap pixmap = icon.pixmap(targetSize, targetSize);\n            if (!pixmap.isNull()) {\n                const int padding = std::max(4, targetSize / 4);\n                const QSize paddedSize(pixmap.width() + padding * 2, pixmap.height() + padding * 2);\n                QPixmap padded(paddedSize);\n                padded.fill(Qt::transparent);\n                QPainter painter(&padded);\n                painter.drawPixmap(padding, padding, pixmap);\n                painter.end();\n                QIcon paddedIcon;\n                paddedIcon.addPixmap(padded, QIcon::Normal);\n                paddedIcon.addPixmap(padded, QIcon::Disabled);\n                icon = paddedIcon;\n            }\n        }\n    }\n    return icon;\n}\n"
  },
  {
    "path": "app/lib/MediaRenameMetadataService.cpp",
    "content": "#include \"MediaRenameMetadataService.hpp\"\n\n#include \"Utils.hpp\"\n\n#include <algorithm>\n#include <array>\n#include <cctype>\n#include <cstdint>\n#include <cstddef>\n#include <cstring>\n#include <fstream>\n#include <limits>\n#include <string>\n#include <unordered_set>\n#include <utility>\n#include <vector>\n\n#ifdef AI_FILE_SORTER_USE_MEDIAINFOLIB\n#if defined(__APPLE__) && !defined(UNICODE) && !defined(_UNICODE)\n// Homebrew's MediaInfoLib is built with the wide-character API enabled.\n#define UNICODE\n#define _UNICODE\n#endif\n#if defined(_WIN32)\n#include <MediaInfoDLL/MediaInfoDLL_Static.h>\nnamespace MediaInfoCompat = MediaInfoDLL;\n#else\n#include <MediaInfo/MediaInfo.h>\nnamespace MediaInfoCompat = MediaInfoLib;\n#endif\n#if defined(UNICODE) || defined(_UNICODE)\n#include <QString>\n#endif\n#endif\n\nnamespace {\n\nstd::string trim_copy(std::string value)\n{\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    const auto start = value.find_first_not_of(whitespace);\n    if (start == std::string::npos) {\n        return std::string();\n    }\n    const auto end = value.find_last_not_of(whitespace);\n    return value.substr(start, end - start + 1);\n}\n\nstd::string to_lower_copy(std::string value)\n{\n    std::transform(value.begin(),\n                   value.end(),\n                   value.begin(),\n                   [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });\n    return value;\n}\n\nconst std::unordered_set<std::string>& audio_extensions()\n{\n    static const std::unordered_set<std::string> extensions = {\n        \".aac\", \".aif\", \".aiff\", \".alac\", \".ape\", \".flac\", \".m4a\", \".mp3\",\n        \".ogg\", \".oga\", \".opus\", \".wav\", \".wma\"\n    };\n    return extensions;\n}\n\nconst std::unordered_set<std::string>& video_extensions()\n{\n    static const std::unordered_set<std::string> extensions = {\n        \".3gp\", \".avi\", \".flv\", \".m4v\", \".mkv\", \".mov\", \".mp4\", \".mpeg\", \".mpg\",\n        \".mts\", \".m2ts\", \".ts\", \".webm\", \".wmv\"\n    };\n    return extensions;\n}\n\nbool is_supported_audio(const std::filesystem::path& path)\n{\n    if (!path.has_extension()) {\n        return false;\n    }\n    const std::string ext = to_lower_copy(Utils::path_to_utf8(path.extension()));\n    return audio_extensions().contains(ext);\n}\n\nbool is_supported_video(const std::filesystem::path& path)\n{\n    if (!path.has_extension()) {\n        return false;\n    }\n    const std::string ext = to_lower_copy(Utils::path_to_utf8(path.extension()));\n    return video_extensions().contains(ext);\n}\n\nbool has_metadata_parts(const MediaRenameMetadataService::MetadataFields& metadata)\n{\n    return metadata.year.has_value() ||\n           metadata.artist.has_value() ||\n           metadata.album.has_value() ||\n           metadata.title.has_value();\n}\n\n#ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB\nconstexpr std::size_t kMaxId3TagSizeBytes = 2U * 1024U * 1024U;\n\nbool read_exact(std::istream& input, char* destination, std::size_t size)\n{\n    if (size == 0) {\n        return true;\n    }\n    input.read(destination, static_cast<std::streamsize>(size));\n    return input.gcount() == static_cast<std::streamsize>(size);\n}\n\nstd::uint32_t read_u32_be(const std::uint8_t* bytes)\n{\n    return (static_cast<std::uint32_t>(bytes[0]) << 24) |\n           (static_cast<std::uint32_t>(bytes[1]) << 16) |\n           (static_cast<std::uint32_t>(bytes[2]) << 8) |\n           static_cast<std::uint32_t>(bytes[3]);\n}\n\nstd::uint32_t read_u32_le(const std::uint8_t* bytes)\n{\n    return static_cast<std::uint32_t>(bytes[0]) |\n           (static_cast<std::uint32_t>(bytes[1]) << 8) |\n           (static_cast<std::uint32_t>(bytes[2]) << 16) |\n           (static_cast<std::uint32_t>(bytes[3]) << 24);\n}\n\nstd::uint32_t read_u24_be(const std::uint8_t* bytes)\n{\n    return (static_cast<std::uint32_t>(bytes[0]) << 16) |\n           (static_cast<std::uint32_t>(bytes[1]) << 8) |\n           static_cast<std::uint32_t>(bytes[2]);\n}\n\nstd::uint64_t read_u64_be(const std::uint8_t* bytes)\n{\n    return (static_cast<std::uint64_t>(bytes[0]) << 56) |\n           (static_cast<std::uint64_t>(bytes[1]) << 48) |\n           (static_cast<std::uint64_t>(bytes[2]) << 40) |\n           (static_cast<std::uint64_t>(bytes[3]) << 32) |\n           (static_cast<std::uint64_t>(bytes[4]) << 24) |\n           (static_cast<std::uint64_t>(bytes[5]) << 16) |\n           (static_cast<std::uint64_t>(bytes[6]) << 8) |\n           static_cast<std::uint64_t>(bytes[7]);\n}\n\nstd::uint32_t read_synchsafe_u32(const std::uint8_t* bytes)\n{\n    return (static_cast<std::uint32_t>(bytes[0] & 0x7F) << 21) |\n           (static_cast<std::uint32_t>(bytes[1] & 0x7F) << 14) |\n           (static_cast<std::uint32_t>(bytes[2] & 0x7F) << 7) |\n           static_cast<std::uint32_t>(bytes[3] & 0x7F);\n}\n\nstd::string sanitize_metadata_value(std::string value)\n{\n    std::string sanitized;\n    sanitized.reserve(value.size());\n\n    for (unsigned char ch : value) {\n        if (ch == '\\0') {\n            continue;\n        }\n        if (std::iscntrl(ch)) {\n            sanitized.push_back(' ');\n            continue;\n        }\n        sanitized.push_back(static_cast<char>(ch));\n    }\n\n    return trim_copy(sanitized);\n}\n\nvoid assign_if_missing(std::optional<std::string>& target, const std::optional<std::string>& candidate)\n{\n    if (!target.has_value() && candidate.has_value() && !candidate->empty()) {\n        target = candidate;\n    }\n}\n\nvoid assign_vorbis_comment_field(const std::string& key,\n                                 const std::string& value,\n                                 MediaRenameMetadataService::MetadataFields& metadata)\n{\n    if (value.empty()) {\n        return;\n    }\n\n    const std::string lowered_key = to_lower_copy(key);\n    if (lowered_key == \"title\") {\n        assign_if_missing(metadata.title, sanitize_metadata_value(value));\n        return;\n    }\n    if (lowered_key == \"artist\" || lowered_key == \"albumartist\" || lowered_key == \"album artist\") {\n        assign_if_missing(metadata.artist, sanitize_metadata_value(value));\n        return;\n    }\n    if (lowered_key == \"album\") {\n        assign_if_missing(metadata.album, sanitize_metadata_value(value));\n        return;\n    }\n    if (lowered_key == \"date\" || lowered_key == \"year\" || lowered_key == \"originaldate\") {\n        assign_if_missing(metadata.year, sanitize_metadata_value(value));\n    }\n}\n\nstd::optional<std::string> decode_id3_text_frame(const std::uint8_t* bytes, std::size_t size)\n{\n    if (bytes == nullptr || size <= 1) {\n        return std::nullopt;\n    }\n\n    const std::uint8_t encoding = bytes[0];\n    const std::uint8_t* payload = bytes + 1;\n    const std::size_t payload_size = size - 1;\n\n    std::string decoded;\n    if (encoding == 0 || encoding == 3) {\n        decoded.assign(reinterpret_cast<const char*>(payload), payload_size);\n    } else if (encoding == 1 || encoding == 2) {\n        bool little_endian = (encoding == 1);\n        std::size_t offset = 0;\n        if (encoding == 1 && payload_size >= 2) {\n            if (payload[0] == 0xFF && payload[1] == 0xFE) {\n                little_endian = true;\n                offset = 2;\n            } else if (payload[0] == 0xFE && payload[1] == 0xFF) {\n                little_endian = false;\n                offset = 2;\n            }\n        }\n\n        decoded.reserve(payload_size / 2);\n        for (std::size_t index = offset; index + 1 < payload_size; index += 2) {\n            const std::uint16_t code_unit = little_endian\n                                                ? static_cast<std::uint16_t>(payload[index]) |\n                                                      (static_cast<std::uint16_t>(payload[index + 1]) << 8)\n                                                : (static_cast<std::uint16_t>(payload[index]) << 8) |\n                                                      static_cast<std::uint16_t>(payload[index + 1]);\n            if (code_unit == 0) {\n                break;\n            }\n            if (code_unit <= 0x7F) {\n                decoded.push_back(static_cast<char>(code_unit));\n            } else {\n                decoded.push_back(' ');\n            }\n        }\n    } else {\n        return std::nullopt;\n    }\n\n    if (const auto null_index = decoded.find('\\0'); null_index != std::string::npos) {\n        decoded.resize(null_index);\n    }\n\n    decoded = sanitize_metadata_value(decoded);\n    if (decoded.empty()) {\n        return std::nullopt;\n    }\n    return decoded;\n}\n\nstd::vector<std::uint8_t> remove_unsynchronization(const std::vector<std::uint8_t>& input)\n{\n    std::vector<std::uint8_t> decoded;\n    decoded.reserve(input.size());\n    for (std::size_t index = 0; index < input.size(); ++index) {\n        const std::uint8_t byte = input[index];\n        if (byte == 0xFF && index + 1 < input.size() && input[index + 1] == 0x00) {\n            decoded.push_back(0xFF);\n            ++index;\n            continue;\n        }\n        decoded.push_back(byte);\n    }\n    return decoded;\n}\n\nbool parse_vorbis_comment_payload(const std::uint8_t* bytes,\n                                  std::size_t size,\n                                  MediaRenameMetadataService::MetadataFields& metadata)\n{\n    if (bytes == nullptr || size < 8) {\n        return false;\n    }\n\n    std::size_t offset = 0;\n    const auto read_u32 = [&](std::uint32_t& value) -> bool {\n        if (offset + 4 > size) {\n            return false;\n        }\n        value = read_u32_le(bytes + offset);\n        offset += 4;\n        return true;\n    };\n\n    std::uint32_t vendor_length = 0;\n    if (!read_u32(vendor_length) || offset + vendor_length > size) {\n        return false;\n    }\n    offset += vendor_length;\n\n    std::uint32_t comment_count = 0;\n    if (!read_u32(comment_count)) {\n        return false;\n    }\n\n    for (std::uint32_t index = 0; index < comment_count; ++index) {\n        std::uint32_t comment_length = 0;\n        if (!read_u32(comment_length) || offset + comment_length > size) {\n            return false;\n        }\n\n        const std::string entry(reinterpret_cast<const char*>(bytes + offset), comment_length);\n        offset += comment_length;\n\n        const auto separator_index = entry.find('=');\n        if (separator_index == std::string::npos || separator_index == 0 ||\n            separator_index + 1 >= entry.size()) {\n            continue;\n        }\n\n        const std::string key = trim_copy(entry.substr(0, separator_index));\n        const std::string value = entry.substr(separator_index + 1);\n        assign_vorbis_comment_field(key, value, metadata);\n    }\n\n    return has_metadata_parts(metadata);\n}\n\nbool parse_id3v2_frames(const std::vector<std::uint8_t>& tag_data,\n                        int id3_major_version,\n                        std::uint8_t id3_flags,\n                        MediaRenameMetadataService::MetadataFields& metadata)\n{\n    if (id3_major_version < 2 || id3_major_version > 4 || tag_data.empty()) {\n        return false;\n    }\n\n    std::vector<std::uint8_t> data = tag_data;\n    if ((id3_flags & 0x80) != 0) {\n        data = remove_unsynchronization(data);\n    }\n\n    std::size_t offset = 0;\n    if ((id3_flags & 0x40) != 0) {\n        if (data.size() < 4) {\n            return false;\n        }\n\n        if (id3_major_version == 3) {\n            const std::size_t ext_size = read_u32_be(data.data());\n            if (ext_size + 4 > data.size()) {\n                return false;\n            }\n            offset = ext_size + 4;\n        } else if (id3_major_version == 4) {\n            const std::size_t ext_size = read_synchsafe_u32(data.data());\n            if (ext_size > data.size()) {\n                return false;\n            }\n            offset = ext_size;\n        }\n    }\n\n    auto apply_frame = [&](const std::string& frame_id, const std::optional<std::string>& value) {\n        if (!value.has_value()) {\n            return;\n        }\n\n        if (frame_id == \"TIT2\" || frame_id == \"TT2\") {\n            assign_if_missing(metadata.title, *value);\n            return;\n        }\n        if (frame_id == \"TPE1\" || frame_id == \"TP1\" ||\n            frame_id == \"TPE2\" || frame_id == \"TP2\") {\n            assign_if_missing(metadata.artist, *value);\n            return;\n        }\n        if (frame_id == \"TALB\" || frame_id == \"TAL\") {\n            assign_if_missing(metadata.album, *value);\n            return;\n        }\n        if (frame_id == \"TDRC\" || frame_id == \"TYER\" || frame_id == \"TYE\" ||\n            frame_id == \"TDOR\" || frame_id == \"TDRL\") {\n            assign_if_missing(metadata.year, *value);\n        }\n    };\n\n    while (offset < data.size()) {\n        std::string frame_id;\n        std::size_t frame_size = 0;\n        std::size_t frame_header_size = 0;\n\n        if (id3_major_version == 2) {\n            if (offset + 6 > data.size()) {\n                break;\n            }\n            const std::uint8_t* frame_header = data.data() + offset;\n            if (frame_header[0] == 0 && frame_header[1] == 0 && frame_header[2] == 0) {\n                break;\n            }\n            frame_id.assign(reinterpret_cast<const char*>(frame_header), 3);\n            frame_size = read_u24_be(frame_header + 3);\n            frame_header_size = 6;\n        } else {\n            if (offset + 10 > data.size()) {\n                break;\n            }\n            const std::uint8_t* frame_header = data.data() + offset;\n            if (frame_header[0] == 0 && frame_header[1] == 0 &&\n                frame_header[2] == 0 && frame_header[3] == 0) {\n                break;\n            }\n            frame_id.assign(reinterpret_cast<const char*>(frame_header), 4);\n            frame_size = id3_major_version == 4\n                             ? read_synchsafe_u32(frame_header + 4)\n                             : read_u32_be(frame_header + 4);\n            frame_header_size = 10;\n        }\n\n        if (frame_size == 0 || offset + frame_header_size + frame_size > data.size()) {\n            break;\n        }\n\n        const std::uint8_t* frame_body = data.data() + offset + frame_header_size;\n        apply_frame(frame_id, decode_id3_text_frame(frame_body, frame_size));\n        offset += frame_header_size + frame_size;\n    }\n\n    return has_metadata_parts(metadata);\n}\n\nbool parse_id3v2_from_file(const std::filesystem::path& media_path,\n                           MediaRenameMetadataService::MetadataFields& metadata)\n{\n    std::ifstream input(media_path, std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    std::uint8_t header[10] = {};\n    if (!read_exact(input, reinterpret_cast<char*>(header), sizeof(header))) {\n        return false;\n    }\n\n    if (std::memcmp(header, \"ID3\", 3) != 0) {\n        return false;\n    }\n\n    const int id3_major_version = static_cast<int>(header[3]);\n    if (id3_major_version < 2 || id3_major_version > 4) {\n        return false;\n    }\n\n    const std::uint32_t tag_size = read_synchsafe_u32(header + 6);\n    if (tag_size == 0 || tag_size > kMaxId3TagSizeBytes) {\n        return false;\n    }\n\n    std::vector<std::uint8_t> tag_data(tag_size);\n    if (!read_exact(input, reinterpret_cast<char*>(tag_data.data()), tag_data.size())) {\n        return false;\n    }\n\n    return parse_id3v2_frames(tag_data, id3_major_version, header[5], metadata);\n}\n\nbool parse_id3v1_from_file(const std::filesystem::path& media_path,\n                           MediaRenameMetadataService::MetadataFields& metadata)\n{\n    std::ifstream input(media_path, std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    input.seekg(0, std::ios::end);\n    const std::streamoff file_size = input.tellg();\n    if (file_size < 128) {\n        return false;\n    }\n    input.seekg(-128, std::ios::end);\n\n    std::array<char, 128> tag{};\n    if (!read_exact(input, tag.data(), tag.size())) {\n        return false;\n    }\n    if (std::memcmp(tag.data(), \"TAG\", 3) != 0) {\n        return false;\n    }\n\n    const auto read_field = [&](std::size_t offset, std::size_t length) -> std::optional<std::string> {\n        std::string value(tag.data() + offset, length);\n        while (!value.empty() && (value.back() == '\\0' || std::isspace(static_cast<unsigned char>(value.back())))) {\n            value.pop_back();\n        }\n        value = sanitize_metadata_value(value);\n        if (value.empty()) {\n            return std::nullopt;\n        }\n        return value;\n    };\n\n    assign_if_missing(metadata.title, read_field(3, 30));\n    assign_if_missing(metadata.artist, read_field(33, 30));\n    assign_if_missing(metadata.album, read_field(63, 30));\n    assign_if_missing(metadata.year, read_field(93, 4));\n\n    return has_metadata_parts(metadata);\n}\n\nbool parse_flac_vorbis_comments(const std::filesystem::path& media_path,\n                                MediaRenameMetadataService::MetadataFields& metadata)\n{\n    std::ifstream input(media_path, std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    std::array<char, 4> signature{};\n    if (!read_exact(input, signature.data(), signature.size()) ||\n        std::memcmp(signature.data(), \"fLaC\", 4) != 0) {\n        return false;\n    }\n\n    bool is_last_block = false;\n    while (!is_last_block && input.good()) {\n        std::uint8_t block_header[4] = {};\n        if (!read_exact(input, reinterpret_cast<char*>(block_header), sizeof(block_header))) {\n            return false;\n        }\n\n        is_last_block = (block_header[0] & 0x80U) != 0;\n        const std::uint8_t block_type = static_cast<std::uint8_t>(block_header[0] & 0x7FU);\n        const std::uint32_t block_length = read_u24_be(block_header + 1);\n\n        if (block_type == 4) {\n            std::vector<std::uint8_t> block(block_length);\n            if (!read_exact(input, reinterpret_cast<char*>(block.data()), block.size())) {\n                return false;\n            }\n            parse_vorbis_comment_payload(block.data(), block.size(), metadata);\n        } else {\n            input.seekg(static_cast<std::streamoff>(block_length), std::ios::cur);\n            if (!input.good()) {\n                return false;\n            }\n        }\n    }\n\n    return has_metadata_parts(metadata);\n}\n\nbool parse_ogg_comments(const std::filesystem::path& media_path,\n                        MediaRenameMetadataService::MetadataFields& metadata)\n{\n    std::ifstream input(media_path, std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    enum class OggCodec {\n        Unknown,\n        Vorbis,\n        Opus\n    };\n\n    OggCodec codec = OggCodec::Unknown;\n    std::vector<std::uint8_t> packet;\n    std::size_t packet_index = 0;\n\n    while (input.good()) {\n        std::uint8_t page_header[27] = {};\n        if (!read_exact(input, reinterpret_cast<char*>(page_header), sizeof(page_header))) {\n            break;\n        }\n        if (std::memcmp(page_header, \"OggS\", 4) != 0 || page_header[4] != 0) {\n            return false;\n        }\n\n        const std::uint8_t segment_count = page_header[26];\n        std::vector<std::uint8_t> segment_table(segment_count);\n        if (segment_count > 0 &&\n            !read_exact(input, reinterpret_cast<char*>(segment_table.data()), segment_table.size())) {\n            return false;\n        }\n\n        std::size_t body_size = 0;\n        for (const std::uint8_t segment : segment_table) {\n            body_size += segment;\n        }\n\n        std::vector<std::uint8_t> body(body_size);\n        if (body_size > 0 && !read_exact(input, reinterpret_cast<char*>(body.data()), body.size())) {\n            return false;\n        }\n\n        std::size_t body_offset = 0;\n        for (const std::uint8_t segment : segment_table) {\n            packet.insert(packet.end(),\n                          body.begin() + static_cast<std::ptrdiff_t>(body_offset),\n                          body.begin() + static_cast<std::ptrdiff_t>(body_offset + segment));\n            body_offset += segment;\n\n            if (segment == 255) {\n                continue;\n            }\n\n            if (packet_index == 0) {\n                if (packet.size() >= 7 && packet[0] == 0x01 &&\n                    std::memcmp(packet.data() + 1, \"vorbis\", 6) == 0) {\n                    codec = OggCodec::Vorbis;\n                } else if (packet.size() >= 8 && std::memcmp(packet.data(), \"OpusHead\", 8) == 0) {\n                    codec = OggCodec::Opus;\n                } else {\n                    return false;\n                }\n            } else if (packet_index == 1) {\n                if (codec == OggCodec::Vorbis &&\n                    packet.size() >= 7 &&\n                    packet[0] == 0x03 &&\n                    std::memcmp(packet.data() + 1, \"vorbis\", 6) == 0) {\n                    return parse_vorbis_comment_payload(packet.data() + 7, packet.size() - 7, metadata);\n                }\n                if (codec == OggCodec::Opus &&\n                    packet.size() >= 8 &&\n                    std::memcmp(packet.data(), \"OpusTags\", 8) == 0) {\n                    return parse_vorbis_comment_payload(packet.data() + 8, packet.size() - 8, metadata);\n                }\n                return false;\n            }\n\n            packet.clear();\n            ++packet_index;\n        }\n    }\n\n    return has_metadata_parts(metadata);\n}\n\nconstexpr std::uint32_t make_fourcc(std::uint8_t c0,\n                                    std::uint8_t c1,\n                                    std::uint8_t c2,\n                                    std::uint8_t c3)\n{\n    return (static_cast<std::uint32_t>(c0) << 24) |\n           (static_cast<std::uint32_t>(c1) << 16) |\n           (static_cast<std::uint32_t>(c2) << 8) |\n           static_cast<std::uint32_t>(c3);\n}\n\nconstexpr std::uint32_t kAtomMoov = make_fourcc('m', 'o', 'o', 'v');\nconstexpr std::uint32_t kAtomUdta = make_fourcc('u', 'd', 't', 'a');\nconstexpr std::uint32_t kAtomMeta = make_fourcc('m', 'e', 't', 'a');\nconstexpr std::uint32_t kAtomIlst = make_fourcc('i', 'l', 's', 't');\nconstexpr std::uint32_t kAtomData = make_fourcc('d', 'a', 't', 'a');\nconstexpr std::uint32_t kAtomTrak = make_fourcc('t', 'r', 'a', 'k');\nconstexpr std::uint32_t kAtomMdia = make_fourcc('m', 'd', 'i', 'a');\nconstexpr std::uint32_t kAtomMinf = make_fourcc('m', 'i', 'n', 'f');\nconstexpr std::uint32_t kAtomStbl = make_fourcc('s', 't', 'b', 'l');\nconstexpr std::uint32_t kAtomEdts = make_fourcc('e', 'd', 't', 's');\nconstexpr std::uint32_t kAtomDinf = make_fourcc('d', 'i', 'n', 'f');\nconstexpr std::uint32_t kAtomMvex = make_fourcc('m', 'v', 'e', 'x');\nconstexpr std::uint32_t kTagName = make_fourcc(0xA9, 'n', 'a', 'm');\nconstexpr std::uint32_t kTagArtist = make_fourcc(0xA9, 'A', 'R', 'T');\nconstexpr std::uint32_t kTagAlbumArtist = make_fourcc('a', 'A', 'R', 'T');\nconstexpr std::uint32_t kTagAlbum = make_fourcc(0xA9, 'a', 'l', 'b');\nconstexpr std::uint32_t kTagDate = make_fourcc(0xA9, 'd', 'a', 'y');\nconstexpr std::uint32_t kTagTitle3gp = make_fourcc('t', 'i', 't', 'l');\nconstexpr std::uint32_t kTagArtist3gp = make_fourcc('a', 'u', 't', 'h');\nconstexpr std::uint32_t kTagAlbum3gp = make_fourcc('a', 'l', 'b', 'm');\nconstexpr std::uint32_t kTagYear3gp = make_fourcc('y', 'r', 'r', 'c');\n\nbool seek_to(std::istream& input, std::uint64_t offset)\n{\n    constexpr std::uint64_t kMaxStreamOff =\n        static_cast<std::uint64_t>(std::numeric_limits<std::streamoff>::max());\n    if (offset > kMaxStreamOff) {\n        return false;\n    }\n\n    input.clear();\n    input.seekg(static_cast<std::streamoff>(offset), std::ios::beg);\n    return input.good();\n}\n\nbool read_at(std::istream& input, std::uint64_t offset, std::uint8_t* destination, std::size_t size)\n{\n    if (destination == nullptr || size == 0) {\n        return true;\n    }\n    if (!seek_to(input, offset)) {\n        return false;\n    }\n    return read_exact(input, reinterpret_cast<char*>(destination), size);\n}\n\nbool is_mp4_container_atom(std::uint32_t atom_type)\n{\n    return atom_type == kAtomMoov ||\n           atom_type == kAtomUdta ||\n           atom_type == kAtomMeta ||\n           atom_type == kAtomIlst ||\n           atom_type == kAtomTrak ||\n           atom_type == kAtomMdia ||\n           atom_type == kAtomMinf ||\n           atom_type == kAtomStbl ||\n           atom_type == kAtomEdts ||\n           atom_type == kAtomDinf ||\n           atom_type == kAtomMvex;\n}\n\nbool is_mp4_metadata_key_atom(std::uint32_t atom_type)\n{\n    return atom_type == kTagName ||\n           atom_type == kTagArtist ||\n           atom_type == kTagAlbumArtist ||\n           atom_type == kTagAlbum ||\n           atom_type == kTagDate ||\n           atom_type == kTagTitle3gp ||\n           atom_type == kTagArtist3gp ||\n           atom_type == kTagAlbum3gp ||\n           atom_type == kTagYear3gp;\n}\n\nstd::string decode_utf16_ascii_fallback(const std::uint8_t* bytes, std::size_t size)\n{\n    if (bytes == nullptr || size < 2) {\n        return std::string();\n    }\n\n    bool little_endian = false;\n    std::size_t offset = 0;\n    if (size >= 2) {\n        if (bytes[0] == 0xFF && bytes[1] == 0xFE) {\n            little_endian = true;\n            offset = 2;\n        } else if (bytes[0] == 0xFE && bytes[1] == 0xFF) {\n            little_endian = false;\n            offset = 2;\n        }\n    }\n\n    std::string decoded;\n    decoded.reserve(size / 2);\n    for (std::size_t index = offset; index + 1 < size; index += 2) {\n        const std::uint16_t code_unit = little_endian\n                                            ? static_cast<std::uint16_t>(bytes[index]) |\n                                                  (static_cast<std::uint16_t>(bytes[index + 1]) << 8)\n                                            : (static_cast<std::uint16_t>(bytes[index]) << 8) |\n                                                  static_cast<std::uint16_t>(bytes[index + 1]);\n        if (code_unit == 0) {\n            break;\n        }\n        if (code_unit <= 0x7F) {\n            decoded.push_back(static_cast<char>(code_unit));\n        } else {\n            decoded.push_back(' ');\n        }\n    }\n\n    return sanitize_metadata_value(decoded);\n}\n\nstd::optional<std::string> parse_mp4_data_text(const std::vector<std::uint8_t>& payload)\n{\n    if (payload.size() < 8) {\n        return std::nullopt;\n    }\n\n    const std::uint32_t marker_a = read_u32_be(payload.data());\n    const std::uint32_t marker_b = read_u32_be(payload.data() + 4);\n\n    std::uint32_t data_type = marker_a;\n    if ((marker_a == 0 || marker_a > 32) &&\n        (marker_b == 1 || marker_b == 2 || marker_b == 0 || marker_b == 21)) {\n        data_type = marker_b;\n    }\n\n    const std::uint8_t* text_bytes = payload.data() + 8;\n    const std::size_t text_size = payload.size() - 8;\n    if (text_size == 0) {\n        return std::nullopt;\n    }\n\n    std::string decoded;\n    if (data_type == 2) {\n        decoded = decode_utf16_ascii_fallback(text_bytes, text_size);\n    } else {\n        decoded.assign(reinterpret_cast<const char*>(text_bytes), text_size);\n        if (const auto null_index = decoded.find('\\0'); null_index != std::string::npos) {\n            decoded.resize(null_index);\n        }\n        decoded = sanitize_metadata_value(decoded);\n    }\n\n    if (decoded.empty()) {\n        return std::nullopt;\n    }\n    return decoded;\n}\n\nvoid assign_mp4_metadata_field(std::uint32_t atom_type,\n                               const std::string& value,\n                               MediaRenameMetadataService::MetadataFields& metadata)\n{\n    if (value.empty()) {\n        return;\n    }\n\n    if (atom_type == kTagName || atom_type == kTagTitle3gp) {\n        assign_if_missing(metadata.title, value);\n        return;\n    }\n    if (atom_type == kTagArtist || atom_type == kTagAlbumArtist || atom_type == kTagArtist3gp) {\n        assign_if_missing(metadata.artist, value);\n        return;\n    }\n    if (atom_type == kTagAlbum || atom_type == kTagAlbum3gp) {\n        assign_if_missing(metadata.album, value);\n        return;\n    }\n    if (atom_type == kTagDate || atom_type == kTagYear3gp) {\n        assign_if_missing(metadata.year, value);\n    }\n}\n\nvoid parse_mp4_atoms(std::istream& input,\n                     std::uint64_t range_start,\n                     std::uint64_t range_end,\n                     std::optional<std::uint32_t> current_tag,\n                     std::size_t depth,\n                     MediaRenameMetadataService::MetadataFields& metadata)\n{\n    if (depth > 12 || range_start >= range_end) {\n        return;\n    }\n\n    std::uint64_t offset = range_start;\n    while (offset + 8 <= range_end) {\n        std::uint8_t header[16] = {};\n        if (!read_at(input, offset, header, 8)) {\n            return;\n        }\n\n        std::uint64_t atom_size = read_u32_be(header);\n        const std::uint32_t atom_type = read_u32_be(header + 4);\n        std::uint64_t atom_header_size = 8;\n\n        if (atom_size == 1) {\n            if (!read_at(input, offset + 8, header + 8, 8)) {\n                return;\n            }\n            atom_size = read_u64_be(header + 8);\n            atom_header_size = 16;\n        } else if (atom_size == 0) {\n            atom_size = range_end - offset;\n        }\n\n        if (atom_size < atom_header_size) {\n            return;\n        }\n        const std::uint64_t atom_end = offset + atom_size;\n        if (atom_end < offset || atom_end > range_end) {\n            return;\n        }\n\n        std::uint64_t payload_start = offset + atom_header_size;\n        const std::uint64_t payload_end = atom_end;\n\n        if (atom_type == kAtomMeta) {\n            if (payload_start + 4 > payload_end) {\n                offset = atom_end;\n                continue;\n            }\n            payload_start += 4;\n        }\n\n        if (atom_type == kAtomData && current_tag.has_value()) {\n            const std::uint64_t payload_size = payload_end - payload_start;\n            if (payload_size >= 8 && payload_size <= 64 * 1024) {\n                std::vector<std::uint8_t> data(static_cast<std::size_t>(payload_size));\n                if (read_at(input, payload_start, data.data(), data.size())) {\n                    if (const auto text = parse_mp4_data_text(data)) {\n                        assign_mp4_metadata_field(*current_tag, *text, metadata);\n                    }\n                }\n            }\n        }\n\n        bool descend = false;\n        std::optional<std::uint32_t> next_tag = current_tag;\n        if (is_mp4_metadata_key_atom(atom_type)) {\n            descend = true;\n            next_tag = atom_type;\n        } else if (is_mp4_container_atom(atom_type)) {\n            descend = true;\n            if (atom_type == kAtomIlst) {\n                next_tag.reset();\n            }\n        } else if (current_tag.has_value() && atom_type != kAtomData) {\n            descend = true;\n        }\n\n        if (descend && payload_start < payload_end) {\n            parse_mp4_atoms(input, payload_start, payload_end, next_tag, depth + 1, metadata);\n        }\n\n        if (atom_size == 0) {\n            return;\n        }\n        offset = atom_end;\n    }\n}\n\nbool parse_mp4_style_metadata(const std::filesystem::path& media_path,\n                              MediaRenameMetadataService::MetadataFields& metadata)\n{\n    std::ifstream input(media_path, std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    input.seekg(0, std::ios::end);\n    const std::streamoff file_size = input.tellg();\n    if (file_size <= 0) {\n        return false;\n    }\n\n    parse_mp4_atoms(input,\n                    0,\n                    static_cast<std::uint64_t>(file_size),\n                    std::nullopt,\n                    0,\n                    metadata);\n    return has_metadata_parts(metadata);\n}\n\nstd::optional<MediaRenameMetadataService::MetadataFields> parse_media_metadata_without_mediainfo(\n    const std::filesystem::path& media_path)\n{\n    if (!MediaRenameMetadataService::is_supported_media(media_path)) {\n        return std::nullopt;\n    }\n\n    MediaRenameMetadataService::MetadataFields metadata;\n    const std::string extension = to_lower_copy(Utils::path_to_utf8(media_path.extension()));\n\n    if (is_supported_audio(media_path)) {\n        parse_id3v2_from_file(media_path, metadata);\n\n        if (extension == \".mp3\") {\n            parse_id3v1_from_file(media_path, metadata);\n        } else if (extension == \".flac\") {\n            parse_flac_vorbis_comments(media_path, metadata);\n        } else if (extension == \".ogg\" || extension == \".oga\" || extension == \".opus\") {\n            parse_ogg_comments(media_path, metadata);\n        } else if (extension == \".m4a\") {\n            parse_mp4_style_metadata(media_path, metadata);\n        }\n    }\n\n    if (is_supported_video(media_path)) {\n        if (extension == \".mp4\" || extension == \".m4v\" || extension == \".mov\" || extension == \".3gp\") {\n            parse_mp4_style_metadata(media_path, metadata);\n        }\n    }\n\n    if (!has_metadata_parts(metadata)) {\n        return std::nullopt;\n    }\n    return metadata;\n}\n#endif\n\n#ifdef AI_FILE_SORTER_USE_MEDIAINFOLIB\nstd::string media_info_to_utf8(const MediaInfoCompat::String& value)\n{\n#if defined(UNICODE) || defined(_UNICODE)\n    const std::wstring wide_value(value.begin(), value.end());\n    return trim_copy(QString::fromStdWString(wide_value).toUtf8().toStdString());\n#else\n    return trim_copy(std::string(value.begin(), value.end()));\n#endif\n}\n\nstd::string query_field(MediaInfoCompat::MediaInfo& media_info,\n                        MediaInfoCompat::stream_t stream_kind,\n                        size_t stream_number,\n                        const MediaInfoCompat::Char* parameter)\n{\n    return media_info_to_utf8(media_info.Get(stream_kind,\n                                             stream_number,\n                                             parameter,\n                                             MediaInfoCompat::Info_Text,\n                                             MediaInfoCompat::Info_Name));\n}\n\ntemplate <size_t N>\nstd::optional<std::string> query_first_field(MediaInfoCompat::MediaInfo& media_info,\n                                             MediaInfoCompat::stream_t stream_kind,\n                                             size_t stream_number,\n                                             const std::array<const MediaInfoCompat::Char*, N>& keys)\n{\n    for (const auto* key : keys) {\n        const std::string value = query_field(media_info, stream_kind, stream_number, key);\n        if (!value.empty()) {\n            return value;\n        }\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> query_first_available(MediaInfoCompat::MediaInfo& media_info,\n                                                 const std::vector<std::pair<MediaInfoCompat::stream_t,\n                                                                             std::array<const MediaInfoCompat::Char*, 6>>>& probes)\n{\n    for (const auto& probe : probes) {\n        if (auto value = query_first_field(media_info, probe.first, 0, probe.second)) {\n            return value;\n        }\n    }\n    return std::nullopt;\n}\n#endif\n\n} // namespace\n\nstd::optional<std::string> MediaRenameMetadataService::suggest_name(const std::filesystem::path& media_path) const\n{\n    if (!is_supported_media(media_path)) {\n        return std::nullopt;\n    }\n\n    const auto metadata = extract_metadata(media_path);\n    if (!metadata.has_value()) {\n        return std::nullopt;\n    }\n\n    const std::string suggested = compose_filename(media_path, *metadata);\n    if (suggested.empty()) {\n        return std::nullopt;\n    }\n\n    const std::string original = Utils::path_to_utf8(media_path.filename());\n    if (to_lower_copy(suggested) == to_lower_copy(original)) {\n        return std::nullopt;\n    }\n\n    return suggested;\n}\n\nbool MediaRenameMetadataService::is_supported_media(const std::filesystem::path& path)\n{\n    return is_supported_audio(path) || is_supported_video(path);\n}\n\nstd::string MediaRenameMetadataService::compose_filename(const std::filesystem::path& original_path,\n                                                         const MetadataFields& metadata)\n{\n    const std::string original_name = Utils::path_to_utf8(original_path.filename());\n    if (original_name.empty()) {\n        return std::string();\n    }\n    if (!has_metadata_parts(metadata)) {\n        return original_name;\n    }\n\n    const std::string extension = Utils::path_to_utf8(original_path.extension());\n    const std::string fallback_stem = Utils::path_to_utf8(original_path.stem());\n\n    std::vector<std::string> parts;\n    parts.reserve(4);\n\n    if (metadata.year.has_value()) {\n        if (const auto year = normalize_year(*metadata.year)) {\n            parts.push_back(*year);\n        }\n    }\n\n    const auto append_slug = [&parts](const std::optional<std::string>& value) {\n        if (!value.has_value() || value->empty()) {\n            return;\n        }\n        const std::string slug = MediaRenameMetadataService::slugify(*value);\n        if (!slug.empty()) {\n            parts.push_back(slug);\n        }\n    };\n\n    append_slug(metadata.artist);\n    append_slug(metadata.album);\n\n    std::string title_slug;\n    if (metadata.title.has_value()) {\n        title_slug = slugify(*metadata.title);\n    }\n    if (title_slug.empty()) {\n        title_slug = slugify(fallback_stem);\n    }\n    if (!title_slug.empty()) {\n        parts.push_back(title_slug);\n    }\n\n    if (parts.empty()) {\n        return original_name;\n    }\n\n    std::string base_name;\n    for (size_t index = 0; index < parts.size(); ++index) {\n        if (index > 0) {\n            base_name.push_back('_');\n        }\n        base_name += parts[index];\n    }\n\n    if (base_name.empty()) {\n        return original_name;\n    }\n\n    return extension.empty() ? base_name : base_name + extension;\n}\n\nstd::optional<MediaRenameMetadataService::MetadataFields> MediaRenameMetadataService::extract_metadata(\n    const std::filesystem::path& media_path)\n{\n#ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB\n    auto metadata = parse_media_metadata_without_mediainfo(media_path);\n    if (!metadata.has_value()) {\n        return std::nullopt;\n    }\n\n    if (metadata->year.has_value()) {\n        metadata->year = normalize_year(*metadata->year);\n        if (!metadata->year.has_value()) {\n            metadata->year.reset();\n        }\n    }\n\n    if (!has_metadata_parts(*metadata)) {\n        return std::nullopt;\n    }\n\n    return metadata;\n#else\n    if (!is_supported_media(media_path)) {\n        return std::nullopt;\n    }\n\n    MediaInfoCompat::MediaInfo media_info;\n\n#if defined(UNICODE) || defined(_UNICODE)\n    const std::wstring wide_path = media_path.wstring();\n    const MediaInfoCompat::String open_path(wide_path.begin(), wide_path.end());\n#else\n    const std::string utf8_path = Utils::path_to_utf8(media_path);\n    const MediaInfoCompat::String open_path(utf8_path.begin(), utf8_path.end());\n#endif\n\n    if (media_info.Open(open_path) == 0) {\n        return std::nullopt;\n    }\n\n    MetadataFields metadata;\n\n    const bool audio_file = is_supported_audio(media_path);\n    const bool video_file = is_supported_video(media_path);\n\n    if (audio_file) {\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kArtistGeneral = {\n            __T(\"Performer\"),\n            __T(\"Album_Artist\"),\n            __T(\"Artist\"),\n            __T(\"Composer\"),\n            __T(\"Track/Performer\"),\n            __T(\"Track/Artist\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kArtistAudio = {\n            __T(\"Performer\"),\n            __T(\"Album_Artist\"),\n            __T(\"Artist\"),\n            __T(\"Composer\"),\n            __T(\"Track/Performer\"),\n            __T(\"Track/Artist\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kAlbumGeneral = {\n            __T(\"Album\"),\n            __T(\"Track/Album\"),\n            __T(\"Movie\"),\n            __T(\"Collection\"),\n            __T(\"Show\"),\n            __T(\"PackageName\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kTitleGeneral = {\n            __T(\"Title\"),\n            __T(\"Track\"),\n            __T(\"Track/Title\"),\n            __T(\"Song\"),\n            __T(\"Movie\"),\n            __T(\"Name\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kTitleAudio = {\n            __T(\"Title\"),\n            __T(\"Track\"),\n            __T(\"Track/Title\"),\n            __T(\"Song\"),\n            __T(\"Name\"),\n            __T(\"Encoded_Library/Name\")\n        };\n\n        metadata.artist = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kArtistGeneral);\n        if (!metadata.artist.has_value()) {\n            metadata.artist = query_first_field(media_info, MediaInfoCompat::Stream_Audio, 0, kArtistAudio);\n        }\n\n        metadata.album = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kAlbumGeneral);\n\n        metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_General, 0, kTitleGeneral);\n        if (!metadata.title.has_value()) {\n            metadata.title = query_first_field(media_info, MediaInfoCompat::Stream_Audio, 0, kTitleAudio);\n        }\n    }\n\n    if (video_file) {\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kArtistVideoGeneral = {\n            __T(\"Performer\"),\n            __T(\"Director\"),\n            __T(\"Composer\"),\n            __T(\"Producer\"),\n            __T(\"Artist\"),\n            __T(\"Encoded_Library/Name\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kAlbumVideoGeneral = {\n            __T(\"Movie\"),\n            __T(\"Show\"),\n            __T(\"Album\"),\n            __T(\"Collection\"),\n            __T(\"Season\"),\n            __T(\"PackageName\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kTitleVideoGeneral = {\n            __T(\"Title\"),\n            __T(\"Movie\"),\n            __T(\"Track\"),\n            __T(\"Episode\"),\n            __T(\"Name\"),\n            __T(\"Series\")\n        };\n        static constexpr std::array<const MediaInfoCompat::Char*, 6> kTitleVideoStream = {\n            __T(\"Title\"),\n            __T(\"Track\"),\n            __T(\"Name\"),\n            __T(\"Movie\"),\n            __T(\"Episode\"),\n            __T(\"Series\")\n        };\n\n        if (!metadata.artist.has_value()) {\n            metadata.artist = query_first_field(media_info,\n                                                MediaInfoCompat::Stream_General,\n                                                0,\n                                                kArtistVideoGeneral);\n        }\n        if (!metadata.album.has_value()) {\n            metadata.album = query_first_field(media_info,\n                                               MediaInfoCompat::Stream_General,\n                                               0,\n                                               kAlbumVideoGeneral);\n        }\n        if (!metadata.title.has_value()) {\n            metadata.title = query_first_field(media_info,\n                                               MediaInfoCompat::Stream_General,\n                                               0,\n                                               kTitleVideoGeneral);\n        }\n        if (!metadata.title.has_value()) {\n            metadata.title = query_first_field(media_info,\n                                               MediaInfoCompat::Stream_Video,\n                                               0,\n                                               kTitleVideoStream);\n        }\n    }\n\n    static const std::vector<std::pair<MediaInfoCompat::stream_t,\n                                       std::array<const MediaInfoCompat::Char*, 6>>> kYearProbes = {\n        {\n            MediaInfoCompat::Stream_General,\n            {\n                __T(\"Recorded_Date\"),\n                __T(\"Released_Date\"),\n                __T(\"Encoded_Date\"),\n                __T(\"Mastered_Date\"),\n                __T(\"Tagged_Date\"),\n                __T(\"Date\")\n            }\n        },\n        {\n            MediaInfoCompat::Stream_Audio,\n            {\n                __T(\"Recorded_Date\"),\n                __T(\"Released_Date\"),\n                __T(\"Encoded_Date\"),\n                __T(\"Date\"),\n                __T(\"Mastered_Date\"),\n                __T(\"Tagged_Date\")\n            }\n        },\n        {\n            MediaInfoCompat::Stream_Video,\n            {\n                __T(\"Recorded_Date\"),\n                __T(\"Released_Date\"),\n                __T(\"Encoded_Date\"),\n                __T(\"Date\"),\n                __T(\"Mastered_Date\"),\n                __T(\"Tagged_Date\")\n            }\n        }\n    };\n\n    if (const auto raw_year = query_first_available(media_info, kYearProbes)) {\n        metadata.year = normalize_year(*raw_year);\n    }\n\n    media_info.Close();\n\n    if (!has_metadata_parts(metadata)) {\n        return std::nullopt;\n    }\n\n    return metadata;\n#endif\n}\n\nstd::string MediaRenameMetadataService::slugify(const std::string& value)\n{\n    std::string slug;\n    slug.reserve(value.size());\n    bool last_separator = false;\n\n    for (unsigned char ch : value) {\n        if (std::isalnum(ch)) {\n            slug.push_back(static_cast<char>(std::tolower(ch)));\n            last_separator = false;\n        } else if (!last_separator && !slug.empty()) {\n            slug.push_back('_');\n            last_separator = true;\n        }\n    }\n\n    while (!slug.empty() && slug.back() == '_') {\n        slug.pop_back();\n    }\n\n    return slug;\n}\n\nstd::optional<std::string> MediaRenameMetadataService::normalize_year(const std::string& value)\n{\n    if (value.size() < 4) {\n        return std::nullopt;\n    }\n\n    for (size_t index = 0; index + 3 < value.size(); ++index) {\n        const char c0 = value[index];\n        const char c1 = value[index + 1];\n        const char c2 = value[index + 2];\n        const char c3 = value[index + 3];\n\n        if (!std::isdigit(static_cast<unsigned char>(c0)) ||\n            !std::isdigit(static_cast<unsigned char>(c1)) ||\n            !std::isdigit(static_cast<unsigned char>(c2)) ||\n            !std::isdigit(static_cast<unsigned char>(c3))) {\n            continue;\n        }\n\n        const bool prefixed_by_digit =\n            index > 0 && std::isdigit(static_cast<unsigned char>(value[index - 1]));\n        const bool suffixed_by_digit =\n            (index + 4) < value.size() &&\n            std::isdigit(static_cast<unsigned char>(value[index + 4]));\n        if (prefixed_by_digit || suffixed_by_digit) {\n            continue;\n        }\n\n        const int year = (c0 - '0') * 1000 +\n                         (c1 - '0') * 100 +\n                         (c2 - '0') * 10 +\n                         (c3 - '0');\n        if (year >= 1900 && year <= 2100) {\n            return std::string{c0, c1, c2, c3};\n        }\n    }\n\n    return std::nullopt;\n}\n"
  },
  {
    "path": "app/lib/MovableCategorizedFile.cpp",
    "content": "#include \"MovableCategorizedFile.hpp\"\n#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include <filesystem>\n#include <cstdio>\n#include <algorithm>\n#include <cctype>\n#include <vector>\n\nnamespace {\ntemplate <typename Callable>\nvoid with_core_logger(Callable callable)\n{\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        callable(*logger);\n    }\n}\n\nstd::string to_lower_copy_str(std::string value) {\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {\n        return static_cast<char>(std::tolower(c));\n    });\n    return value;\n}\n\nbool contains_only_allowed_chars(const std::string& value) {\n    for (unsigned char ch : value) {\n        if (std::iscntrl(ch)) {\n            return false;\n        }\n        static const std::string forbidden = R\"(<>:\"/\\|?*)\";\n        if (forbidden.find(static_cast<char>(ch)) != std::string::npos) {\n            return false;\n        }\n        // Everything else is allowed (including non-ASCII letters and punctuation).\n    }\n    return true;\n}\n\nbool has_leading_or_trailing_space_or_dot(const std::string& value) {\n    if (value.empty()) {\n        return false;\n    }\n    const unsigned char first = static_cast<unsigned char>(value.front());\n    const unsigned char last = static_cast<unsigned char>(value.back());\n    // Only guard leading/trailing whitespace; dots are allowed.\n    return std::isspace(first) || std::isspace(last);\n}\n\nbool is_reserved_windows_name(const std::string& value) {\n    static const std::vector<std::string> reserved = {\n        \"con\",\"prn\",\"aux\",\"nul\",\n        \"com1\",\"com2\",\"com3\",\"com4\",\"com5\",\"com6\",\"com7\",\"com8\",\"com9\",\n        \"lpt1\",\"lpt2\",\"lpt3\",\"lpt4\",\"lpt5\",\"lpt6\",\"lpt7\",\"lpt8\",\"lpt9\"\n    };\n    const std::string lower = to_lower_copy_str(value);\n    return std::find(reserved.begin(), reserved.end(), lower) != reserved.end();\n}\n\nbool looks_like_extension_label(const std::string& value) {\n    const auto dot_pos = value.rfind('.');\n    if (dot_pos == std::string::npos || dot_pos == value.size() - 1) {\n        return false;\n    }\n    const std::string ext = value.substr(dot_pos + 1);\n    if (ext.empty() || ext.size() > 5) {\n        return false;\n    }\n    return std::all_of(ext.begin(), ext.end(), [](unsigned char ch) { return std::isalpha(ch); });\n}\n\nbool validate_labels(const std::string& category,\n                     const std::string& subcategory,\n                     std::string& error) {\n    constexpr size_t kMaxLabelLength = 80;\n    if (category.empty() || subcategory.empty()) {\n        error = \"Category or subcategory is empty\";\n        return false;\n    }\n    if (category.size() > kMaxLabelLength || subcategory.size() > kMaxLabelLength) {\n        error = \"Category or subcategory exceeds max length\";\n        return false;\n    }\n    if (!contains_only_allowed_chars(category) || !contains_only_allowed_chars(subcategory)) {\n        error = \"Category or subcategory contains disallowed characters\";\n        return false;\n    }\n    if (looks_like_extension_label(category) || looks_like_extension_label(subcategory)) {\n        error = \"Category or subcategory looks like a file extension\";\n        return false;\n    }\n    if (is_reserved_windows_name(category) || is_reserved_windows_name(subcategory)) {\n        error = \"Category or subcategory is a reserved name\";\n        return false;\n    }\n    if (has_leading_or_trailing_space_or_dot(category) || has_leading_or_trailing_space_or_dot(subcategory)) {\n        error = \"Category or subcategory has leading/trailing space or dot\";\n        return false;\n    }\n    return true;\n}\n}\n\nMovableCategorizedFile::MovePaths\nMovableCategorizedFile::build_move_paths(bool use_subcategory) const\n{\n    const std::filesystem::path base_dir = Utils::utf8_to_path(dir_path);\n    const std::filesystem::path category_segment = Utils::utf8_to_path(category);\n    const std::filesystem::path subcategory_segment = Utils::utf8_to_path(subcategory);\n    const std::filesystem::path file_segment = Utils::utf8_to_path(file_name);\n    const std::filesystem::path destination_segment = Utils::utf8_to_path(destination_file_name);\n\n    const std::filesystem::path categorized_root = use_subcategory\n        ? base_dir / category_segment / subcategory_segment\n        : base_dir / category_segment;\n\n    return MovePaths{\n        Utils::utf8_to_path(source_dir) / file_segment,\n        categorized_root / destination_segment\n    };\n}\n\nbool MovableCategorizedFile::source_is_available(const std::filesystem::path& source_path) const\n{\n    if (std::filesystem::exists(source_path)) {\n        return true;\n    }\n\n    with_core_logger([&](auto& logger) {\n        logger.warn(\"Source file missing when moving '{}': {}\", file_name, Utils::path_to_utf8(source_path));\n    });\n    return false;\n}\n\nbool MovableCategorizedFile::destination_is_available(const std::filesystem::path& destination_path) const\n{\n    if (!std::filesystem::exists(destination_path)) {\n        return true;\n    }\n\n    with_core_logger([&](auto& logger) {\n        logger.info(\"Destination already contains '{}'; skipping move\", Utils::path_to_utf8(destination_path));\n    });\n    return false;\n}\n\nbool MovableCategorizedFile::perform_move(const std::filesystem::path& source_path,\n                                          const std::filesystem::path& destination_path) const\n{\n    try {\n        std::filesystem::rename(source_path, destination_path);\n        with_core_logger([&](auto& logger) {\n            logger.info(\"Moved '{}' to '{}'\", Utils::path_to_utf8(source_path), Utils::path_to_utf8(destination_path));\n        });\n        return true;\n    } catch (const std::filesystem::filesystem_error& e) {\n        with_core_logger([&](auto& logger) {\n            logger.error(\"Failed to move '{}' to '{}': {}\", Utils::path_to_utf8(source_path), Utils::path_to_utf8(destination_path), e.what());\n        });\n        return false;\n    }\n}\n\n\nMovableCategorizedFile::MovableCategorizedFile(\n    const std::string& dir_path, const std::string& cat, const std::string& subcat,\n    const std::string& file_name, const std::string& destination_name)\n    : MovableCategorizedFile(dir_path, dir_path, cat, subcat, file_name, destination_name)\n{\n}\n\nMovableCategorizedFile::MovableCategorizedFile(\n    const std::string& source_dir,\n    const std::string& destination_root,\n    const std::string& cat,\n    const std::string& subcat,\n    const std::string& file_name,\n    const std::string& destination_name)\n    : file_name(file_name),\n      destination_file_name(destination_name.empty() ? file_name : destination_name),\n      source_dir(source_dir),\n      dir_path(destination_root),\n      category(cat),\n      subcategory(subcat)\n{\n    std::string validation_error;\n    if (!validate_labels(category, subcategory, validation_error)) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->error(\"Invalid path components while constructing MovableCategorizedFile (dir='{}', category='{}', subcategory='{}', file='{}'): {}\",\n                          dir_path, category, subcategory, file_name, validation_error);\n        }\n        throw std::runtime_error(\"Invalid category/subcategory: \" + validation_error);\n    }\n    if (dir_path.empty() || category.empty() || subcategory.empty() || file_name.empty()) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->error(\"Invalid path components while constructing MovableCategorizedFile (dir='{}', category='{}', subcategory='{}', file='{}')\",\n                          dir_path, category, subcategory, file_name);\n        }\n        throw std::runtime_error(\"Invalid path component in CategorizedFile constructor.\");\n    }\n\n    const std::filesystem::path base_dir = Utils::utf8_to_path(dir_path);\n    category_path = base_dir / Utils::utf8_to_path(category);\n    subcategory_path = category_path / Utils::utf8_to_path(subcategory);\n    destination_path = subcategory_path / Utils::utf8_to_path(destination_file_name);\n}\n\n\nvoid MovableCategorizedFile::create_cat_dirs(bool use_subcategory)\n{\n    try {\n        if (!std::filesystem::exists(category_path)) {\n            std::filesystem::create_directory(category_path);\n        }\n        if (use_subcategory && !std::filesystem::exists(subcategory_path)) {\n            std::filesystem::create_directory(subcategory_path);\n        }\n    } catch (const std::filesystem::filesystem_error& e) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->error(\"Failed to create directories for '{}': {}\", file_name, e.what());\n        }\n        throw;\n    }\n}\n\n\nbool MovableCategorizedFile::move_file(bool use_subcategory)\n{\n    const MovePaths paths = build_move_paths(use_subcategory);\n\n    if (!source_is_available(paths.source)) {\n        return false;\n    }\n\n    if (!destination_is_available(paths.destination)) {\n        return false;\n    }\n\n    return perform_move(paths.source, paths.destination);\n}\n\nMovableCategorizedFile::PreviewPaths\nMovableCategorizedFile::preview_move_paths(bool use_subcategory) const\n{\n    const MovePaths paths = build_move_paths(use_subcategory);\n    return PreviewPaths{\n        Utils::path_to_utf8(paths.source),\n        Utils::path_to_utf8(paths.destination)\n    };\n}\n\n\nstd::string MovableCategorizedFile::get_subcategory_path() const\n{\n    return Utils::path_to_utf8(subcategory_path);\n}\n\n\nstd::string MovableCategorizedFile::get_category_path() const\n{\n    return Utils::path_to_utf8(category_path);\n}\n\n\nstd::string MovableCategorizedFile::get_destination_path() const\n{\n    return Utils::path_to_utf8(destination_path);\n}\n\n\nstd::string MovableCategorizedFile::get_file_name() const\n{\n    return file_name;\n}\n\nstd::string MovableCategorizedFile::get_dir_path() const\n{\n    return dir_path;\n}\n\nstd::string MovableCategorizedFile::get_category() const\n{\n    return category;\n}\n\nstd::string MovableCategorizedFile::get_subcategory() const\n{\n    return subcategory;\n}\n\nvoid MovableCategorizedFile::set_category(std::string& category)\n{\n    this->category = category;\n}\n\nvoid MovableCategorizedFile::set_subcategory(std::string& subcategory)\n{\n    this->subcategory = subcategory;\n}\n\nMovableCategorizedFile::~MovableCategorizedFile() {}\n"
  },
  {
    "path": "app/lib/PugixmlBundle.cpp",
    "content": "#if defined(AI_FILE_SORTER_USE_PUGIXML)\n#include \"pugixml.hpp\"\n#include \"pugixml.cpp\"\n#endif\n"
  },
  {
    "path": "app/lib/ResultsCoordinator.cpp",
    "content": "#include \"ResultsCoordinator.hpp\"\n\n#include <algorithm>\n#include <filesystem>\n\nResultsCoordinator::ResultsCoordinator(FileScanner& scanner)\n    : scanner(scanner)\n{\n}\n\nstd::vector<FileEntry> ResultsCoordinator::list_directory(const std::string& directory,\n                                                          FileScanOptions options) const\n{\n    return scanner.get_directory_entries(directory, options);\n}\n\nstd::vector<FileEntry> ResultsCoordinator::find_files_to_categorize(\n    const std::string& directory_path,\n    FileScanOptions options,\n    const std::unordered_set<std::string>& cached_files,\n    bool use_full_path_keys) const\n{\n    std::vector<FileEntry> actual_files = list_directory(directory_path, options);\n\n    std::vector<FileEntry> found_files;\n    found_files.reserve(actual_files.size());\n\n    for (const auto& entry : actual_files) {\n        const std::string key = use_full_path_keys ? entry.full_path : entry.file_name;\n        if (!cached_files.contains(key)) {\n            found_files.push_back(entry);\n        }\n    }\n\n    return found_files;\n}\n\nstd::vector<CategorizedFile> ResultsCoordinator::compute_files_to_sort(\n    const std::string& directory_path,\n    FileScanOptions options,\n    const std::vector<FileEntry>& actual_files,\n    const std::vector<CategorizedFile>& categorized_files,\n    bool use_full_path_keys) const\n{\n    (void)directory_path;\n    (void)options;\n    std::vector<CategorizedFile> files_to_sort;\n    files_to_sort.reserve(actual_files.size());\n\n    for (const auto& entry : actual_files) {\n        const auto it = std::find_if(\n            categorized_files.begin(),\n            categorized_files.end(),\n            [&entry, use_full_path_keys](const CategorizedFile& categorized_file) {\n                if (categorized_file.type != entry.type) {\n                    return false;\n                }\n                if (use_full_path_keys) {\n                    const auto full_path = std::filesystem::path(categorized_file.file_path) /\n                                           std::filesystem::path(categorized_file.file_name);\n                    return full_path == std::filesystem::path(entry.full_path);\n                }\n                return categorized_file.file_name == entry.file_name;\n            });\n\n        if (it != categorized_files.end()) {\n            files_to_sort.push_back(*it);\n        }\n    }\n\n    return files_to_sort;\n}\n\nstd::unordered_set<std::string> ResultsCoordinator::extract_file_names(\n    const std::vector<CategorizedFile>& categorized_files,\n    bool use_full_path_keys) const\n{\n    std::unordered_set<std::string> file_names;\n    file_names.reserve(categorized_files.size());\n    for (const auto& file : categorized_files) {\n        if (use_full_path_keys) {\n            const auto full_path = std::filesystem::path(file.file_path) /\n                                   std::filesystem::path(file.file_name);\n            file_names.insert(full_path.string());\n        } else {\n            file_names.insert(file.file_name);\n        }\n    }\n    return file_names;\n}\n"
  },
  {
    "path": "app/lib/Settings.cpp",
    "content": "#include \"Settings.hpp\"\n#include \"Types.hpp\"\n#include \"Logger.hpp\"\n#include \"Language.hpp\"\n#include \"Utils.hpp\"\n#include <filesystem>\n#include <cstdio>\n#include <iostream>\n#include <QStandardPaths>\n#include <QLocale>\n#include <QString>\n#include <QByteArray>\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/fmt.h>\n#include <algorithm>\n#include <sstream>\n#include <cctype>\n#include <chrono>\n#include <random>\n#ifdef _WIN32\n    #include <shlobj.h>\n    #include <windows.h>\n#endif\n\n\nnamespace {\ntemplate <typename... Args>\nvoid settings_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) {\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nint parse_int_or(const std::string& value, int fallback) {\n    try {\n        return std::stoi(value);\n    } catch (...) {\n        return fallback;\n    }\n}\n\nstd::vector<std::string> parse_list(const std::string& value) {\n    std::vector<std::string> result;\n    std::stringstream ss(value);\n    std::string item;\n    while (std::getline(ss, item, ',')) {\n        auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n        item.erase(item.begin(), std::find_if(item.begin(), item.end(), not_space));\n        item.erase(std::find_if(item.rbegin(), item.rend(), not_space).base(), item.end());\n        if (!item.empty()) {\n            result.push_back(item);\n        }\n    }\n    return result;\n}\n\nstd::string trim_copy(const std::string& value) {\n    auto trimmed = value;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    return trimmed;\n}\n\nstd::string join_list(const std::vector<std::string>& items) {\n    std::ostringstream oss;\n    for (size_t i = 0; i < items.size(); ++i) {\n        if (i > 0) {\n            oss << \",\";\n        }\n        oss << items[i];\n    }\n    return oss.str();\n}\n\nstd::string to_bool_string(bool value) {\n    return value ? \"true\" : \"false\";\n}\n\nstd::string encode_multiline(const std::string& value) {\n    std::string output;\n    output.reserve(value.size());\n    for (char ch : value) {\n        if (ch == '\\\\') {\n            output.append(\"\\\\\\\\\");\n        } else if (ch == '\\n') {\n            output.append(\"\\\\n\");\n        } else {\n            output.push_back(ch);\n        }\n    }\n    return output;\n}\n\nstd::string decode_multiline(const std::string& value) {\n    std::string output;\n    output.reserve(value.size());\n    for (size_t i = 0; i < value.size(); ++i) {\n        char ch = value[i];\n        if (ch == '\\\\' && i + 1 < value.size()) {\n            char next = value[i + 1];\n            if (next == 'n') {\n                output.push_back('\\n');\n                ++i;\n                continue;\n            }\n            if (next == '\\\\') {\n                output.push_back('\\\\');\n                ++i;\n                continue;\n            }\n        }\n        output.push_back(ch);\n    }\n    return output;\n}\n\nstd::string llm_choice_to_string(LLMChoice choice) {\n    switch (choice) {\n        case LLMChoice::Remote_OpenAI: return \"Remote_OpenAI\";\n        case LLMChoice::Remote_Gemini: return \"Remote_Gemini\";\n        case LLMChoice::Remote_Custom: return \"Remote_Custom\";\n        case LLMChoice::Local_3b: return \"Local_3b\";\n        case LLMChoice::Local_3b_legacy: return \"Local_3b_legacy\";\n        case LLMChoice::Local_7b: return \"Local_7b\";\n        case LLMChoice::Custom: return \"Custom\";\n        default: return \"Unset\";\n    }\n}\n\nvoid set_bool_setting(IniConfig& config, const std::string& section, const char* key, bool value) {\n    config.setValue(section, key, to_bool_string(value));\n}\n\nvoid set_optional_setting(IniConfig& config, const std::string& section, const char* key, const std::string& value) {\n    if (!value.empty()) {\n        config.setValue(section, key, value);\n    }\n}\n\nstd::string generate_custom_llm_id() {\n    using clock = std::chrono::steady_clock;\n    const auto now = clock::now().time_since_epoch().count();\n    std::mt19937_64 rng(static_cast<std::mt19937_64::result_type>(now));\n    const uint64_t value = rng();\n    std::ostringstream oss;\n    oss << \"llm_\" << std::hex << value;\n    return oss.str();\n}\n\nstd::string generate_custom_api_id() {\n    using clock = std::chrono::steady_clock;\n    const auto now = clock::now().time_since_epoch().count();\n    std::mt19937_64 rng(static_cast<std::mt19937_64::result_type>(now));\n    const uint64_t value = rng();\n    std::ostringstream oss;\n    oss << \"api_\" << std::hex << value;\n    return oss.str();\n}\n\nLanguage system_default_language()\n{\n    switch (QLocale::system().language()) {\n        case QLocale::French: return Language::French;\n        case QLocale::German: return Language::German;\n        case QLocale::Italian: return Language::Italian;\n        case QLocale::Spanish: return Language::Spanish;\n        case QLocale::Turkish: return Language::Turkish;\n        case QLocale::Korean: return Language::Korean;\n        case QLocale::Dutch: return Language::Dutch;\n        default: return Language::English;\n    }\n}\n\nstd::string path_from_env_url(const char* env_key)\n{\n    const char* url = std::getenv(env_key);\n    if (!url || *url == '\\0') {\n        return {};\n    }\n    try {\n        return Utils::make_default_path_to_file_from_download_url(url);\n    } catch (...) {\n        return {};\n    }\n}\n\nbool file_exists_for_env_url(const char* env_key)\n{\n    const std::string path = path_from_env_url(env_key);\n    if (path.empty()) {\n        return false;\n    }\n    std::error_code ec;\n    return std::filesystem::exists(path, ec);\n}\n}\n\n\nSettings::Settings()\n    : use_subcategories(true),\n      categorize_files(true),\n      categorize_directories(false),\n      include_subdirectories(false),\n      use_consistency_hints(false),\n      use_whitelist(false),\n      default_sort_folder(\"\"),\n      sort_folder(\"\")\n{\n    std::string AppName = \"AIFileSorter\";\n    config_path = define_config_path();\n\n    config_dir = std::filesystem::path(config_path).parent_path();\n\n    try {\n        if (!std::filesystem::exists(config_dir)) {\n            std::filesystem::create_directories(config_dir);\n        }\n    } catch (const std::filesystem::filesystem_error &e) {\n        settings_log(spdlog::level::err, \"Error creating configuration directory: {}\", e.what());\n    }\n\n    auto to_utf8 = [](const QString& value) -> std::string {\n        const QByteArray bytes = value.toUtf8();\n        return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));\n    };\n\n    QString downloads = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);\n    if (!downloads.isEmpty()) {\n        default_sort_folder = to_utf8(downloads);\n    } else {\n        QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);\n        if (!home.isEmpty()) {\n            default_sort_folder = to_utf8(home);\n        }\n    }\n\n    if (default_sort_folder.empty()) {\n        default_sort_folder = Utils::path_to_utf8(std::filesystem::current_path());\n    }\n\n    sort_folder = default_sort_folder;\n\n    // Default language follows system locale on first run (before any config file exists).\n    language = system_default_language();\n    category_language = CategoryLanguage::English;\n    analyze_images_by_content = false;\n    offer_rename_images = false;\n    add_image_date_place_to_filename = false;\n    add_audio_video_metadata_to_filename = true;\n    add_image_date_to_category = false;\n    analyze_documents_by_content = false;\n    offer_rename_documents = false;\n    rename_documents_only = false;\n    process_documents_only = false;\n    add_document_date_to_category = false;\n}\n\nLLMChoice Settings::parse_llm_choice() const\n{\n    const std::string value = config.getValue(\"Settings\", \"LLMChoice\", \"Unset\");\n    if (value == \"Remote\" || value == \"Remote_OpenAI\") return LLMChoice::Remote_OpenAI;\n    if (value == \"Remote_Gemini\") return LLMChoice::Remote_Gemini;\n    if (value == \"Remote_Custom\") return LLMChoice::Remote_Custom;\n    if (value == \"Local_3b\") return LLMChoice::Local_3b;\n    if (value == \"Local_3b_legacy\") return LLMChoice::Local_3b_legacy;\n    if (value == \"Local_7b\") return LLMChoice::Local_7b;\n    if (value == \"Custom\")   return LLMChoice::Custom;\n    return LLMChoice::Unset;\n}\n\nvoid Settings::load_basic_settings(const std::function<bool(const char*, bool)>& load_bool,\n                                   const std::function<int(const char*, int, int)>& load_int)\n{\n    llm_choice = parse_llm_choice();\n    set_openai_api_key(config.getValue(\"Settings\", \"RemoteApiKey\", \"\"));\n    set_openai_model(config.getValue(\"Settings\", \"RemoteModel\", \"gpt-4o-mini\"));\n    set_gemini_api_key(config.getValue(\"Settings\", \"GeminiApiKey\", \"\"));\n    set_gemini_model(config.getValue(\"Settings\", \"GeminiModel\", \"gemini-2.5-flash-lite\"));\n    llm_downloads_expanded = load_bool(\"LLMDownloadsExpanded\", true);\n    use_subcategories = load_bool(\"UseSubcategories\", false);\n    use_consistency_hints = load_bool(\"UseConsistencyHints\", false);\n    categorize_files = load_bool(\"CategorizeFiles\", true);\n    categorize_directories = load_bool(\"CategorizeDirectories\", false);\n    include_subdirectories = load_bool(\"IncludeSubdirectories\", false);\n    analyze_images_by_content = load_bool(\"AnalyzeImagesByContent\", false);\n    offer_rename_images = load_bool(\"OfferRenameImages\", false);\n    add_image_date_place_to_filename = load_bool(\"AddImageDatePlaceToFilename\", false);\n    add_audio_video_metadata_to_filename = load_bool(\"AddAudioVideoMetadataToFilename\", true);\n    add_image_date_to_category = load_bool(\"AddImageDateToCategory\", false);\n    rename_images_only = load_bool(\"RenameImagesOnly\", false);\n    process_images_only = load_bool(\"ProcessImagesOnly\", false);\n    analyze_documents_by_content = load_bool(\"AnalyzeDocumentsByContent\", false);\n    offer_rename_documents = load_bool(\"OfferRenameDocuments\", false);\n    rename_documents_only = load_bool(\"RenameDocumentsOnly\", false);\n    process_documents_only = load_bool(\"ProcessDocumentsOnly\", false);\n    add_document_date_to_category = load_bool(\"AddDocumentDateToCategory\", false);\n    const bool image_expand_default = process_images_only ||\n                                      offer_rename_images ||\n                                      rename_images_only ||\n                                      add_image_date_place_to_filename ||\n                                      add_image_date_to_category;\n    if (config.hasValue(\"Settings\", \"ImageOptionsExpanded\")) {\n        image_options_expanded = load_bool(\"ImageOptionsExpanded\", image_expand_default);\n    } else {\n        image_options_expanded = image_expand_default;\n    }\n    const bool document_expand_default = process_documents_only ||\n                                         offer_rename_documents ||\n                                         rename_documents_only ||\n                                         add_document_date_to_category;\n    if (config.hasValue(\"Settings\", \"DocumentOptionsExpanded\")) {\n        document_options_expanded = load_bool(\"DocumentOptionsExpanded\", document_expand_default);\n    } else {\n        document_options_expanded = document_expand_default;\n    }\n    if (rename_images_only && !offer_rename_images) {\n        offer_rename_images = true;\n    }\n    if (rename_documents_only && !offer_rename_documents) {\n        offer_rename_documents = true;\n    }\n    if (include_subdirectories && categorize_directories) {\n        categorize_directories = false;\n    }\n    sort_folder = config.getValue(\"Settings\", \"SortFolder\", default_sort_folder.empty() ? std::string(\"/\") : default_sort_folder);\n    show_file_explorer = load_bool(\"ShowFileExplorer\", true);\n    suitability_benchmark_completed = load_bool(\"SuitabilityBenchmarkCompleted\", false);\n    suitability_benchmark_suppressed = load_bool(\"SuitabilityBenchmarkSuppressed\", false);\n    benchmark_last_report = decode_multiline(config.getValue(\"Settings\", \"BenchmarkLastReport\", \"\"));\n    benchmark_last_run = config.getValue(\"Settings\", \"BenchmarkLastRun\", \"\");\n    consistency_pass_enabled = load_bool(\"ConsistencyPass\", false);\n    development_prompt_logging = load_bool(\"DevelopmentPromptLogging\", false);\n    skipped_version = config.getValue(\"Settings\", \"SkippedVersion\", \"0.0.0\");\n    if (config.hasValue(\"Settings\", \"Language\")) {\n        language = languageFromString(QString::fromStdString(config.getValue(\"Settings\", \"Language\", \"English\")));\n    } else {\n        language = system_default_language();\n    }\n    category_language = categoryLanguageFromString(QString::fromStdString(config.getValue(\"Settings\", \"CategoryLanguage\", \"English\")));\n    categorized_file_count = load_int(\"CategorizedFileCount\", 0, 0);\n    next_support_prompt_threshold = load_int(\"SupportPromptThreshold\", 50, 50);\n}\n\nvoid Settings::load_whitelist_settings(const std::function<bool(const char*, bool)>& load_bool)\n{\n    allowed_categories = parse_list(config.getValue(\"Settings\", \"AllowedCategories\", \"\"));\n    allowed_subcategories = parse_list(config.getValue(\"Settings\", \"AllowedSubcategories\", \"\"));\n    use_whitelist = load_bool(\"UseWhitelist\", false);\n    active_whitelist = config.getValue(\"Settings\", \"ActiveWhitelist\", \"\");\n}\n\nvoid Settings::load_custom_llm_settings()\n{\n    active_custom_llm_id = config.getValue(\"LLMs\", \"ActiveCustomId\", \"\");\n\n    custom_llms.clear();\n    const auto custom_ids = parse_list(config.getValue(\"LLMs\", \"CustomIds\", \"\"));\n    for (const auto& id : custom_ids) {\n        const std::string section = \"LLM_\" + id;\n        CustomLLM entry;\n        entry.id = id;\n        entry.name = config.getValue(section, \"Name\", \"\");\n        entry.description = config.getValue(section, \"Description\", \"\");\n        entry.path = config.getValue(section, \"Path\", \"\");\n        if (!entry.name.empty() && !entry.path.empty()) {\n            custom_llms.push_back(entry);\n        }\n    }\n}\n\nvoid Settings::load_custom_api_settings()\n{\n    active_custom_api_id = config.getValue(\"CustomApis\", \"ActiveCustomApiId\", \"\");\n\n    custom_api_endpoints.clear();\n    const auto api_ids = parse_list(config.getValue(\"CustomApis\", \"CustomApiIds\", \"\"));\n    for (const auto& id : api_ids) {\n        const std::string section = \"CustomApi_\" + id;\n        CustomApiEndpoint entry;\n        entry.id = id;\n        entry.name = config.getValue(section, \"Name\", \"\");\n        entry.description = config.getValue(section, \"Description\", \"\");\n        entry.base_url = config.getValue(section, \"BaseUrl\", \"\");\n        entry.api_key = config.getValue(section, \"ApiKey\", \"\");\n        entry.model = config.getValue(section, \"Model\", \"\");\n        entry.name = trim_copy(entry.name);\n        entry.description = trim_copy(entry.description);\n        entry.base_url = trim_copy(entry.base_url);\n        entry.api_key = trim_copy(entry.api_key);\n        entry.model = trim_copy(entry.model);\n        if (is_valid_custom_api_endpoint(entry)) {\n            custom_api_endpoints.push_back(entry);\n        }\n    }\n}\n\nvoid Settings::log_loaded_settings() const\n{\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->info(\"Loaded settings from '{}' (allowed categories: {}, allowed subcategories: {}, use whitelist: {}, active whitelist: '{}', custom llms: {}, custom apis: {}, category language: {})\",\n                     config_path,\n                     allowed_categories.size(),\n                     allowed_subcategories.size(),\n                     use_whitelist,\n                     active_whitelist,\n                     custom_llms.size(),\n                     custom_api_endpoints.size(),\n                     categoryLanguageDisplay(category_language));\n    }\n}\n\nvoid Settings::save_core_settings()\n{\n    static const std::string settings_section = \"Settings\";\n\n    config.setValue(settings_section, \"LLMChoice\", llm_choice_to_string(llm_choice));\n    config.setValue(settings_section, \"RemoteApiKey\", openai_api_key);\n    config.setValue(settings_section, \"RemoteModel\", openai_model.empty() ? \"gpt-4o-mini\" : openai_model);\n    config.setValue(settings_section, \"GeminiApiKey\", gemini_api_key);\n    config.setValue(settings_section, \"GeminiModel\", gemini_model.empty() ? \"gemini-2.5-flash-lite\" : gemini_model);\n    set_bool_setting(config, settings_section, \"LLMDownloadsExpanded\", llm_downloads_expanded);\n    set_bool_setting(config, settings_section, \"UseSubcategories\", use_subcategories);\n    set_bool_setting(config, settings_section, \"UseConsistencyHints\", use_consistency_hints);\n    set_bool_setting(config, settings_section, \"CategorizeFiles\", categorize_files);\n    set_bool_setting(config, settings_section, \"CategorizeDirectories\", categorize_directories);\n    set_bool_setting(config, settings_section, \"IncludeSubdirectories\", include_subdirectories);\n    if (rename_images_only) {\n        offer_rename_images = true;\n    }\n    if (rename_documents_only) {\n        offer_rename_documents = true;\n    }\n    set_bool_setting(config, settings_section, \"AnalyzeImagesByContent\", analyze_images_by_content);\n    set_bool_setting(config, settings_section, \"OfferRenameImages\", offer_rename_images);\n    set_bool_setting(config, settings_section, \"AddImageDatePlaceToFilename\", add_image_date_place_to_filename);\n    set_bool_setting(config, settings_section, \"AddAudioVideoMetadataToFilename\", add_audio_video_metadata_to_filename);\n    set_bool_setting(config, settings_section, \"AddImageDateToCategory\", add_image_date_to_category);\n    set_bool_setting(config, settings_section, \"ImageOptionsExpanded\", image_options_expanded);\n    set_bool_setting(config, settings_section, \"RenameImagesOnly\", rename_images_only);\n    set_bool_setting(config, settings_section, \"ProcessImagesOnly\", process_images_only);\n    set_bool_setting(config, settings_section, \"AnalyzeDocumentsByContent\", analyze_documents_by_content);\n    set_bool_setting(config, settings_section, \"OfferRenameDocuments\", offer_rename_documents);\n    set_bool_setting(config, settings_section, \"DocumentOptionsExpanded\", document_options_expanded);\n    set_bool_setting(config, settings_section, \"RenameDocumentsOnly\", rename_documents_only);\n    set_bool_setting(config, settings_section, \"ProcessDocumentsOnly\", process_documents_only);\n    set_bool_setting(config, settings_section, \"AddDocumentDateToCategory\", add_document_date_to_category);\n    config.setValue(settings_section, \"SortFolder\", this->sort_folder);\n\n    set_optional_setting(config, settings_section, \"SkippedVersion\", skipped_version);\n\n    set_bool_setting(config, settings_section, \"ShowFileExplorer\", show_file_explorer);\n    set_bool_setting(config, settings_section, \"SuitabilityBenchmarkCompleted\", suitability_benchmark_completed);\n    set_bool_setting(config, settings_section, \"SuitabilityBenchmarkSuppressed\", suitability_benchmark_suppressed);\n    set_optional_setting(config, settings_section, \"BenchmarkLastReport\", encode_multiline(benchmark_last_report));\n    set_optional_setting(config, settings_section, \"BenchmarkLastRun\", benchmark_last_run);\n    set_bool_setting(config, settings_section, \"ConsistencyPass\", consistency_pass_enabled);\n    set_bool_setting(config, settings_section, \"DevelopmentPromptLogging\", development_prompt_logging);\n    config.setValue(settings_section, \"Language\", languageToString(language).toStdString());\n    config.setValue(settings_section, \"CategoryLanguage\", categoryLanguageToString(category_language).toStdString());\n    config.setValue(settings_section, \"CategorizedFileCount\", std::to_string(categorized_file_count));\n    config.setValue(settings_section, \"SupportPromptThreshold\", std::to_string(next_support_prompt_threshold));\n}\n\nvoid Settings::save_whitelist_settings()\n{\n    static const std::string settings_section = \"Settings\";\n\n    config.setValue(settings_section, \"AllowedCategories\", join_list(allowed_categories));\n    config.setValue(settings_section, \"AllowedSubcategories\", join_list(allowed_subcategories));\n    set_bool_setting(config, settings_section, \"UseWhitelist\", use_whitelist);\n    set_optional_setting(config, settings_section, \"ActiveWhitelist\", active_whitelist);\n}\n\nvoid Settings::save_custom_llms()\n{\n    static const std::string llm_section = \"LLMs\";\n\n    set_optional_setting(config, llm_section, \"ActiveCustomId\", active_custom_llm_id);\n\n    std::vector<std::string> ids;\n    ids.reserve(custom_llms.size());\n    for (const auto& entry : custom_llms) {\n        if (!is_valid_custom_llm(entry)) {\n            continue;\n        }\n        ids.push_back(entry.id);\n        const std::string section = \"LLM_\" + entry.id;\n        config.setValue(section, \"Name\", entry.name);\n        config.setValue(section, \"Description\", entry.description);\n        config.setValue(section, \"Path\", entry.path);\n    }\n    config.setValue(llm_section, \"CustomIds\", join_list(ids));\n}\n\nvoid Settings::save_custom_api_endpoints()\n{\n    static const std::string api_section = \"CustomApis\";\n\n    set_optional_setting(config, api_section, \"ActiveCustomApiId\", active_custom_api_id);\n\n    std::vector<std::string> ids;\n    ids.reserve(custom_api_endpoints.size());\n    for (const auto& entry : custom_api_endpoints) {\n        if (!is_valid_custom_api_endpoint(entry)) {\n            continue;\n        }\n        ids.push_back(entry.id);\n        const std::string section = \"CustomApi_\" + entry.id;\n        config.setValue(section, \"Name\", entry.name);\n        config.setValue(section, \"Description\", entry.description);\n        config.setValue(section, \"BaseUrl\", entry.base_url);\n        config.setValue(section, \"ApiKey\", entry.api_key);\n        config.setValue(section, \"Model\", entry.model);\n    }\n    config.setValue(api_section, \"CustomApiIds\", join_list(ids));\n}\n\nstd::string Settings::define_config_path()\n{\n    std::string AppName = \"AIFileSorter\";\n    if (const char* override_root = std::getenv(\"AI_FILE_SORTER_CONFIG_DIR\")) {\n        std::filesystem::path base = override_root;\n        return (base / AppName / \"config.ini\").string();\n    }\n#ifdef _WIN32\n    char appDataPath[MAX_PATH];\n    if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, appDataPath))) {\n        return std::string(appDataPath) + \"\\\\\" + AppName + \"\\\\config.ini\";\n    }\n#elif defined(__APPLE__)\n    return std::string(getenv(\"HOME\")) + \"/Library/Application Support/\" + AppName + \"/config.ini\";\n#else\n    return std::string(getenv(\"HOME\")) + \"/.config/\" + AppName + \"/config.ini\";\n#endif\n    return \"config.ini\";\n}\n\n\nstd::string Settings::get_config_dir()\n{\n    return config_dir.string();\n}\n\n\nbool Settings::load()\n{\n    if (!config.load(config_path)) {\n        sort_folder = default_sort_folder.empty() ? std::string(\"/\") : default_sort_folder;\n        // Keep language defaults derived from system locale when no config is found.\n        return false;\n    }\n\n    const auto load_bool = [&](const char* key, bool def) {\n        return config.getValue(\"Settings\", key, def ? \"true\" : \"false\") == \"true\";\n    };\n\n    const auto load_int = [&](const char* key, int def, int min_val = std::numeric_limits<int>::min()) {\n        int value = parse_int_or(config.getValue(\"Settings\", key, std::to_string(def)), def);\n        return value < min_val ? min_val : value;\n    };\n\n    load_basic_settings(load_bool, load_int);\n    if (llm_choice == LLMChoice::Local_3b\n        && !file_exists_for_env_url(\"LOCAL_LLM_3B_DOWNLOAD_URL\")\n        && file_exists_for_env_url(\"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\")) {\n        llm_choice = LLMChoice::Local_3b_legacy;\n    }\n    load_whitelist_settings(load_bool);\n    load_custom_llm_settings();\n    load_custom_api_settings();\n    log_loaded_settings();\n\n    return true;\n}\n\n\nbool Settings::save()\n{\n    save_core_settings();\n    save_whitelist_settings();\n    save_custom_llms();\n    save_custom_api_endpoints();\n    return config.save(config_path);\n}\n\n\nLLMChoice Settings::get_llm_choice() const\n{\n    return llm_choice;\n}\n\n\nvoid Settings::set_llm_choice(LLMChoice choice)\n{\n    llm_choice = choice;\n}\n\nstd::string Settings::get_openai_api_key() const\n{\n    return openai_api_key;\n}\n\nvoid Settings::set_openai_api_key(const std::string& key)\n{\n    auto trimmed = key;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    openai_api_key = trimmed;\n}\n\nstd::string Settings::get_openai_model() const\n{\n    return openai_model;\n}\n\nvoid Settings::set_openai_model(const std::string& model)\n{\n    auto trimmed = model;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    if (trimmed.empty()) {\n        trimmed = \"gpt-4o-mini\";\n    }\n    openai_model = trimmed;\n}\n\nstd::string Settings::get_gemini_api_key() const\n{\n    return gemini_api_key;\n}\n\nvoid Settings::set_gemini_api_key(const std::string& key)\n{\n    auto trimmed = key;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    gemini_api_key = trimmed;\n}\n\nstd::string Settings::get_gemini_model() const\n{\n    return gemini_model;\n}\n\nvoid Settings::set_gemini_model(const std::string& model)\n{\n    auto trimmed = model;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    if (trimmed.empty()) {\n        trimmed = \"gemini-2.5-flash-lite\";\n    }\n    gemini_model = trimmed;\n}\n\nbool Settings::get_llm_downloads_expanded() const\n{\n    return llm_downloads_expanded;\n}\n\nvoid Settings::set_llm_downloads_expanded(bool value)\n{\n    llm_downloads_expanded = value;\n}\n\nstd::string Settings::get_active_custom_llm_id() const\n{\n    return active_custom_llm_id;\n}\n\nvoid Settings::set_active_custom_llm_id(const std::string& id)\n{\n    active_custom_llm_id = id;\n}\n\nconst std::vector<CustomLLM>& Settings::get_custom_llms() const\n{\n    return custom_llms;\n}\n\nCustomLLM Settings::find_custom_llm(const std::string& id) const\n{\n    const auto it = std::find_if(custom_llms.begin(), custom_llms.end(),\n                                 [&id](const CustomLLM& item) { return item.id == id; });\n    if (it != custom_llms.end()) {\n        return *it;\n    }\n    return {};\n}\n\nstd::string Settings::upsert_custom_llm(const CustomLLM& llm)\n{\n    CustomLLM copy = llm;\n    if (copy.id.empty()) {\n        copy.id = generate_custom_llm_id();\n    }\n    const auto it = std::find_if(custom_llms.begin(), custom_llms.end(),\n                                 [&copy](const CustomLLM& item) { return item.id == copy.id; });\n    if (it != custom_llms.end()) {\n        *it = copy;\n    } else {\n        custom_llms.push_back(copy);\n    }\n    return copy.id;\n}\n\nvoid Settings::remove_custom_llm(const std::string& id)\n{\n    custom_llms.erase(std::remove_if(custom_llms.begin(),\n                                     custom_llms.end(),\n                                     [&id](const CustomLLM& item) { return item.id == id; }),\n                      custom_llms.end());\n    if (active_custom_llm_id == id) {\n        active_custom_llm_id.clear();\n    }\n}\n\nstd::string Settings::get_active_custom_api_id() const\n{\n    return active_custom_api_id;\n}\n\nvoid Settings::set_active_custom_api_id(const std::string& id)\n{\n    active_custom_api_id = id;\n}\n\nconst std::vector<CustomApiEndpoint>& Settings::get_custom_api_endpoints() const\n{\n    return custom_api_endpoints;\n}\n\nCustomApiEndpoint Settings::find_custom_api_endpoint(const std::string& id) const\n{\n    const auto it = std::find_if(custom_api_endpoints.begin(), custom_api_endpoints.end(),\n                                 [&id](const CustomApiEndpoint& item) { return item.id == id; });\n    if (it != custom_api_endpoints.end()) {\n        return *it;\n    }\n    return {};\n}\n\nstd::string Settings::upsert_custom_api_endpoint(const CustomApiEndpoint& endpoint)\n{\n    CustomApiEndpoint copy = endpoint;\n    if (copy.id.empty()) {\n        copy.id = generate_custom_api_id();\n    }\n    copy.name = trim_copy(copy.name);\n    copy.description = trim_copy(copy.description);\n    copy.base_url = trim_copy(copy.base_url);\n    copy.api_key = trim_copy(copy.api_key);\n    copy.model = trim_copy(copy.model);\n    const auto it = std::find_if(custom_api_endpoints.begin(), custom_api_endpoints.end(),\n                                 [&copy](const CustomApiEndpoint& item) { return item.id == copy.id; });\n    if (it != custom_api_endpoints.end()) {\n        *it = copy;\n    } else {\n        custom_api_endpoints.push_back(copy);\n    }\n    return copy.id;\n}\n\nvoid Settings::remove_custom_api_endpoint(const std::string& id)\n{\n    custom_api_endpoints.erase(std::remove_if(custom_api_endpoints.begin(),\n                                             custom_api_endpoints.end(),\n                                             [&id](const CustomApiEndpoint& item) { return item.id == id; }),\n                               custom_api_endpoints.end());\n    if (active_custom_api_id == id) {\n        active_custom_api_id.clear();\n    }\n}\n\n\nbool Settings::is_llm_chosen() const {\n    return llm_choice != LLMChoice::Unset;\n}\n\nCategoryLanguage Settings::get_category_language() const\n{\n    return category_language;\n}\n\nvoid Settings::set_category_language(CategoryLanguage language)\n{\n    category_language = language;\n}\n\n\nbool Settings::get_use_subcategories() const\n{\n    return use_subcategories;\n}\n\n\nvoid Settings::set_use_subcategories(bool value)\n{\n    use_subcategories = value;\n}\n\nbool Settings::get_use_consistency_hints() const\n{\n    return use_consistency_hints;\n}\n\nvoid Settings::set_use_consistency_hints(bool value)\n{\n    use_consistency_hints = value;\n}\n\n\nbool Settings::get_categorize_files() const\n{\n    return categorize_files;\n}\n\n\nvoid Settings::set_categorize_files(bool value)\n{\n    categorize_files = value;\n}\n\n\nbool Settings::get_categorize_directories() const\n{\n    return categorize_directories;\n}\n\n\nvoid Settings::set_categorize_directories(bool value)\n{\n    categorize_directories = value;\n}\n\nbool Settings::get_include_subdirectories() const\n{\n    return include_subdirectories;\n}\n\nvoid Settings::set_include_subdirectories(bool value)\n{\n    include_subdirectories = value;\n}\n\nbool Settings::get_analyze_images_by_content() const\n{\n    return analyze_images_by_content;\n}\n\nvoid Settings::set_analyze_images_by_content(bool value)\n{\n    analyze_images_by_content = value;\n}\n\nbool Settings::get_offer_rename_images() const\n{\n    return offer_rename_images;\n}\n\nvoid Settings::set_offer_rename_images(bool value)\n{\n    offer_rename_images = value;\n}\n\nbool Settings::get_add_image_date_place_to_filename() const\n{\n    return add_image_date_place_to_filename;\n}\n\nvoid Settings::set_add_image_date_place_to_filename(bool value)\n{\n    add_image_date_place_to_filename = value;\n}\n\nbool Settings::get_add_audio_video_metadata_to_filename() const\n{\n    return add_audio_video_metadata_to_filename;\n}\n\nvoid Settings::set_add_audio_video_metadata_to_filename(bool value)\n{\n    add_audio_video_metadata_to_filename = value;\n}\n\nbool Settings::get_add_image_date_to_category() const\n{\n    return add_image_date_to_category;\n}\n\nvoid Settings::set_add_image_date_to_category(bool value)\n{\n    add_image_date_to_category = value;\n}\n\nbool Settings::get_image_options_expanded() const\n{\n    return image_options_expanded;\n}\n\nvoid Settings::set_image_options_expanded(bool value)\n{\n    image_options_expanded = value;\n}\n\nbool Settings::get_rename_images_only() const\n{\n    return rename_images_only;\n}\n\nvoid Settings::set_rename_images_only(bool value)\n{\n    rename_images_only = value;\n}\n\nbool Settings::get_process_images_only() const\n{\n    return process_images_only;\n}\n\nvoid Settings::set_process_images_only(bool value)\n{\n    process_images_only = value;\n}\n\nbool Settings::get_analyze_documents_by_content() const\n{\n    return analyze_documents_by_content;\n}\n\nvoid Settings::set_analyze_documents_by_content(bool value)\n{\n    analyze_documents_by_content = value;\n}\n\nbool Settings::get_offer_rename_documents() const\n{\n    return offer_rename_documents;\n}\n\nvoid Settings::set_offer_rename_documents(bool value)\n{\n    offer_rename_documents = value;\n}\n\nbool Settings::get_document_options_expanded() const\n{\n    return document_options_expanded;\n}\n\nvoid Settings::set_document_options_expanded(bool value)\n{\n    document_options_expanded = value;\n}\n\nbool Settings::get_rename_documents_only() const\n{\n    return rename_documents_only;\n}\n\nvoid Settings::set_rename_documents_only(bool value)\n{\n    rename_documents_only = value;\n}\n\nbool Settings::get_process_documents_only() const\n{\n    return process_documents_only;\n}\n\nvoid Settings::set_process_documents_only(bool value)\n{\n    process_documents_only = value;\n}\n\nbool Settings::get_add_document_date_to_category() const\n{\n    return add_document_date_to_category;\n}\n\nvoid Settings::set_add_document_date_to_category(bool value)\n{\n    add_document_date_to_category = value;\n}\n\n\nstd::string Settings::get_sort_folder() const\n{\n    return sort_folder;\n}\n\n\nvoid Settings::set_sort_folder(const std::string &path)\n{\n    this->sort_folder = path;\n}\n\nbool Settings::get_consistency_pass_enabled() const\n{\n    return consistency_pass_enabled;\n}\n\nvoid Settings::set_consistency_pass_enabled(bool value)\n{\n    consistency_pass_enabled = value;\n}\n\nbool Settings::get_development_prompt_logging() const\n{\n    return development_prompt_logging;\n}\n\nvoid Settings::set_development_prompt_logging(bool value)\n{\n    development_prompt_logging = value;\n}\n\nbool Settings::get_use_whitelist() const\n{\n    return use_whitelist;\n}\n\nvoid Settings::set_use_whitelist(bool value)\n{\n    use_whitelist = value;\n}\n\nstd::string Settings::get_active_whitelist() const\n{\n    return active_whitelist;\n}\n\nvoid Settings::set_active_whitelist(const std::string& name)\n{\n    active_whitelist = name;\n}\n\n\nvoid Settings::set_skipped_version(const std::string &version) {\n    skipped_version = version;\n}\n\n\nstd::string Settings::get_skipped_version()\n{\n    return skipped_version;\n}\n\n\nvoid Settings::set_show_file_explorer(bool value)\n{\n    show_file_explorer = value;\n}\n\n\nbool Settings::get_show_file_explorer() const\n{\n    return show_file_explorer;\n}\n\nbool Settings::get_suitability_benchmark_completed() const\n{\n    return suitability_benchmark_completed;\n}\n\nbool Settings::get_suitability_benchmark_suppressed() const\n{\n    return suitability_benchmark_suppressed;\n}\n\nvoid Settings::set_suitability_benchmark_completed(bool value)\n{\n    suitability_benchmark_completed = value;\n}\n\nvoid Settings::set_suitability_benchmark_suppressed(bool value)\n{\n    suitability_benchmark_suppressed = value;\n}\n\nstd::string Settings::get_benchmark_last_report() const\n{\n    return benchmark_last_report;\n}\n\nvoid Settings::set_benchmark_last_report(const std::string& value)\n{\n    benchmark_last_report = value;\n}\n\nstd::string Settings::get_benchmark_last_run() const\n{\n    return benchmark_last_run;\n}\n\nvoid Settings::set_benchmark_last_run(const std::string& value)\n{\n    benchmark_last_run = value;\n}\n\n\nLanguage Settings::get_language() const\n{\n    return language;\n}\n\n\nvoid Settings::set_language(Language value)\n{\n    language = value;\n}\n\nint Settings::get_total_categorized_files() const\n{\n    return categorized_file_count;\n}\n\nvoid Settings::add_categorized_files(int count)\n{\n    if (count <= 0) {\n        return;\n    }\n    categorized_file_count += count;\n}\n\nint Settings::get_next_support_prompt_threshold() const\n{\n    return next_support_prompt_threshold;\n}\n\nvoid Settings::set_next_support_prompt_threshold(int threshold)\n{\n    if (threshold < 50) {\n        threshold = 50;\n    }\n    next_support_prompt_threshold = threshold;\n}\n\nstd::vector<std::string> Settings::get_allowed_categories() const\n{\n    return allowed_categories;\n}\n\nvoid Settings::set_allowed_categories(std::vector<std::string> values)\n{\n    allowed_categories = std::move(values);\n}\n\nstd::vector<std::string> Settings::get_allowed_subcategories() const\n{\n    return allowed_subcategories;\n}\n\nvoid Settings::set_allowed_subcategories(std::vector<std::string> values)\n{\n    allowed_subcategories = std::move(values);\n}\n"
  },
  {
    "path": "app/lib/SuitabilityBenchmarkDialog.cpp",
    "content": "#include \"SuitabilityBenchmarkDialog.hpp\"\n\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n#include \"LlmCatalog.hpp\"\n#include \"LocalLLMClient.hpp\"\n#include \"Settings.hpp\"\n#include \"Types.hpp\"\n#include \"Utils.hpp\"\n#include \"ggml-backend.h\"\n\n#include <QCloseEvent>\n#include <QColor>\n#include <QCheckBox>\n#include <QEvent>\n#include <QHBoxLayout>\n#include <QImage>\n#include <QLabel>\n#include <QMetaObject>\n#include <QPainter>\n#include <QObject>\n#include <QPointer>\n#include <QProgressBar>\n#include <QPushButton>\n#include <QRect>\n#include <QRegularExpression>\n#include <QScrollBar>\n#include <QString>\n#include <QTextCursor>\n#include <QTextEdit>\n#include <QVBoxLayout>\n\n#include <algorithm>\n#include <array>\n#include <cctype>\n#include <chrono>\n#include <cmath>\n#include <ctime>\n#include <cstdlib>\n#include <exception>\n#include <filesystem>\n#include <fstream>\n#include <functional>\n#include <iomanip>\n#include <optional>\n#include <sstream>\n#include <limits>\n#include <string>\n#include <string_view>\n#include <unordered_set>\n#include <utility>\n#include <vector>\n\nnamespace {\nstruct VisualLlmPaths {\n    std::filesystem::path model_path;\n    std::filesystem::path mmproj_path;\n};\n\nstd::optional<VisualLlmPaths> resolve_visual_llm_paths(std::string* error);\n\nenum class PerfClass {\n    Optimal,\n    Acceptable,\n    TooLong\n};\n\nstruct PerfThresholds {\n    double optimal_max{0.0};\n    double acceptable_max{0.0};\n};\n\nstd::string trim_copy(const std::string& value)\n{\n    std::string trimmed = value;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    return trimmed;\n}\n\nstd::string format_duration(std::chrono::steady_clock::duration elapsed)\n{\n    using namespace std::chrono;\n    const double seconds = duration_cast<milliseconds>(elapsed).count() / 1000.0;\n    std::ostringstream oss;\n    oss << std::fixed << std::setprecision(1) << seconds << \"s\";\n    return oss.str();\n}\n\ndouble duration_seconds(std::chrono::steady_clock::duration elapsed)\n{\n    using namespace std::chrono;\n    return duration_cast<milliseconds>(elapsed).count() / 1000.0;\n}\n\nstd::string format_seconds(double seconds)\n{\n    std::ostringstream oss;\n    oss << std::fixed << std::setprecision(1) << seconds << \"s\";\n    return oss.str();\n}\n\ndouble read_env_double(const char* key, double fallback)\n{\n    const char* value = std::getenv(key);\n    if (!value || !*value) {\n        return fallback;\n    }\n    try {\n        size_t idx = 0;\n        const double parsed = std::stod(value, &idx);\n        if (idx == 0) {\n            return fallback;\n        }\n        return parsed;\n    } catch (const std::exception&) {\n        return fallback;\n    }\n}\n\n\nPerfThresholds thresholds_for_choice(LLMChoice choice)\n{\n    switch (choice) {\n    case LLMChoice::Local_3b:\n        return PerfThresholds{\n            read_env_double(\"BENCH_CAT_LOCAL_3B_OPTIMAL_MAX\", 2.0),\n            read_env_double(\"BENCH_CAT_LOCAL_3B_ACCEPTABLE_MAX\", 5.0)};\n    case LLMChoice::Local_3b_legacy:\n        return PerfThresholds{\n            read_env_double(\"BENCH_CAT_LOCAL_3B_LEGACY_OPTIMAL_MAX\", 5.0),\n            read_env_double(\"BENCH_CAT_LOCAL_3B_LEGACY_ACCEPTABLE_MAX\", 10.0)};\n    case LLMChoice::Local_7b:\n        return PerfThresholds{\n            read_env_double(\"BENCH_CAT_LOCAL_7B_OPTIMAL_MAX\", 8.0),\n            read_env_double(\"BENCH_CAT_LOCAL_7B_ACCEPTABLE_MAX\", 12.0)};\n    default:\n        return PerfThresholds{\n            read_env_double(\"BENCH_CAT_DEFAULT_OPTIMAL_MAX\", 5.0),\n            read_env_double(\"BENCH_CAT_DEFAULT_ACCEPTABLE_MAX\", 10.0)};\n    }\n}\n\nPerfThresholds thresholds_for_document_choice(LLMChoice choice)\n{\n    switch (choice) {\n    case LLMChoice::Local_3b:\n        return PerfThresholds{\n            read_env_double(\"BENCH_DOC_LOCAL_3B_OPTIMAL_MAX\", 4.0),\n            read_env_double(\"BENCH_DOC_LOCAL_3B_ACCEPTABLE_MAX\", 7.0)};\n    case LLMChoice::Local_3b_legacy:\n        return PerfThresholds{\n            read_env_double(\"BENCH_DOC_LOCAL_3B_LEGACY_OPTIMAL_MAX\", 8.0),\n            read_env_double(\"BENCH_DOC_LOCAL_3B_LEGACY_ACCEPTABLE_MAX\", 12.0)};\n    case LLMChoice::Local_7b:\n        return PerfThresholds{\n            read_env_double(\"BENCH_DOC_LOCAL_7B_OPTIMAL_MAX\", 12.0),\n            read_env_double(\"BENCH_DOC_LOCAL_7B_ACCEPTABLE_MAX\", 15.0)};\n    default:\n        return PerfThresholds{\n            read_env_double(\"BENCH_DOC_DEFAULT_OPTIMAL_MAX\", 8.0),\n            read_env_double(\"BENCH_DOC_DEFAULT_ACCEPTABLE_MAX\", 12.0)};\n    }\n}\n\nPerfThresholds image_thresholds()\n{\n    return PerfThresholds{\n        read_env_double(\"BENCH_IMAGE_OPTIMAL_MAX\", 15.0),\n        read_env_double(\"BENCH_IMAGE_ACCEPTABLE_MAX\", 25.0)};\n}\n\nPerfClass classify_perf(double seconds, const PerfThresholds& thresholds)\n{\n    if (seconds <= thresholds.optimal_max) {\n        return PerfClass::Optimal;\n    }\n    if (seconds <= thresholds.acceptable_max) {\n        return PerfClass::Acceptable;\n    }\n    return PerfClass::TooLong;\n}\n\nint perf_rank(PerfClass perf)\n{\n    switch (perf) {\n    case PerfClass::Optimal:\n        return 0;\n    case PerfClass::Acceptable:\n        return 1;\n    case PerfClass::TooLong:\n        return 2;\n    }\n    return 2;\n}\n\nPerfClass worst_perf(PerfClass a, PerfClass b)\n{\n    return perf_rank(a) >= perf_rank(b) ? a : b;\n}\n\nQString perf_color(PerfClass perf)\n{\n    switch (perf) {\n    case PerfClass::Optimal:\n        return QStringLiteral(\"#1f6feb\");\n    case PerfClass::Acceptable:\n        return QStringLiteral(\"#f2c200\");\n    case PerfClass::TooLong:\n        return QStringLiteral(\"#d73a49\");\n    }\n    return QStringLiteral(\"#1f6feb\");\n}\n\nQString highlight_figures(const QString& text)\n{\n    static const QRegularExpression figure_pattern(QStringLiteral(R\"(\\b\\d+(?:\\.\\d+)?\\s*(?:MiB|s)\\b)\"));\n    const QString escaped = text.toHtmlEscaped();\n    QString result;\n    result.reserve(escaped.size() + 32);\n\n    int last_pos = 0;\n    auto match_it = figure_pattern.globalMatch(escaped);\n    while (match_it.hasNext()) {\n        const auto match = match_it.next();\n        const int start = match.capturedStart();\n        const int end = match.capturedEnd();\n        if (start < last_pos) {\n            continue;\n        }\n        result += escaped.mid(last_pos, start - last_pos);\n        result += QStringLiteral(\"<span style=\\\"color:#1f6feb;\\\">%1</span>\").arg(match.captured(0));\n        last_pos = end;\n    }\n    result += escaped.mid(last_pos);\n    return result;\n}\n\nQString bold_llm_label(const std::string& label)\n{\n    return QStringLiteral(\"<b>%1</b>\").arg(QString::fromStdString(label).toHtmlEscaped());\n}\n\nQString colored_seconds(double seconds, PerfClass perf)\n{\n    return QStringLiteral(\"<span style=\\\"color:%1;\\\">%2</span>\")\n        .arg(perf_color(perf))\n        .arg(QString::fromStdString(format_seconds(seconds)));\n}\n\nQString colored_seconds_list(const std::vector<double>& seconds,\n                             const std::function<PerfClass(double)>& classifier)\n{\n    QStringList parts;\n    parts.reserve(static_cast<int>(seconds.size()));\n    for (double value : seconds) {\n        const PerfClass perf = classifier(value);\n        parts << colored_seconds(value, perf);\n    }\n    return parts.join(QStringLiteral(\", \"));\n}\n\nstd::string format_mib(size_t bytes)\n{\n    constexpr double kToMiB = 1024.0 * 1024.0;\n    std::ostringstream oss;\n    oss << std::fixed << std::setprecision(1) << (static_cast<double>(bytes) / kToMiB) << \" MiB\";\n    return oss.str();\n}\n\nstd::string to_lower_copy(std::string value)\n{\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nstd::string read_env_lower(const char* key)\n{\n    const char* value = std::getenv(key);\n    if (!value || !*value) {\n        return {};\n    }\n    return to_lower_copy(value);\n}\n\nstd::optional<std::string> read_env_value(const char* key)\n{\n    const char* value = std::getenv(key);\n    if (!value) {\n        return std::nullopt;\n    }\n    return std::string(value);\n}\n\nvoid set_env_value(const char* key, const std::optional<std::string>& value)\n{\n#if defined(_WIN32)\n    if (value.has_value()) {\n        _putenv_s(key, value->c_str());\n    } else {\n        _putenv_s(key, \"\");\n    }\n#else\n    if (value.has_value()) {\n        setenv(key, value->c_str(), 1);\n    } else {\n        unsetenv(key);\n    }\n#endif\n}\n\nbool case_insensitive_contains(std::string_view haystack, std::string_view needle)\n{\n    if (needle.empty()) {\n        return true;\n    }\n    const std::string hay = to_lower_copy(std::string(haystack));\n    const std::string nee = to_lower_copy(std::string(needle));\n    return hay.find(nee) != std::string::npos;\n}\n\nstd::string format_timestamp(std::chrono::system_clock::time_point point)\n{\n    std::time_t time_value = std::chrono::system_clock::to_time_t(point);\n    std::tm local_time{};\n#if defined(_WIN32)\n    localtime_s(&local_time, &time_value);\n#else\n    localtime_r(&time_value, &local_time);\n#endif\n    std::ostringstream oss;\n    oss << std::put_time(&local_time, \"%Y-%m-%d %H:%M:%S\");\n    return oss.str();\n}\n\nstruct DefaultModel {\n    std::string label;\n    std::filesystem::path path;\n    LLMChoice choice;\n};\n\nstruct BackendTarget {\n    std::string key;\n    std::string label;\n};\n\nstruct BenchmarkBackendInfo {\n    bool cuda_available{false};\n    bool vulkan_available{false};\n    bool metal_available{false};\n    std::string vulkan_device;\n    std::string metal_device;\n    std::optional<std::string> blas_label;\n};\n\nstruct EnvEntry {\n    std::string key;\n    std::optional<std::string> value;\n};\n\nclass EnvSnapshot {\npublic:\n    static EnvSnapshot capture(const std::array<const char*, 3>& keys)\n    {\n        EnvSnapshot snapshot;\n        for (const char* key : keys) {\n            snapshot.entries_.push_back(EnvEntry{key, read_env_value(key)});\n        }\n        return snapshot;\n    }\n\n    void restore() const\n    {\n        for (const auto& entry : entries_) {\n            set_env_value(entry.key.c_str(), entry.value);\n        }\n    }\n\nprivate:\n    std::vector<EnvEntry> entries_;\n};\n\nclass ScopedEnvRestore {\npublic:\n    explicit ScopedEnvRestore(const EnvSnapshot& snapshot)\n        : snapshot_(snapshot)\n    {\n    }\n\n    ~ScopedEnvRestore()\n    {\n        snapshot_.restore();\n    }\n\nprivate:\n    const EnvSnapshot& snapshot_;\n};\n\nBackendTarget resolve_backend_target(std::string_view override_value)\n{\n    if (override_value == \"cpu\") {\n        return {\"cpu\", QObject::tr(\"CPU\").toStdString()};\n    }\n    if (override_value == \"metal\") {\n        return {\"metal\", QObject::tr(\"Metal\").toStdString()};\n    }\n    if (override_value == \"cuda\") {\n        return {\"cuda\", QObject::tr(\"CUDA\").toStdString()};\n    }\n    if (override_value == \"vulkan\") {\n        return {\"vulkan\", QObject::tr(\"Vulkan\").toStdString()};\n    }\n    if (override_value == \"auto\") {\n#if defined(__APPLE__)\n        return {\"metal\", QObject::tr(\"Metal (auto)\").toStdString()};\n#else\n        return {\"vulkan\", QObject::tr(\"Vulkan (auto)\").toStdString()};\n#endif\n    }\n    if (!override_value.empty()) {\n        return {\"auto\",\n                QObject::tr(\"%1 (auto)\").arg(QString::fromStdString(std::string(override_value))).toStdString()};\n    }\n#if defined(__APPLE__)\n    return {\"metal\", QObject::tr(\"Metal (auto)\").toStdString()};\n#else\n    return {\"vulkan\", QObject::tr(\"Vulkan (auto)\").toStdString()};\n#endif\n}\n\nstd::string format_backend_label(std::string_view name)\n{\n    if (name.empty()) {\n        return QObject::tr(\"Auto\").toStdString();\n    }\n    const std::string lowered = to_lower_copy(std::string(name));\n    if (lowered == \"vulkan\") {\n        return QObject::tr(\"Vulkan\").toStdString();\n    }\n    if (lowered == \"cuda\") {\n        return QObject::tr(\"CUDA\").toStdString();\n    }\n    if (lowered == \"metal\") {\n        return QObject::tr(\"Metal\").toStdString();\n    }\n    if (lowered == \"cpu\") {\n        return QObject::tr(\"CPU\").toStdString();\n    }\n    return std::string(name);\n}\n\nstd::optional<std::filesystem::path> resolve_default_model_path(const char* env_var)\n{\n    const char* url = std::getenv(env_var);\n    if (!url || !*url) {\n        return std::nullopt;\n    }\n    try {\n        std::filesystem::path path = Utils::make_default_path_to_file_from_download_url(url);\n        if (std::filesystem::exists(path)) {\n            return path;\n        }\n    } catch (...) {\n        return std::nullopt;\n    }\n    return std::nullopt;\n}\n\nstd::vector<DefaultModel> collect_default_models()\n{\n    std::vector<DefaultModel> models;\n    std::unordered_set<std::string> seen;\n    for (const auto& entry : default_llm_entries()) {\n        auto path = resolve_default_model_path(entry.url_env);\n        if (!path) {\n            continue;\n        }\n        const std::string path_key = path->string();\n        if (!seen.insert(path_key).second) {\n            continue;\n        }\n        models.push_back(DefaultModel{default_llm_label(entry).toStdString(), *path, entry.choice});\n    }\n    return models;\n}\n\nvoid load_ggml_backends_once();\n\nstd::optional<std::string> detect_blas_backend_label()\n{\n    load_ggml_backends_once();\n\n    const size_t device_count = ggml_backend_dev_count();\n    for (size_t i = 0; i < device_count; ++i) {\n        auto* device = ggml_backend_dev_get(i);\n        if (!device) {\n            continue;\n        }\n        const auto type = ggml_backend_dev_type(device);\n        if (type != GGML_BACKEND_DEVICE_TYPE_ACCEL &&\n            type != GGML_BACKEND_DEVICE_TYPE_CPU) {\n            continue;\n        }\n\n        const char* dev_name = ggml_backend_dev_name(device);\n        const char* dev_desc = ggml_backend_dev_description(device);\n        auto* reg = ggml_backend_dev_backend_reg(device);\n        const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr;\n\n        auto matches = [&](std::string_view needle) {\n            return case_insensitive_contains(dev_name ? dev_name : \"\", needle) ||\n                   case_insensitive_contains(dev_desc ? dev_desc : \"\", needle) ||\n                   case_insensitive_contains(reg_name ? reg_name : \"\", needle);\n        };\n\n        if (matches(\"openblas\")) {\n            return std::string(\"OpenBLAS\");\n        }\n        if (matches(\"accelerate\")) {\n            return std::string(\"Accelerate\");\n        }\n        if (matches(\"mkl\")) {\n            return std::string(\"MKL\");\n        }\n        if (matches(\"blis\")) {\n            return std::string(\"BLIS\");\n        }\n        if (matches(\"blas\")) {\n            return std::string(\"BLAS\");\n        }\n    }\n\n    return std::nullopt;\n}\n\nstruct BackendMemorySnapshot {\n    size_t free_bytes{0};\n    size_t total_bytes{0};\n    std::string name;\n};\n\nvoid load_ggml_backends_once()\n{\n    static bool loaded = false;\n    if (loaded) {\n        return;\n    }\n\n    const char* ggml_dir = std::getenv(\"AI_FILE_SORTER_GGML_DIR\");\n    if (ggml_dir && *ggml_dir) {\n        ggml_backend_load_all_from_path(ggml_dir);\n    } else {\n        ggml_backend_load_all();\n    }\n    loaded = true;\n}\n\nstd::optional<BackendMemorySnapshot> query_backend_memory(std::string_view backend_name)\n{\n    load_ggml_backends_once();\n\n    const size_t device_count = ggml_backend_dev_count();\n    BackendMemorySnapshot best{};\n    bool found = false;\n\n    for (size_t i = 0; i < device_count; ++i) {\n        auto* device = ggml_backend_dev_get(i);\n        if (!device) {\n            continue;\n        }\n        if (ggml_backend_dev_type(device) != GGML_BACKEND_DEVICE_TYPE_GPU) {\n            continue;\n        }\n        auto* reg = ggml_backend_dev_backend_reg(device);\n        const char* reg_name = reg ? ggml_backend_reg_name(reg) : nullptr;\n        if (!case_insensitive_contains(reg_name ? reg_name : \"\", backend_name)) {\n            continue;\n        }\n\n        size_t free_bytes = 0;\n        size_t total_bytes = 0;\n        ggml_backend_dev_memory(device, &free_bytes, &total_bytes);\n        if (free_bytes == 0 && total_bytes == 0) {\n            continue;\n        }\n\n        if (!found || total_bytes > best.total_bytes) {\n            best.free_bytes = free_bytes;\n            best.total_bytes = (total_bytes != 0) ? total_bytes : free_bytes;\n            const char* dev_name = ggml_backend_dev_name(device);\n            best.name = dev_name ? dev_name : \"\";\n            found = true;\n        }\n    }\n\n    if (found) {\n        return best;\n    }\n    return std::nullopt;\n}\n\nbool is_backend_available(std::string_view backend_name)\n{\n    load_ggml_backends_once();\n    const std::string name(backend_name);\n    ggml_backend_reg_t reg = ggml_backend_reg_by_name(name.c_str());\n    if (!reg) {\n        return false;\n    }\n    return ggml_backend_reg_dev_count(reg) > 0;\n}\n\nQString build_cpu_backend_note(const QString& reason,\n                               const std::optional<std::string>& blas_label)\n{\n    QString details = reason;\n    if (blas_label.has_value()) {\n        if (!details.isEmpty()) {\n            details += QStringLiteral(\"; \");\n        }\n        details += QString::fromStdString(*blas_label);\n    }\n    if (details.isEmpty()) {\n        return QObject::tr(\"CPU\");\n    }\n    return QObject::tr(\"CPU (%1)\").arg(details);\n}\n\nQString build_gpu_backend_note(const BackendTarget& target)\n{\n    return QObject::tr(\"GPU (target: %1)\").arg(QString::fromStdString(target.label));\n}\n\nQString build_backend_note(const BackendTarget& target,\n                           const BenchmarkBackendInfo& info,\n                           bool gpu_fallback)\n{\n    if (target.key == \"cpu\") {\n        return build_cpu_backend_note(QString(), info.blas_label);\n    }\n\n    if (gpu_fallback) {\n        QString reason;\n        if (target.key == \"vulkan\" && !info.vulkan_available) {\n            reason = QObject::tr(\"GPU via Vulkan unavailable\");\n        } else if (target.key == \"cuda\" && !info.cuda_available) {\n            reason = QObject::tr(\"GPU via CUDA unavailable\");\n            if (!info.vulkan_available) {\n                reason += QStringLiteral(\"; \") + QObject::tr(\"Vulkan unavailable\");\n            }\n        } else if (target.key == \"metal\" && !info.metal_available) {\n            reason = QObject::tr(\"GPU via Metal unavailable\");\n        } else {\n            reason = QObject::tr(\"GPU init failed\");\n        }\n        return build_cpu_backend_note(reason, info.blas_label);\n    }\n\n    return build_gpu_backend_note(target);\n}\n\nstd::string join_duration_list(const std::vector<double>& seconds)\n{\n    std::ostringstream oss;\n    for (size_t i = 0; i < seconds.size(); ++i) {\n        if (i > 0) {\n            oss << \", \";\n        }\n        oss << format_seconds(seconds[i]);\n    }\n    return oss.str();\n}\n\ndouble median_seconds(std::vector<double> seconds)\n{\n    if (seconds.empty()) {\n        return 0.0;\n    }\n    std::sort(seconds.begin(), seconds.end());\n    const size_t mid = seconds.size() / 2;\n    if (seconds.size() % 2 == 1) {\n        return seconds[mid];\n    }\n    return (seconds[mid - 1] + seconds[mid]) / 2.0;\n}\n\nbool has_visual_llm_files()\n{\n    return resolve_visual_llm_paths(nullptr).has_value();\n}\n\nbool has_any_llm_available()\n{\n    return !collect_default_models().empty() || has_visual_llm_files();\n}\n\nstd::filesystem::path create_temp_dir()\n{\n    auto ensure_writable_dir = [](const std::filesystem::path& dir) {\n        std::error_code ec;\n        std::filesystem::create_directories(dir, ec);\n        if (ec || !std::filesystem::exists(dir)) {\n            return false;\n        }\n\n        const std::filesystem::path probe = dir / \".aifs-write-probe\";\n        std::ofstream out(probe, std::ios::out | std::ios::trunc);\n        if (!out) {\n            return false;\n        }\n        out << \"ok\";\n        out.close();\n        std::filesystem::remove(probe, ec);\n        return true;\n    };\n\n    std::vector<std::filesystem::path> roots;\n    std::error_code ec;\n    std::filesystem::path temp_root = std::filesystem::temp_directory_path(ec);\n    if (!ec && !temp_root.empty()) {\n        roots.push_back(temp_root);\n    }\n    if (const char* tmpdir = std::getenv(\"TMPDIR\"); tmpdir && *tmpdir) {\n        roots.emplace_back(tmpdir);\n    }\n    if (const char* home = std::getenv(\"HOME\"); home && *home) {\n        roots.emplace_back(std::filesystem::path(home) / \".cache\");\n    }\n    ec.clear();\n    std::filesystem::path cwd = std::filesystem::current_path(ec);\n    if (!ec && !cwd.empty()) {\n        roots.push_back(cwd);\n    }\n\n    const auto stamp = std::chrono::duration_cast<std::chrono::milliseconds>(\n        std::chrono::system_clock::now().time_since_epoch()).count();\n\n    for (const auto& root : roots) {\n        std::filesystem::path base = root / \"aifs-benchmark\";\n        if (!ensure_writable_dir(base)) {\n            continue;\n        }\n\n        for (int attempt = 0; attempt < 16; ++attempt) {\n            std::filesystem::path run_dir = base / (\"run-\" + std::to_string(stamp) +\n                                                    \"-\" + std::to_string(attempt));\n            if (ensure_writable_dir(run_dir)) {\n                return run_dir;\n            }\n        }\n    }\n\n    return std::filesystem::path();\n}\n\nbool write_sample_document(const std::filesystem::path& path)\n{\n    std::error_code ec;\n    std::filesystem::create_directories(path.parent_path(), ec);\n    if (ec) {\n        return false;\n    }\n\n    std::ofstream out(path);\n    if (!out) {\n        return false;\n    }\n    out << \"Project Phoenix Q1 Summary\\n\";\n    out << \"This report covers milestones, risks, and budget updates for Q1 2025.\\n\";\n    out << \"Key topics include cloud migration, incident response, and hiring plans.\\n\";\n    out << \"Overall progress is steady with a focus on cost optimization and delivery timelines.\\n\";\n    return static_cast<bool>(out);\n}\n\nbool write_sample_image(const std::filesystem::path& path)\n{\n    std::error_code ec;\n    std::filesystem::create_directories(path.parent_path(), ec);\n    if (ec) {\n        return false;\n    }\n\n    QImage image(96, 96, QImage::Format_RGB32);\n    image.fill(QColor(30, 120, 200));\n    QPainter painter(&image);\n    painter.fillRect(QRect(18, 18, 60, 60), QColor(240, 200, 60));\n    painter.end();\n    return image.save(QString::fromStdString(path.string()), \"PNG\");\n}\n\nstd::optional<std::filesystem::path> resolve_mmproj_path(const std::filesystem::path& primary)\n{\n    if (std::filesystem::exists(primary)) {\n        return primary;\n    }\n\n    const auto llm_dir = std::filesystem::path(Utils::get_default_llm_destination());\n    static const char* kAltMmprojNames[] = {\n        \"mmproj-model-f16.gguf\",\n        \"llava-v1.6-mistral-7b-mmproj-f16.gguf\"\n    };\n    for (const char* alt_name : kAltMmprojNames) {\n        const auto candidate = llm_dir / alt_name;\n        if (std::filesystem::exists(candidate)) {\n            return candidate;\n        }\n    }\n\n    return std::nullopt;\n}\n\nstd::optional<VisualLlmPaths> resolve_visual_llm_paths(std::string* error)\n{\n    const char* model_url = std::getenv(\"LLAVA_MODEL_URL\");\n    const char* mmproj_url = std::getenv(\"LLAVA_MMPROJ_URL\");\n    if (!model_url || !*model_url || !mmproj_url || !*mmproj_url) {\n        if (error) {\n            *error = \"Missing visual LLM download URLs.\";\n        }\n        return std::nullopt;\n    }\n\n    std::filesystem::path model_path;\n    std::filesystem::path mmproj_primary;\n    try {\n        model_path = std::filesystem::path(Utils::make_default_path_to_file_from_download_url(model_url));\n        mmproj_primary = std::filesystem::path(Utils::make_default_path_to_file_from_download_url(mmproj_url));\n    } catch (...) {\n        if (error) {\n            *error = \"Failed to resolve visual LLM file paths.\";\n        }\n        return std::nullopt;\n    }\n\n    if (!std::filesystem::exists(model_path)) {\n        if (error) {\n            *error = \"Visual LLM model file is missing.\";\n        }\n        return std::nullopt;\n    }\n\n    auto mmproj_path = resolve_mmproj_path(mmproj_primary);\n    if (!mmproj_path) {\n        if (error) {\n            *error = \"Visual LLM mmproj file is missing.\";\n        }\n        return std::nullopt;\n    }\n\n    return VisualLlmPaths{model_path, *mmproj_path};\n}\n\nbool should_use_visual_gpu()\n{\n    const char* backend = std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\");\n    if (!backend || !*backend) {\n        return true;\n    }\n    std::string lowered = backend;\n    std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return lowered != \"cpu\";\n}\n\nstd::optional<std::pair<std::string, std::string>> parse_category_pair(const std::string& response)\n{\n    std::istringstream stream(response);\n    std::string line;\n    std::string category;\n    std::string subcategory;\n\n    while (std::getline(stream, line)) {\n        std::string trimmed = trim_copy(line);\n        if (trimmed.empty()) {\n            continue;\n        }\n\n        if (trimmed.rfind(\"Category\", 0) == 0) {\n            const auto pos = trimmed.find(':');\n            if (pos != std::string::npos) {\n                category = trim_copy(trimmed.substr(pos + 1));\n            }\n            continue;\n        }\n\n        if (trimmed.rfind(\"Subcategory\", 0) == 0) {\n            const auto pos = trimmed.find(':');\n            if (pos != std::string::npos) {\n                subcategory = trim_copy(trimmed.substr(pos + 1));\n            }\n            continue;\n        }\n\n        if (!trimmed.empty() && (trimmed.front() == '-' || trimmed.front() == '*')) {\n            trimmed = trim_copy(trimmed.substr(1));\n        }\n\n        size_t pos = trimmed.find(\" : \");\n        size_t delim_len = 0;\n        if (pos != std::string::npos) {\n            delim_len = 3;\n        } else {\n            pos = trimmed.find(':');\n            delim_len = (pos != std::string::npos) ? 1 : 0;\n        }\n\n        if (pos != std::string::npos && delim_len > 0) {\n            const std::string raw_category = trim_copy(trimmed.substr(0, pos));\n            const std::string raw_subcategory = trim_copy(trimmed.substr(pos + delim_len));\n            if (!raw_category.empty() && !raw_subcategory.empty()) {\n                category = Utils::sanitize_path_label(raw_category);\n                subcategory = Utils::sanitize_path_label(raw_subcategory);\n                break;\n            }\n        }\n    }\n\n    if (!category.empty() && !subcategory.empty()) {\n        return std::make_pair(category, subcategory);\n    }\n    return std::nullopt;\n}\n\nstruct StepResult {\n    bool success{false};\n    bool skipped{false};\n    std::string detail;\n    std::chrono::steady_clock::duration duration{};\n};\n\nstruct TextModelOutcome {\n    bool skipped{true};\n    bool categorization_ok{false};\n    bool document_ok{false};\n    std::optional<PerfClass> categorization_perf;\n    std::optional<PerfClass> document_perf;\n    struct ModelPerf {\n        std::string label;\n        LLMChoice choice{LLMChoice::Unset};\n        PerfClass cat_perf{PerfClass::TooLong};\n        PerfClass doc_perf{PerfClass::TooLong};\n        double cat_median{0.0};\n        double doc_median{0.0};\n    };\n    std::vector<ModelPerf> model_results;\n};\n\nStepResult run_categorization_test(ILLMClient& llm, const std::filesystem::path& temp_dir)\n{\n    StepResult result;\n    const auto start = std::chrono::steady_clock::now();\n    try {\n        const std::string file_name = \"Quarterly_Report_Q1_2025.pdf\";\n        const std::filesystem::path file_path = temp_dir / file_name;\n        const std::string response = llm.categorize_file(file_name,\n                                                         file_path.string(),\n                                                         FileType::File,\n                                                         std::string());\n        const auto parsed = parse_category_pair(response);\n        result.success = parsed.has_value();\n        if (!result.success) {\n            result.detail = \"Unexpected response format.\";\n        }\n    } catch (const std::exception& ex) {\n        result.detail = ex.what();\n    }\n    result.duration = std::chrono::steady_clock::now() - start;\n    return result;\n}\n\nStepResult run_document_test(ILLMClient& llm, const std::filesystem::path& temp_dir)\n{\n    StepResult result;\n    if (temp_dir.empty()) {\n        result.detail = \"No writable temporary directory available.\";\n        return result;\n    }\n\n    const std::filesystem::path doc_path = temp_dir / \"benchmark_document.txt\";\n    if (!write_sample_document(doc_path)) {\n        result.detail = \"Failed to create sample document.\";\n        return result;\n    }\n\n    const auto start = std::chrono::steady_clock::now();\n    try {\n        DocumentTextAnalyzer analyzer;\n        const auto analysis = analyzer.analyze(doc_path, llm);\n        result.success = !analysis.suggested_name.empty();\n        if (!result.success) {\n            result.detail = \"Empty suggestion.\";\n        }\n    } catch (const std::exception& ex) {\n        result.detail = ex.what();\n    }\n    result.duration = std::chrono::steady_clock::now() - start;\n    return result;\n}\n\nStepResult run_image_test(const std::filesystem::path& temp_dir)\n{\n    StepResult result;\n#if defined(AI_FILE_SORTER_HAS_MTMD)\n    if (temp_dir.empty()) {\n        result.detail = \"No writable temporary directory available.\";\n        return result;\n    }\n\n    std::string visual_error;\n    auto visual_paths = resolve_visual_llm_paths(&visual_error);\n    if (!visual_paths) {\n        result.skipped = true;\n        result.detail = visual_error.empty() ? \"Visual LLM files unavailable.\" : visual_error;\n        return result;\n    }\n\n    const std::filesystem::path image_path = temp_dir / \"benchmark_image.png\";\n    if (!write_sample_image(image_path)) {\n        result.detail = \"Failed to create sample image.\";\n        return result;\n    }\n\n    const auto start = std::chrono::steady_clock::now();\n    try {\n        LlavaImageAnalyzer::Settings settings;\n        settings.use_gpu = should_use_visual_gpu();\n        LlavaImageAnalyzer analyzer(visual_paths->model_path, visual_paths->mmproj_path, settings);\n        const auto analysis = analyzer.analyze(image_path);\n        result.success = !analysis.suggested_name.empty();\n        if (!result.success) {\n            result.detail = \"Empty suggestion.\";\n        }\n    } catch (const std::exception& ex) {\n        result.detail = ex.what();\n    }\n    result.duration = std::chrono::steady_clock::now() - start;\n#else\n    result.skipped = true;\n    result.detail = \"Visual LLM support is not available in this build.\";\n#endif\n    return result;\n}\n\nTextModelOutcome run_text_model_checks(const std::vector<DefaultModel>& models,\n                                       const std::filesystem::path& temp_dir,\n                                       const EnvSnapshot& baseline_env,\n                                       const BenchmarkBackendInfo& backend_info,\n                                       const std::function<void(const QString&)>& post_line,\n                                       const std::function<void(const QString&)>& post_line_html,\n                                       const std::function<bool()>& should_stop)\n{\n    TextModelOutcome outcome;\n    constexpr int kPerItemRuns = 3;\n    if (models.empty()) {\n        return outcome;\n    }\n\n    outcome.skipped = false;\n    outcome.categorization_ok = true;\n    outcome.document_ok = true;\n\n    bool first_model = true;\n    for (const auto& model : models) {\n        if (should_stop && should_stop()) {\n            break;\n        }\n        baseline_env.restore();\n        ScopedEnvRestore env_restore(baseline_env);\n        if (post_line) {\n            if (!first_model) {\n                post_line(QStringLiteral(\"----\"));\n            }\n            if (post_line_html) {\n                post_line_html(QObject::tr(\"Default model: %1\").arg(bold_llm_label(model.label)));\n            } else {\n                post_line(QObject::tr(\"Default model: %1\").arg(QString::fromStdString(model.label)));\n            }\n        }\n        try {\n            LocalLLMClient client(model.path.string());\n\n            StepResult cat_warm;\n            StepResult cat_init;\n            std::vector<StepResult> cat_runs;\n            StepResult doc_warm;\n            StepResult doc_init;\n            std::vector<StepResult> doc_runs;\n            bool status_fallback = false;\n            client.set_status_callback([&status_fallback](LocalLLMClient::Status status) {\n                if (status == LocalLLMClient::Status::GpuFallbackToCpu) {\n                    status_fallback = true;\n                }\n            });\n\n            const std::string backend_before_cat = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n            const BackendTarget cat_target = resolve_backend_target(backend_before_cat);\n            if (post_line) {\n                post_line(QObject::tr(\"    Measuring categorization (warm-up + %1 run(s))...\")\n                              .arg(kPerItemRuns + 1));\n            }\n            cat_warm = run_categorization_test(client, temp_dir);\n            if (should_stop && should_stop()) {\n                return outcome;\n            }\n            cat_init = run_categorization_test(client, temp_dir);\n            if (should_stop && should_stop()) {\n                return outcome;\n            }\n            cat_runs.reserve(static_cast<size_t>(kPerItemRuns));\n            for (int i = 0; i < kPerItemRuns; ++i) {\n                cat_runs.push_back(run_categorization_test(client, temp_dir));\n                if (should_stop && should_stop()) {\n                    return outcome;\n                }\n            }\n            const std::string backend_after_cat = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n            const bool env_fallback_cat = (cat_target.key != \"cpu\" && backend_after_cat == \"cpu\");\n            const bool cat_fallback = status_fallback || env_fallback_cat;\n            bool cat_success = cat_warm.success && cat_init.success;\n            for (const auto& run : cat_runs) {\n                cat_success = cat_success && run.success;\n            }\n\n            status_fallback = false;\n            const std::string backend_before_doc = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n            const BackendTarget doc_target = resolve_backend_target(backend_before_doc);\n            if (post_line) {\n                post_line(QObject::tr(\"    Measuring document analysis (warm-up + %1 run(s))...\")\n                              .arg(kPerItemRuns + 1));\n            }\n            doc_warm = run_document_test(client, temp_dir);\n            if (should_stop && should_stop()) {\n                return outcome;\n            }\n            doc_init = run_document_test(client, temp_dir);\n            if (should_stop && should_stop()) {\n                return outcome;\n            }\n            doc_runs.reserve(static_cast<size_t>(kPerItemRuns));\n            for (int i = 0; i < kPerItemRuns; ++i) {\n                doc_runs.push_back(run_document_test(client, temp_dir));\n                if (should_stop && should_stop()) {\n                    return outcome;\n                }\n            }\n            const std::string backend_after_doc = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n            const bool env_fallback_doc = (doc_target.key != \"cpu\" && backend_after_doc == \"cpu\");\n            const bool doc_fallback = status_fallback || env_fallback_doc;\n            bool doc_success = doc_warm.success && doc_init.success;\n            for (const auto& run : doc_runs) {\n                doc_success = doc_success && run.success;\n            }\n\n            outcome.categorization_ok = outcome.categorization_ok && cat_success;\n            outcome.document_ok = outcome.document_ok && doc_success;\n\n            std::vector<double> cat_per_seconds;\n            cat_per_seconds.reserve(cat_runs.size());\n            for (const auto& run : cat_runs) {\n                cat_per_seconds.push_back(duration_seconds(run.duration));\n            }\n            const double cat_median = median_seconds(cat_per_seconds);\n            const PerfClass cat_perf = classify_perf(cat_median, thresholds_for_choice(model.choice));\n            outcome.categorization_perf = outcome.categorization_perf.has_value()\n                ? std::optional<PerfClass>(worst_perf(*outcome.categorization_perf, cat_perf))\n                : std::optional<PerfClass>(cat_perf);\n\n            std::vector<double> doc_per_seconds;\n            doc_per_seconds.reserve(doc_runs.size());\n            for (const auto& run : doc_runs) {\n                doc_per_seconds.push_back(duration_seconds(run.duration));\n            }\n            const double doc_median = median_seconds(doc_per_seconds);\n            const PerfClass doc_perf = classify_perf(doc_median, thresholds_for_document_choice(model.choice));\n            outcome.document_perf = outcome.document_perf.has_value()\n                ? std::optional<PerfClass>(worst_perf(*outcome.document_perf, doc_perf))\n                : std::optional<PerfClass>(doc_perf);\n\n            outcome.model_results.push_back(TextModelOutcome::ModelPerf{\n                model.label,\n                model.choice,\n                cat_perf,\n                doc_perf,\n                cat_median,\n                doc_median\n            });\n\n            if (post_line) {\n                post_line(QObject::tr(\"Categorization: %1\")\n                              .arg(cat_success ? QObject::tr(\"done\") : QObject::tr(\"failed\")));\n                if (post_line_html) {\n                    post_line_html(QObject::tr(\"    Warm-up: %1\")\n                                      .arg(colored_seconds(duration_seconds(cat_warm.duration), PerfClass::Optimal)));\n                    post_line_html(QObject::tr(\"    Init: %1\")\n                                      .arg(colored_seconds(duration_seconds(cat_init.duration), PerfClass::Optimal)));\n                    post_line_html(QObject::tr(\"    Per-item (median of %1): %2\")\n                                      .arg(cat_per_seconds.size())\n                                      .arg(colored_seconds(cat_median, cat_perf)));\n                    post_line_html(QObject::tr(\"    Per-item runs: %1\")\n                                      .arg(colored_seconds_list(\n                                          cat_per_seconds,\n                                          [model](double value) {\n                                              return classify_perf(value, thresholds_for_choice(model.choice));\n                                          })));\n                } else {\n                    post_line(QObject::tr(\"    Warm-up: %1\")\n                                  .arg(QString::fromStdString(format_duration(cat_warm.duration))));\n                    post_line(QObject::tr(\"    Init: %1\")\n                                  .arg(QString::fromStdString(format_duration(cat_init.duration))));\n                    post_line(QObject::tr(\"    Per-item (median of %1): %2\")\n                                  .arg(cat_per_seconds.size())\n                                  .arg(QString::fromStdString(format_seconds(cat_median))));\n                    post_line(QObject::tr(\"    Per-item runs: %1\")\n                                  .arg(QString::fromStdString(join_duration_list(cat_per_seconds))));\n                }\n                if (!cat_success) {\n                    std::string detail = cat_warm.detail;\n                    if (detail.empty()) {\n                        detail = cat_init.detail;\n                    }\n                    if (detail.empty()) {\n                        for (const auto& run : cat_runs) {\n                            if (!run.detail.empty()) {\n                                detail = run.detail;\n                                break;\n                            }\n                        }\n                    }\n                    if (!detail.empty()) {\n                        post_line(QObject::tr(\"Details: %1\").arg(QString::fromStdString(detail)));\n                    }\n                }\n                post_line(QObject::tr(\"Backend used: %1\")\n                              .arg(build_backend_note(cat_target, backend_info, cat_fallback)));\n                post_line(QObject::tr(\"Document analysis: %1\")\n                              .arg(doc_success ? QObject::tr(\"done\") : QObject::tr(\"failed\")));\n                if (post_line_html) {\n                    post_line_html(QObject::tr(\"    Warm-up: %1\")\n                                      .arg(colored_seconds(duration_seconds(doc_warm.duration), PerfClass::Optimal)));\n                    post_line_html(QObject::tr(\"    Init: %1\")\n                                      .arg(colored_seconds(duration_seconds(doc_init.duration), PerfClass::Optimal)));\n                    post_line_html(QObject::tr(\"    Per-item (median of %1): %2\")\n                                      .arg(doc_per_seconds.size())\n                                      .arg(colored_seconds(doc_median, doc_perf)));\n                    post_line_html(QObject::tr(\"    Per-item runs: %1\")\n                                      .arg(colored_seconds_list(\n                                          doc_per_seconds,\n                                          [model](double value) {\n                                              return classify_perf(value, thresholds_for_document_choice(model.choice));\n                                          })));\n                } else {\n                    post_line(QObject::tr(\"    Warm-up: %1\")\n                                  .arg(QString::fromStdString(format_duration(doc_warm.duration))));\n                    post_line(QObject::tr(\"    Init: %1\")\n                                  .arg(QString::fromStdString(format_duration(doc_init.duration))));\n                    post_line(QObject::tr(\"    Per-item (median of %1): %2\")\n                                  .arg(doc_per_seconds.size())\n                                  .arg(QString::fromStdString(format_seconds(doc_median))));\n                    post_line(QObject::tr(\"    Per-item runs: %1\")\n                                  .arg(QString::fromStdString(join_duration_list(doc_per_seconds))));\n                }\n                if (!doc_success) {\n                    std::string detail = doc_warm.detail;\n                    if (detail.empty()) {\n                        detail = doc_init.detail;\n                    }\n                    if (detail.empty()) {\n                        for (const auto& run : doc_runs) {\n                            if (!run.detail.empty()) {\n                                detail = run.detail;\n                                break;\n                            }\n                        }\n                    }\n                    if (!detail.empty()) {\n                        post_line(QObject::tr(\"Details: %1\").arg(QString::fromStdString(detail)));\n                    }\n                }\n                post_line(QObject::tr(\"Backend used: %1\")\n                              .arg(build_backend_note(doc_target, backend_info, doc_fallback)));\n            }\n        } catch (const std::exception& ex) {\n            outcome.categorization_ok = false;\n            outcome.document_ok = false;\n            if (post_line) {\n                post_line(QObject::tr(\"Model failed to load: %1\")\n                              .arg(QString::fromStdString(ex.what())));\n            }\n        }\n        first_model = false;\n    }\n\n    return outcome;\n}\n\nQString perf_label_qt(PerfClass perf)\n{\n    switch (perf) {\n    case PerfClass::Optimal:\n        return QObject::tr(\"optimal\");\n    case PerfClass::Acceptable:\n        return QObject::tr(\"acceptable\");\n    case PerfClass::TooLong:\n        return QObject::tr(\"a bit long\");\n    }\n    return QObject::tr(\"a bit long\");\n}\n\nQString colored_perf_label(PerfClass perf)\n{\n    return QStringLiteral(\"<span style=\\\"color:%1; font-weight:600;\\\">%2</span>\")\n        .arg(perf_color(perf))\n        .arg(perf_label_qt(perf));\n}\n\nQString build_recommended_list(const QStringList& labels)\n{\n    QStringList items;\n    items.reserve(labels.size());\n    for (const auto& label : labels) {\n        const QString trimmed = label.trimmed();\n        if (!trimmed.isEmpty()) {\n            items << trimmed;\n        }\n    }\n    if (items.empty()) {\n        items << QObject::tr(\"n/a\");\n    }\n    QString html;\n    for (int i = 0; i < items.size(); ++i) {\n        if (i > 0) {\n            html += QStringLiteral(\"<br>\");\n        }\n        html += QStringLiteral(\"- %1\").arg(items[i].toHtmlEscaped());\n    }\n    return html;\n}\n\nQStringList build_result_lines(const TextModelOutcome& text_models,\n                               const StepResult& image)\n{\n    QStringList lines;\n    lines << QStringLiteral(\"<span style=\\\"color:#1f6feb; font-weight:700;\\\">%1</span>\")\n                 .arg(QObject::tr(\"Result\"));\n\n    if (text_models.skipped) {\n        lines << QObject::tr(\"Categorization speed: unavailable\");\n        lines << QObject::tr(\"Document analysis speed: unavailable\");\n    } else {\n        PerfClass cat_perf = PerfClass::TooLong;\n        PerfClass doc_perf = PerfClass::TooLong;\n        for (const auto& entry : text_models.model_results) {\n            if (perf_rank(entry.cat_perf) < perf_rank(cat_perf)) {\n                cat_perf = entry.cat_perf;\n            }\n            if (perf_rank(entry.doc_perf) < perf_rank(doc_perf)) {\n                doc_perf = entry.doc_perf;\n            }\n        }\n        lines << QObject::tr(\"Categorization speed: %1\").arg(colored_perf_label(cat_perf));\n        lines << QObject::tr(\"Document analysis speed: %1\").arg(colored_perf_label(doc_perf));\n    }\n\n    if (image.skipped) {\n        lines << QObject::tr(\"Image analysis speed: unavailable\");\n    } else if (image.success) {\n        const double seconds = duration_seconds(image.duration);\n        const PerfClass image_perf = classify_perf(seconds, image_thresholds());\n        lines << QObject::tr(\"Image analysis speed: %1\").arg(colored_perf_label(image_perf));\n    } else {\n        lines << QObject::tr(\"Image analysis speed: %1\").arg(colored_perf_label(PerfClass::TooLong));\n    }\n\n    QStringList recommended_labels;\n    if (!text_models.model_results.empty()) {\n        std::vector<const TextModelOutcome::ModelPerf*> optimal;\n        std::vector<const TextModelOutcome::ModelPerf*> acceptable;\n        std::vector<const TextModelOutcome::ModelPerf*> quite_long;\n        for (const auto& entry : text_models.model_results) {\n            if (entry.cat_perf == PerfClass::Optimal && entry.doc_perf == PerfClass::Optimal) {\n                optimal.push_back(&entry);\n            } else if (entry.cat_perf != PerfClass::TooLong && entry.doc_perf != PerfClass::TooLong) {\n                acceptable.push_back(&entry);\n            } else {\n                quite_long.push_back(&entry);\n            }\n        }\n\n        if (optimal.size() == 1) {\n            recommended_labels << QString::fromStdString(optimal.front()->label);\n        } else if (optimal.size() > 1) {\n            for (const auto* entry : optimal) {\n                recommended_labels << QString::fromStdString(entry->label);\n            }\n        } else if (acceptable.size() == 1) {\n            recommended_labels << QString::fromStdString(acceptable.front()->label);\n        } else if (acceptable.size() > 1) {\n            for (const auto* entry : acceptable) {\n                recommended_labels << QString::fromStdString(entry->label);\n            }\n        } else if (!quite_long.empty()) {\n            double best_score = std::numeric_limits<double>::max();\n            for (const auto* entry : quite_long) {\n                const double score = entry->cat_median + entry->doc_median;\n                best_score = std::min(best_score, score);\n            }\n            for (const auto* entry : quite_long) {\n                const double score = entry->cat_median + entry->doc_median;\n                if (std::abs(score - best_score) < 0.0001) {\n                    recommended_labels << QString::fromStdString(entry->label);\n                }\n            }\n        }\n    }\n\n    lines << QString();\n    const QString recommended_header = QObject::tr(\"Recommended Local LLM choice: %1\").arg(QString());\n    lines << QStringLiteral(\"<span style=\\\"color:#1b9e3c; font-weight:700;\\\">%1</span>\")\n                 .arg(recommended_header.toHtmlEscaped());\n    lines << build_recommended_list(recommended_labels);\n    lines << QString();\n    lines << QStringLiteral(\"<span style=\\\"color:#1f6feb;\\\">%1</span>\")\n                 .arg(QObject::tr(\"You can toggle LLMs in Settings -> Select LLM\").toHtmlEscaped());\n    return lines;\n}\n} // namespace\n\nSuitabilityBenchmarkDialog::SuitabilityBenchmarkDialog(Settings& settings,\n                                                       QWidget* parent)\n    : QDialog(parent)\n    , settings_(settings)\n{\n    resize(820, 560);\n    setup_ui();\n    retranslate_ui();\n    load_previous_results();\n}\n\nSuitabilityBenchmarkDialog::~SuitabilityBenchmarkDialog()\n{\n    if (worker_.joinable()) {\n        worker_.join();\n    }\n}\n\nvoid SuitabilityBenchmarkDialog::setup_ui()\n{\n    auto* layout = new QVBoxLayout(this);\n\n    intro_label_ = new QLabel(this);\n    intro_label_->setTextFormat(Qt::RichText);\n    intro_label_->setWordWrap(true);\n    layout->addWidget(intro_label_);\n\n    output_view_ = new QTextEdit(this);\n    output_view_->setReadOnly(true);\n    output_view_->setAcceptRichText(true);\n    output_view_->setLineWrapMode(QTextEdit::WidgetWidth);\n    layout->addWidget(output_view_, 1);\n\n    progress_bar_ = new QProgressBar(this);\n    progress_bar_->setVisible(false);\n    progress_bar_->setRange(0, 0);\n    layout->addWidget(progress_bar_);\n\n    auto* button_layout = new QHBoxLayout();\n    suppress_checkbox_ = new QCheckBox(this);\n    suppress_checkbox_->setChecked(settings_.get_suitability_benchmark_suppressed());\n    button_layout->addWidget(suppress_checkbox_);\n    button_layout->addStretch(1);\n\n    stop_button_ = new QPushButton(this);\n    stop_button_->setEnabled(false);\n    button_layout->addWidget(stop_button_);\n\n    run_button_ = new QPushButton(this);\n    button_layout->addWidget(run_button_);\n\n    close_button_ = new QPushButton(this);\n    button_layout->addWidget(close_button_);\n\n    layout->addLayout(button_layout);\n\n    connect(run_button_, &QPushButton::clicked, this, &SuitabilityBenchmarkDialog::start_benchmark);\n    connect(stop_button_, &QPushButton::clicked, this, &SuitabilityBenchmarkDialog::request_stop);\n    connect(close_button_, &QPushButton::clicked, this, &QDialog::accept);\n    connect(suppress_checkbox_, &QCheckBox::toggled, this, [this](bool checked) {\n        settings_.set_suitability_benchmark_suppressed(checked);\n        settings_.save();\n    });\n}\n\nvoid SuitabilityBenchmarkDialog::retranslate_ui()\n{\n    setWindowTitle(QObject::tr(\"Compatibility Benchmark\"));\n    if (intro_label_) {\n        const QString intro_main = QObject::tr(\"Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.\");\n        const QString intro_warning = QObject::tr(\"It is recommended to quit any CPU- and GPU-intensive applications before running this test.\");\n        intro_label_->setText(QStringLiteral(\"%1<br><br><span style=\\\"color:#d73a49; font-weight:600;\\\">%2</span>\")\n                                  .arg(intro_main.toHtmlEscaped(), intro_warning.toHtmlEscaped()));\n    }\n    if (run_button_) {\n        run_button_->setText(QObject::tr(\"Run benchmark\"));\n    }\n    if (suppress_checkbox_) {\n        suppress_checkbox_->setText(QObject::tr(\"Do not auto-show this dialog again\"));\n    }\n    if (stop_button_) {\n        stop_button_->setText(QObject::tr(\"Stop Benchmark\"));\n    }\n    if (close_button_) {\n        close_button_->setText(QObject::tr(\"Close\"));\n    }\n    if (showing_previous_results_) {\n        render_previous_results();\n    }\n}\n\nvoid SuitabilityBenchmarkDialog::changeEvent(QEvent* event)\n{\n    QDialog::changeEvent(event);\n    if (event && event->type() == QEvent::LanguageChange) {\n        retranslate_ui();\n    }\n}\n\nvoid SuitabilityBenchmarkDialog::load_previous_results()\n{\n    last_run_stamp_ = QString::fromStdString(settings_.get_benchmark_last_run());\n    last_report_ = QString::fromStdString(settings_.get_benchmark_last_report());\n    render_previous_results();\n}\n\nvoid SuitabilityBenchmarkDialog::render_previous_results()\n{\n    if (!output_view_) {\n        return;\n    }\n\n    const bool was_recording = recording_;\n    recording_ = false;\n    output_view_->clear();\n    showing_previous_results_ = true;\n\n    if (last_report_.isEmpty()) {\n        append_line(QObject::tr(\"No previous results yet.\"), false);\n        recording_ = was_recording;\n        return;\n    }\n\n    if (!last_run_stamp_.isEmpty()) {\n        append_line(QObject::tr(\"Last run: %1\").arg(last_run_stamp_), false);\n    }\n    append_line(QObject::tr(\"Previous results:\"), false);\n\n    const QStringList lines = last_report_.split('\\n');\n    for (const QString& line : lines) {\n        append_line(line, line.contains('<'));\n    }\n\n    if (auto* scroll = output_view_->verticalScrollBar()) {\n        scroll->setValue(scroll->maximum());\n    }\n    recording_ = was_recording;\n}\n\nvoid SuitabilityBenchmarkDialog::closeEvent(QCloseEvent* event)\n{\n    if (running_) {\n        if (event) {\n            event->ignore();\n        }\n        return;\n    }\n    QDialog::closeEvent(event);\n}\n\nvoid SuitabilityBenchmarkDialog::start_benchmark()\n{\n    if (running_) {\n        return;\n    }\n    if (worker_.joinable()) {\n        worker_.join();\n    }\n\n    if (!has_any_llm_available()) {\n        if (output_view_) {\n            output_view_->clear();\n        }\n        append_line(QObject::tr(\"No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.\"), false);\n        return;\n    }\n\n    if (output_view_) {\n        output_view_->clear();\n    }\n    showing_previous_results_ = false;\n    recording_ = true;\n    current_report_.clear();\n    stop_requested_ = false;\n    set_running_state(true);\n\n    worker_ = std::thread(&SuitabilityBenchmarkDialog::run_benchmark_worker, this);\n}\n\nvoid SuitabilityBenchmarkDialog::run_benchmark_worker()\n{\n    QPointer<SuitabilityBenchmarkDialog> self(this);\n    auto post_line = [self](const QString& text) {\n        if (!self) {\n            return;\n        }\n        QMetaObject::invokeMethod(self, [self, text]() {\n            if (self) {\n                self->append_line(text, false);\n            }\n        }, Qt::QueuedConnection);\n    };\n\n    auto post_line_html = [self](const QString& html) {\n        if (!self) {\n            return;\n        }\n        QMetaObject::invokeMethod(self, [self, html]() {\n            if (self) {\n                self->append_line(html, true);\n            }\n        }, Qt::QueuedConnection);\n    };\n\n    auto finish = [self]() {\n        if (!self) {\n            return;\n        }\n        QMetaObject::invokeMethod(self, [self]() {\n            if (self) {\n                self->finish_benchmark();\n            }\n        }, Qt::QueuedConnection);\n    };\n\n    auto should_stop = [self]() -> bool {\n        if (!self) {\n            return true;\n        }\n        return self->stop_requested_.load();\n    };\n\n    try {\n        post_line(QObject::tr(\"Starting system compatibility check...\"));\n\n        static const std::array<const char*, 3> kBenchmarkEnvKeys = {\n            \"AI_FILE_SORTER_GPU_BACKEND\",\n            \"LLAMA_ARG_DEVICE\",\n            \"GGML_DISABLE_CUDA\"\n        };\n        const EnvSnapshot baseline_env = EnvSnapshot::capture(kBenchmarkEnvKeys);\n        ScopedEnvRestore env_restore(baseline_env);\n\n        const unsigned int hw_threads = std::max(1u, std::thread::hardware_concurrency());\n        post_line(QObject::tr(\"CPU threads detected: %1\").arg(hw_threads));\n\n        const char* backend_env = std::getenv(\"AI_FILE_SORTER_GPU_BACKEND\");\n        std::string backend_override = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n        if (backend_env && *backend_env) {\n            post_line(QObject::tr(\"GPU backend override: %1\").arg(QString::fromUtf8(backend_env)));\n        }\n\n        bool cuda_available = false;\n        std::optional<BackendMemorySnapshot> vk_memory;\n        bool metal_available = false;\n        std::optional<BackendMemorySnapshot> metal_memory;\n\n#if defined(__APPLE__)\n        metal_available = is_backend_available(\"Metal\");\n        post_line(QObject::tr(\"Metal available: %1\")\n                      .arg(metal_available ? QObject::tr(\"yes\") : QObject::tr(\"no\")));\n        metal_memory = query_backend_memory(\"metal\");\n        if (metal_memory.has_value()) {\n            post_line(QObject::tr(\"GPU memory allocation (Metal): %1 free / %2 total\")\n                          .arg(QString::fromStdString(format_mib(metal_memory->free_bytes)))\n                          .arg(QString::fromStdString(format_mib(metal_memory->total_bytes))));\n        } else {\n            post_line(QObject::tr(\"GPU memory allocation (Metal): unavailable\"));\n        }\n#else\n        cuda_available = Utils::is_cuda_available();\n        post_line(QObject::tr(\"CUDA available: %1\")\n                      .arg(cuda_available ? QObject::tr(\"yes\") : QObject::tr(\"no\")));\n        if (cuda_available) {\n            auto cuda_info = Utils::query_cuda_memory();\n            if (cuda_info && cuda_info->valid()) {\n                QString line = QObject::tr(\"CUDA memory (allocatable): %1 free / %2 total\")\n                                   .arg(QString::fromStdString(format_mib(cuda_info->free_bytes)))\n                                   .arg(QString::fromStdString(format_mib(cuda_info->total_bytes)));\n                if (cuda_info->device_total_bytes > 0) {\n                    line += QObject::tr(\" (device total: %1)\")\n                                .arg(QString::fromStdString(format_mib(cuda_info->device_total_bytes)));\n                }\n                post_line(line);\n            }\n        }\n\n        vk_memory = query_backend_memory(\"vulkan\");\n        if (vk_memory.has_value()) {\n            post_line(QObject::tr(\"GPU memory allocation (Vulkan): %1 free / %2 total\")\n                          .arg(QString::fromStdString(format_mib(vk_memory->free_bytes)))\n                          .arg(QString::fromStdString(format_mib(vk_memory->total_bytes))));\n        } else {\n            post_line(QObject::tr(\"GPU memory allocation (Vulkan): unavailable\"));\n        }\n#endif\n\n        BenchmarkBackendInfo backend_info;\n        backend_info.cuda_available = cuda_available;\n        backend_info.vulkan_available = vk_memory.has_value();\n        backend_info.vulkan_device = vk_memory ? vk_memory->name : std::string();\n        backend_info.metal_available = metal_available;\n        backend_info.metal_device = metal_memory ? metal_memory->name : std::string();\n        backend_info.blas_label = detect_blas_backend_label();\n\n        const auto temp_dir = create_temp_dir();\n        if (temp_dir.empty()) {\n            post_line(QObject::tr(\"Temporary directory setup failed; benchmark sample file creation may fail.\"));\n        }\n        const std::vector<DefaultModel> default_models = collect_default_models();\n        if (default_models.empty()) {\n            post_line(QObject::tr(\"No default models downloaded; skipping categorization and document checks.\"));\n        } else {\n            post_line(QObject::tr(\"Default models detected: %1\").arg(default_models.size()));\n        }\n        post_line(QStringLiteral(\"----\"));\n\n        const TextModelOutcome text_outcome = run_text_model_checks(default_models,\n                                                                    temp_dir,\n                                                                    baseline_env,\n                                                                    backend_info,\n                                                                    post_line,\n                                                                    post_line_html,\n                                                                    should_stop);\n\n        if (should_stop()) {\n            post_line(QObject::tr(\"Benchmark stopped.\"));\n            finish();\n            return;\n        }\n\n        post_line(QStringLiteral(\"----\"));\n        post_line(QObject::tr(\"Running image analysis test...\"));\n        baseline_env.restore();\n        ScopedEnvRestore image_env_restore(baseline_env);\n        if (should_stop()) {\n            post_line(QObject::tr(\"Benchmark stopped.\"));\n            finish();\n            return;\n        }\n        StepResult image_result = run_image_test(temp_dir);\n\n        if (image_result.skipped) {\n            const QString detail = image_result.detail.empty()\n                ? QObject::tr(\"unavailable\")\n                : QString::fromStdString(image_result.detail);\n            post_line(QObject::tr(\"Image analysis: skipped (%1)\").arg(detail));\n        } else {\n            const double seconds = duration_seconds(image_result.duration);\n            const PerfClass image_perf = classify_perf(seconds, image_thresholds());\n            post_line(QObject::tr(\"Image analysis: %1\")\n                          .arg(image_result.success ? QObject::tr(\"done\") : QObject::tr(\"failed\")));\n            post_line_html(QObject::tr(\"    Time: %1\")\n                              .arg(colored_seconds(seconds, image_perf)));\n            if (!image_result.success && !image_result.detail.empty()) {\n                post_line(QObject::tr(\"Details: %1\").arg(QString::fromStdString(image_result.detail)));\n            }\n        }\n\n        if (should_stop()) {\n            post_line(QObject::tr(\"Benchmark stopped.\"));\n            finish();\n            return;\n        }\n\n        if (!image_result.skipped) {\n            std::string visual_backend = read_env_lower(\"AI_FILE_SORTER_GPU_BACKEND\");\n            if (visual_backend.empty()) {\n                visual_backend = read_env_lower(\"LLAMA_ARG_DEVICE\");\n            }\n\n            QString backend_note;\n            if (!should_use_visual_gpu()) {\n                backend_note = build_cpu_backend_note(QObject::tr(\"GPU disabled by backend override\"), std::nullopt);\n            } else if (case_insensitive_contains(visual_backend, \"vulkan\") &&\n                       !backend_info.vulkan_available) {\n                backend_note = build_cpu_backend_note(QObject::tr(\"GPU via Vulkan unavailable\"), std::nullopt);\n            } else if (case_insensitive_contains(visual_backend, \"metal\") &&\n                       !backend_info.metal_available) {\n                backend_note = build_cpu_backend_note(QObject::tr(\"GPU via Metal unavailable\"), std::nullopt);\n            } else {\n                BackendTarget visual_target = resolve_backend_target(visual_backend);\n                if (visual_target.key == \"cpu\") {\n                    backend_note = build_cpu_backend_note(QObject::tr(\"GPU disabled by backend override\"), std::nullopt);\n                } else {\n                    if (!visual_backend.empty()) {\n                        visual_target.label = format_backend_label(visual_backend);\n                    }\n                    backend_note = build_gpu_backend_note(visual_target);\n                }\n            }\n\n            post_line(QObject::tr(\"Backend used (image analysis): %1\")\n                          .arg(backend_note));\n        }\n\n        post_line(QStringLiteral(\"----\"));\n        const QStringList result_lines = build_result_lines(text_outcome, image_result);\n        for (const QString& line : result_lines) {\n            if (line.contains('<')) {\n                post_line_html(line);\n            } else {\n                post_line(line);\n            }\n        }\n\n        std::error_code cleanup_error;\n        std::filesystem::remove_all(temp_dir, cleanup_error);\n    } catch (const std::exception& ex) {\n        post_line(QObject::tr(\"Benchmark failed: %1\").arg(QString::fromStdString(ex.what())));\n    }\n\n    finish();\n}\n\nvoid SuitabilityBenchmarkDialog::request_stop()\n{\n    if (!running_) {\n        return;\n    }\n    stop_requested_ = true;\n    append_line(QObject::tr(\"[STOP] Benchmark will stop after the current step is processed.\"), false);\n}\n\nvoid SuitabilityBenchmarkDialog::append_line(const QString& text, bool is_html)\n{\n    if (!output_view_) {\n        return;\n    }\n\n    const QString html = is_html ? text : highlight_figures(text);\n    QTextCursor cursor(output_view_->textCursor());\n    cursor.movePosition(QTextCursor::End);\n    cursor.insertHtml(html);\n    cursor.insertBlock();\n    output_view_->setTextCursor(cursor);\n    if (auto* scroll = output_view_->verticalScrollBar()) {\n        scroll->setValue(scroll->maximum());\n    }\n    if (recording_) {\n        current_report_.push_back(html);\n    }\n}\n\nvoid SuitabilityBenchmarkDialog::set_running_state(bool running)\n{\n    running_ = running;\n    if (progress_bar_) {\n        progress_bar_->setVisible(running);\n    }\n    if (run_button_) {\n        run_button_->setEnabled(!running);\n    }\n    if (stop_button_) {\n        stop_button_->setEnabled(running);\n    }\n    if (close_button_) {\n        close_button_->setEnabled(!running);\n    }\n}\n\nvoid SuitabilityBenchmarkDialog::finish_benchmark()\n{\n    recording_ = false;\n    const std::string timestamp = format_timestamp(std::chrono::system_clock::now());\n    settings_.set_benchmark_last_run(timestamp);\n    settings_.set_benchmark_last_report(current_report_.join('\\n').toStdString());\n    settings_.set_suitability_benchmark_completed(true);\n    settings_.save();\n    set_running_state(false);\n}\n"
  },
  {
    "path": "app/lib/SupportCodeManager.cpp",
    "content": "#include \"SupportCodeManager.hpp\"\n\n#include <QByteArray>\n#include <QCryptographicHash>\n#include <QRandomGenerator>\n#include <QString>\n#include <QSysInfo>\n\n#include <openssl/evp.h>\n\n#include <algorithm>\n#include <array>\n#include <cctype>\n#include <cstddef>\n#include <cstdint>\n#include <fstream>\n#include <initializer_list>\n#include <string_view>\n#include <system_error>\n#include <utility>\n\nnamespace {\n\nconstexpr std::uint32_t kBlobMagic = 0xA15F50C2u;\nconstexpr std::uint32_t kBlobVersion = 2u;\nconstexpr std::size_t kSaltSize = 16u;\nconstexpr std::size_t kHashSize = 32u;\nconstexpr std::size_t kBlobSize = 120u;\nconstexpr std::size_t kSignatureSize = 64u;\nconstexpr char kCodePrefix[] = \"AIFS1\";\nconstexpr char kPayloadPrefix[] = \"aifs-support:v1:\";\n\n// This must match the private key held by the website-side signer.\nconstexpr std::array<unsigned char, 32> kVerificationPublicKey{\n    0xd4, 0x56, 0x9d, 0x00, 0x24, 0x50, 0xf5, 0xa2,\n    0x90, 0x94, 0xff, 0x0f, 0xf8, 0xee, 0xcc, 0x7b,\n    0x4f, 0xfa, 0x05, 0x2a, 0xf8, 0x35, 0x37, 0xba,\n    0x4e, 0xde, 0x3c, 0xc5, 0x16, 0xf5, 0x66, 0xe1,\n};\n\nconstexpr std::array<unsigned char, 32> kBlobPepper{\n    0x6f, 0x24, 0x94, 0x11, 0x5d, 0xca, 0x37, 0xa8,\n    0x7b, 0xe0, 0x12, 0x49, 0xf6, 0x9d, 0x58, 0x03,\n    0xc4, 0x71, 0x2e, 0xb9, 0x8a, 0x16, 0xdd, 0x60,\n    0x34, 0xf3, 0x8c, 0x27, 0x90, 0x4a, 0xbe, 0x15,\n};\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nconstexpr char kTestPayload[] = \"aifs-support:v1:test-build\";\n#endif\n\nstd::string trim_ascii(std::string_view value) {\n    std::size_t first = 0;\n    while (first < value.size() &&\n           std::isspace(static_cast<unsigned char>(value[first])) != 0) {\n        ++first;\n    }\n\n    std::size_t last = value.size();\n    while (last > first &&\n           std::isspace(static_cast<unsigned char>(value[last - 1])) != 0) {\n        --last;\n    }\n\n    return std::string(value.substr(first, last - first));\n}\n\nQByteArray appendable_base64url(std::string_view segment) {\n    if (segment.empty()) {\n        return {};\n    }\n\n    QByteArray encoded(segment.data(), static_cast<qsizetype>(segment.size()));\n    const int remainder = encoded.size() % 4;\n    if (remainder != 0) {\n        encoded.append(QByteArray(4 - remainder, '='));\n    }\n    return encoded;\n}\n\nQByteArray decode_base64url(std::string_view segment) {\n    if (segment.empty()) {\n        return {};\n    }\n\n    return QByteArray::fromBase64(\n        appendable_base64url(segment),\n        QByteArray::Base64UrlEncoding | QByteArray::AbortOnBase64DecodingErrors);\n}\n\nbool is_supported_payload(const QByteArray& payload) {\n    if (!payload.startsWith(kPayloadPrefix)) {\n        return false;\n    }\n\n    if (payload.size() <= static_cast<qsizetype>(std::char_traits<char>::length(kPayloadPrefix)) ||\n        payload.size() > 160) {\n        return false;\n    }\n\n    for (int i = static_cast<int>(std::char_traits<char>::length(kPayloadPrefix)); i < payload.size(); ++i) {\n        const unsigned char ch = static_cast<unsigned char>(payload.at(i));\n        if ((ch >= 'a' && ch <= 'z') ||\n            (ch >= 'A' && ch <= 'Z') ||\n            (ch >= '0' && ch <= '9') ||\n            ch == '-' ||\n            ch == '_' ||\n            ch == ':' ||\n            ch == '.') {\n            continue;\n        }\n        return false;\n    }\n\n    return true;\n}\n\nbool verify_signature(const QByteArray& payload, const QByteArray& signature) {\n    EVP_PKEY* key = EVP_PKEY_new_raw_public_key(\n        EVP_PKEY_ED25519,\n        nullptr,\n        kVerificationPublicKey.data(),\n        kVerificationPublicKey.size());\n    if (!key) {\n        return false;\n    }\n\n    EVP_MD_CTX* ctx = EVP_MD_CTX_new();\n    if (!ctx) {\n        EVP_PKEY_free(key);\n        return false;\n    }\n\n    const bool verified =\n        EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr, key) == 1 &&\n        EVP_DigestVerify(\n            ctx,\n            reinterpret_cast<const unsigned char*>(signature.constData()),\n            static_cast<std::size_t>(signature.size()),\n            reinterpret_cast<const unsigned char*>(payload.constData()),\n            static_cast<std::size_t>(payload.size())) == 1;\n\n    EVP_MD_CTX_free(ctx);\n    EVP_PKEY_free(key);\n    return verified;\n}\n\nQByteArray to_byte_array(std::uint32_t value) {\n    QByteArray bytes(4, Qt::Uninitialized);\n    bytes[0] = static_cast<char>(value & 0xffu);\n    bytes[1] = static_cast<char>((value >> 8) & 0xffu);\n    bytes[2] = static_cast<char>((value >> 16) & 0xffu);\n    bytes[3] = static_cast<char>((value >> 24) & 0xffu);\n    return bytes;\n}\n\nstd::uint32_t from_little_endian_u32(const unsigned char* data) {\n    return static_cast<std::uint32_t>(data[0]) |\n           (static_cast<std::uint32_t>(data[1]) << 8) |\n           (static_cast<std::uint32_t>(data[2]) << 16) |\n           (static_cast<std::uint32_t>(data[3]) << 24);\n}\n\nstd::uint32_t leading_u32(const QByteArray& value) {\n    if (value.size() < 4) {\n        return 0;\n    }\n    const auto* data = reinterpret_cast<const unsigned char*>(value.constData());\n    return from_little_endian_u32(data);\n}\n\nQByteArray sha256_labeled(std::string_view label, std::initializer_list<QByteArray> segments) {\n    QCryptographicHash hash(QCryptographicHash::Sha256);\n    hash.addData(label.data(), static_cast<qsizetype>(label.size()));\n    hash.addData(reinterpret_cast<const char*>(kBlobPepper.data()),\n                 static_cast<qsizetype>(kBlobPepper.size()));\n    for (const QByteArray& segment : segments) {\n        hash.addData(segment);\n    }\n    return hash.result();\n}\n\nstd::array<unsigned char, kSaltSize> random_salt() {\n    std::array<unsigned char, kSaltSize> salt{};\n    for (std::size_t i = 0; i < salt.size(); i += sizeof(quint32)) {\n        const quint32 word = QRandomGenerator::global()->generate();\n        const std::size_t remaining = std::min<std::size_t>(sizeof(word), salt.size() - i);\n        for (std::size_t j = 0; j < remaining; ++j) {\n            salt[i + j] = static_cast<unsigned char>((word >> (j * 8)) & 0xffu);\n        }\n    }\n    return salt;\n}\n\nQByteArray to_byte_array(const std::array<unsigned char, kSaltSize>& value) {\n    return QByteArray(reinterpret_cast<const char*>(value.data()),\n                      static_cast<qsizetype>(value.size()));\n}\n\nstd::filesystem::path blob_filename() {\n    return \"support_prompt_state.bin\";\n}\n\n} // namespace\n\nSupportCodeManager::SupportCodeManager(std::filesystem::path config_dir)\n    : config_dir_(std::move(config_dir)) {}\n\nbool SupportCodeManager::is_valid_code(const std::string& code) {\n    return decode_payload(code).has_value();\n}\n\nbool SupportCodeManager::redeem_code(const std::string& code) const {\n    const auto payload = decode_payload(code);\n    if (!payload.has_value()) {\n        return false;\n    }\n\n    return write_state(*payload);\n}\n\nbool SupportCodeManager::is_prompt_permanently_disabled() const {\n    std::ifstream input(storage_path(), std::ios::binary);\n    if (!input) {\n        return false;\n    }\n\n    std::array<unsigned char, kBlobSize> blob{};\n    input.read(reinterpret_cast<char*>(blob.data()), static_cast<std::streamsize>(blob.size()));\n    if (!input || input.gcount() != static_cast<std::streamsize>(blob.size())) {\n        return false;\n    }\n\n    const std::uint32_t stored_magic = from_little_endian_u32(blob.data());\n    const std::uint32_t stored_version = from_little_endian_u32(blob.data() + 4);\n    const QByteArray salt(reinterpret_cast<const char*>(blob.data() + 8),\n                          static_cast<qsizetype>(kSaltSize));\n    const QByteArray payload_hash(reinterpret_cast<const char*>(blob.data() + 24),\n                                  static_cast<qsizetype>(kHashSize));\n    const QByteArray machine_hash(reinterpret_cast<const char*>(blob.data() + 56),\n                                  static_cast<qsizetype>(kHashSize));\n    const QByteArray checksum(reinterpret_cast<const char*>(blob.data() + 88),\n                              static_cast<qsizetype>(kHashSize));\n\n    const QByteArray expected_machine_hash = sha256_labeled(\n        \"aifs/support/machine/v2\",\n        {salt, QByteArray::fromStdString(machine_binding_key())});\n    if (machine_hash != expected_machine_hash) {\n        return false;\n    }\n\n    if (stored_magic != (kBlobMagic ^ leading_u32(payload_hash)) ||\n        stored_version != (kBlobVersion ^ leading_u32(machine_hash))) {\n        return false;\n    }\n\n    const QByteArray expected_checksum = sha256_labeled(\n        \"aifs/support/blob/v2\",\n        {to_byte_array(stored_magic), to_byte_array(stored_version), salt, payload_hash, machine_hash});\n\n    return checksum == expected_checksum;\n}\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nbool SupportCodeManager::force_disable_prompt_for_testing() const {\n    return write_state(kTestPayload);\n}\n#endif\n\nstd::optional<std::string> SupportCodeManager::decode_payload(const std::string& code) {\n    const std::string trimmed = trim_ascii(code);\n    if (trimmed.empty() || trimmed.size() > 512) {\n        return std::nullopt;\n    }\n\n    const std::size_t first_dot = trimmed.find('.');\n    if (first_dot == std::string::npos || trimmed.substr(0, first_dot) != kCodePrefix) {\n        return std::nullopt;\n    }\n\n    const std::size_t second_dot = trimmed.find('.', first_dot + 1);\n    if (second_dot == std::string::npos || trimmed.find('.', second_dot + 1) != std::string::npos) {\n        return std::nullopt;\n    }\n\n    const std::string_view payload_segment(trimmed.data() + first_dot + 1,\n                                           second_dot - first_dot - 1);\n    const std::string_view signature_segment(trimmed.data() + second_dot + 1,\n                                             trimmed.size() - second_dot - 1);\n    if (payload_segment.empty() || signature_segment.empty()) {\n        return std::nullopt;\n    }\n\n    const QByteArray payload = decode_base64url(payload_segment);\n    const QByteArray signature = decode_base64url(signature_segment);\n    if (payload.isEmpty() ||\n        signature.size() != static_cast<qsizetype>(kSignatureSize) ||\n        !is_supported_payload(payload) ||\n        !verify_signature(payload, signature)) {\n        return std::nullopt;\n    }\n\n    return std::string(payload.constData(), static_cast<std::size_t>(payload.size()));\n}\n\nstd::filesystem::path SupportCodeManager::storage_path() const {\n    return config_dir_ / blob_filename();\n}\n\nstd::string SupportCodeManager::machine_binding_key() const {\n    QByteArray material;\n\n    auto append = [&material](const QByteArray& value) {\n        if (value.isEmpty()) {\n            return;\n        }\n        if (!material.isEmpty()) {\n            material.push_back('\\0');\n        }\n        material.append(value);\n    };\n\n    append(QSysInfo::machineUniqueId());\n    append(QSysInfo::machineHostName().toUtf8());\n    append(QSysInfo::currentCpuArchitecture().toUtf8());\n    append(QSysInfo::buildAbi().toUtf8());\n    append(QSysInfo::kernelType().toUtf8());\n    append(QSysInfo::kernelVersion().toUtf8());\n    append(QSysInfo::prettyProductName().toUtf8());\n\n    if (material.isEmpty()) {\n        material = QByteArray::fromStdString(config_dir_.string());\n    }\n\n    return std::string(material.constData(), static_cast<std::size_t>(material.size()));\n}\n\nbool SupportCodeManager::write_state(const std::string& payload) const {\n    const auto salt = random_salt();\n    const QByteArray salt_bytes = to_byte_array(salt);\n    const QByteArray payload_hash = sha256_labeled(\n        \"aifs/support/payload/v2\",\n        {QByteArray::fromStdString(payload)});\n    const QByteArray machine_hash = sha256_labeled(\n        \"aifs/support/machine/v2\",\n        {salt_bytes, QByteArray::fromStdString(machine_binding_key())});\n\n    const std::uint32_t stored_magic = kBlobMagic ^ leading_u32(payload_hash);\n    const std::uint32_t stored_version = kBlobVersion ^ leading_u32(machine_hash);\n    const QByteArray checksum = sha256_labeled(\n        \"aifs/support/blob/v2\",\n        {to_byte_array(stored_magic), to_byte_array(stored_version), salt_bytes, payload_hash, machine_hash});\n\n    QByteArray blob;\n    blob.reserve(static_cast<qsizetype>(kBlobSize));\n    blob.append(to_byte_array(stored_magic));\n    blob.append(to_byte_array(stored_version));\n    blob.append(salt_bytes);\n    blob.append(payload_hash);\n    blob.append(machine_hash);\n    blob.append(checksum);\n\n    std::error_code ec;\n    std::filesystem::create_directories(config_dir_, ec);\n    if (ec) {\n        return false;\n    }\n\n    std::ofstream output(storage_path(), std::ios::binary | std::ios::trunc);\n    if (!output) {\n        return false;\n    }\n\n    output.write(blob.constData(), static_cast<std::streamsize>(blob.size()));\n    output.close();\n    if (!output) {\n        return false;\n    }\n\n    std::filesystem::permissions(\n        storage_path(),\n        std::filesystem::perms::owner_read | std::filesystem::perms::owner_write,\n        std::filesystem::perm_options::replace,\n        ec);\n\n    return true;\n}\n"
  },
  {
    "path": "app/lib/TranslationManager.cpp",
    "content": "#include \"TranslationManager.hpp\"\n\n#include <QApplication>\n#include <QCoreApplication>\n#include <QDir>\n#include <QFileInfo>\n\n#include <algorithm>\n\nnamespace {\n\nusing LanguageInfo = TranslationManager::LanguageInfo;\n\nstd::vector<LanguageInfo> build_languages()\n{\n    return {\n        {Language::English, QStringLiteral(\"en\"), QStringLiteral(\"English\"), QString()},\n        {Language::Dutch, QStringLiteral(\"nl\"), QStringLiteral(\"Dutch\"), QStringLiteral(\":/i18n/aifilesorter_nl.qm\")},\n        {Language::French, QStringLiteral(\"fr\"), QStringLiteral(\"French\"), QStringLiteral(\":/i18n/aifilesorter_fr.qm\")},\n        {Language::German, QStringLiteral(\"de\"), QStringLiteral(\"German\"), QStringLiteral(\":/i18n/aifilesorter_de.qm\")},\n        {Language::Italian, QStringLiteral(\"it\"), QStringLiteral(\"Italian\"), QStringLiteral(\":/i18n/aifilesorter_it.qm\")},\n        {Language::Spanish, QStringLiteral(\"es\"), QStringLiteral(\"Spanish\"), QStringLiteral(\":/i18n/aifilesorter_es.qm\")},\n        {Language::Turkish, QStringLiteral(\"tr\"), QStringLiteral(\"Turkish\"), QStringLiteral(\":/i18n/aifilesorter_tr.qm\")},\n        {Language::Korean, QStringLiteral(\"ko\"), QStringLiteral(\"Korean\"), QStringLiteral(\":/i18n/aifilesorter_ko.qm\")},\n    };\n}\n\nconst LanguageInfo* find_language_info(const std::vector<LanguageInfo>& languages, Language language)\n{\n    const auto it = std::find_if(\n        languages.cbegin(), languages.cend(),\n        [language](const LanguageInfo& info) { return info.id == language; });\n    if (it == languages.cend()) {\n        return nullptr;\n    }\n    return &(*it);\n}\n\nQStringList translation_search_paths()\n{\n    QStringList paths;\n    if (QCoreApplication::instance()) {\n        const QDir app_dir(QCoreApplication::applicationDirPath());\n        paths << app_dir.filePath(QStringLiteral(\"i18n\"));\n        paths << app_dir.filePath(QStringLiteral(\"../i18n\"));\n#if defined(Q_OS_MACOS)\n        paths << app_dir.filePath(QStringLiteral(\"../Resources/i18n\"));\n#endif\n    }\n\n    const QDir cwd(QDir::currentPath());\n    paths << cwd.filePath(QStringLiteral(\"app/resources/i18n\"));\n    paths << cwd.filePath(QStringLiteral(\"resources/i18n\"));\n    paths.removeDuplicates();\n    return paths;\n}\n\n} // namespace\n\nTranslationManager::TranslationManager() = default;\n\nTranslationManager& TranslationManager::instance()\n{\n    static TranslationManager manager;\n    return manager;\n}\n\nvoid TranslationManager::initialize(QApplication* app)\n{\n    app_ = app;\n    if (!translator_) {\n        translator_ = std::make_unique<QTranslator>();\n    }\n    if (languages_.empty()) {\n        languages_ = build_languages();\n    }\n}\n\nvoid TranslationManager::initialize_for_app(QApplication* app, Language language)\n{\n    initialize(app);\n    set_language(language);\n}\n\nvoid TranslationManager::set_language(Language language)\n{\n    if (languages_.empty()) {\n        languages_ = build_languages();\n    }\n\n    const LanguageInfo* info = find_language_info(languages_, language);\n    if (!info) {\n        language = Language::English;\n        info = find_language_info(languages_, language);\n    }\n\n    if (!app_) {\n        current_language_ = language;\n        return;\n    }\n\n    if (translator_) {\n        app_->removeTranslator(translator_.get());\n        translator_ = std::make_unique<QTranslator>();\n    }\n\n    if (info && language != Language::English) {\n        if (load_translation(*info)) {\n            app_->installTranslator(translator_.get());\n        } else {\n            language = Language::English;\n        }\n    }\n\n    current_language_ = language;\n}\n\nLanguage TranslationManager::current_language() const\n{\n    return current_language_;\n}\n\nconst std::vector<TranslationManager::LanguageInfo>& TranslationManager::available_languages() const\n{\n    return languages_;\n}\n\nbool TranslationManager::load_translation(const LanguageInfo& info)\n{\n    if (!translator_) {\n        return false;\n    }\n\n    if (!info.resource_path.isEmpty() && translator_->load(info.resource_path)) {\n        return true;\n    }\n\n    const QString file_name = QFileInfo(info.resource_path).fileName();\n    if (file_name.isEmpty()) {\n        return false;\n    }\n\n    for (const QString& dir : translation_search_paths()) {\n        const QString candidate = QDir(dir).filePath(file_name);\n        if (QFileInfo::exists(candidate) && translator_->load(candidate)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n"
  },
  {
    "path": "app/lib/UiTranslator.cpp",
    "content": "#include \"UiTranslator.hpp\"\n\n#include \"Language.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"Settings.hpp\"\n\n#include <QAction>\n#include <QActionGroup>\n#include <QCoreApplication>\n#include <QChar>\n#include <QCheckBox>\n#include <QComboBox>\n#include <QDockWidget>\n#include <QLabel>\n#include <QMainWindow>\n#include <QMenu>\n#include <QObject>\n#include <QPointer>\n#include <QPushButton>\n#include <QToolButton>\n#include <QSignalBlocker>\n#include <QStandardItem>\n#include <QStandardItemModel>\n#include <QStatusBar>\n#include <QStringList>\n\nnamespace {\n\ntemplate <typename Widget>\nWidget* raw_ptr(const QPointer<Widget>& pointer)\n{\n    return pointer.data();\n}\n\n} // namespace\n\nUiTranslator::UiTranslator(Dependencies deps)\n    : deps_(deps)\n{\n    if (!deps_.translator) {\n        deps_.translator = [](const char* source) {\n            return QCoreApplication::translate(\"UiTranslator\", source);\n        };\n    }\n}\n\nvoid UiTranslator::retranslate_all(const State& state) const\n{\n    translate_window_title();\n    translate_primary_controls(state.analysis_in_progress);\n    translate_tree_view_labels();\n    translate_menus_and_actions();\n    translate_status_messages(state);\n    update_language_checks();\n}\n\nvoid UiTranslator::translate_window_title() const\n{\n    deps_.window.setWindowTitle(QStringLiteral(\"AI File Sorter\"));\n}\n\nvoid UiTranslator::translate_primary_controls(bool analysis_in_progress) const\n{\n    if (auto* label = raw_ptr(deps_.primary.path_label)) {\n        label->setText(tr(\"Folder:\"));\n    }\n    if (auto* button = raw_ptr(deps_.primary.browse_button)) {\n        button->setText(tr(\"Browse…\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.use_subcategories_checkbox)) {\n        checkbox->setText(tr(\"Use subcategories\"));\n        checkbox->setToolTip(tr(\"Create subcategory folders within each category.\"));\n    }\n    if (auto* heading = raw_ptr(deps_.primary.categorization_style_heading)) {\n        heading->setText(tr(\"Categorization type\"));\n        heading->setToolTip(tr(\"Choose how strict the category labels should be.\"));\n    }\n    if (auto* refined_radio = raw_ptr(deps_.primary.categorization_style_refined_radio)) {\n        refined_radio->setText(tr(\"More refined\"));\n        refined_radio->setToolTip(tr(\"Favor detailed labels even if similar items vary.\"));\n    }\n    if (auto* consistent_radio = raw_ptr(deps_.primary.categorization_style_consistent_radio)) {\n        consistent_radio->setText(tr(\"More consistent\"));\n        consistent_radio->setToolTip(tr(\"Favor consistent labels across similar items.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.use_whitelist_checkbox)) {\n        checkbox->setText(tr(\"Use a whitelist\"));\n        checkbox->setToolTip(tr(\"Restrict categories and subcategories to the selected whitelist.\"));\n    }\n    if (auto* selector = raw_ptr(deps_.primary.whitelist_selector)) {\n        selector->setToolTip(tr(\"Select the whitelist used for this run.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.categorize_files_checkbox)) {\n        checkbox->setText(tr(\"Categorize files\"));\n        checkbox->setToolTip(tr(\"Include files in the categorization pass.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.categorize_directories_checkbox)) {\n        checkbox->setText(tr(\"Categorize folders\"));\n        checkbox->setToolTip(tr(\"Include directories in the categorization pass.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.include_subdirectories_checkbox)) {\n        checkbox->setText(tr(\"Scan subfolders\"));\n        checkbox->setToolTip(tr(\"Scan files inside subfolders and treat them as part of the main folder.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.analyze_images_checkbox)) {\n        checkbox->setText(tr(\"Analyze picture files by content (can be slow)\"));\n        checkbox->setToolTip(tr(\"Run the visual LLM on supported picture files.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.process_images_only_checkbox)) {\n        checkbox->setText(tr(\"Process picture files only (ignore any other files)\"));\n        checkbox->setToolTip(tr(\"Ignore non-picture files in this run.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.add_image_date_to_category_checkbox)) {\n        checkbox->setText(tr(\"Add image creation date (if available) to category name\"));\n        checkbox->setToolTip(tr(\"Append the image creation date from metadata to the category label.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.add_image_date_place_to_filename_checkbox)) {\n        checkbox->setText(tr(\"Add photo date and place to filename (if available)\"));\n        checkbox->setToolTip(tr(\"Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.add_audio_video_metadata_to_filename_checkbox)) {\n        checkbox->setText(tr(\"Add audio/video metadata to file name (if available)\"));\n        checkbox->setToolTip(tr(\"Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.offer_rename_images_checkbox)) {\n        checkbox->setText(tr(\"Offer to rename picture files\"));\n        checkbox->setToolTip(tr(\"Show suggested filenames for picture files.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.rename_images_only_checkbox)) {\n        checkbox->setText(tr(\"Do not categorize picture files (only rename)\"));\n        checkbox->setToolTip(tr(\"Skip categorization for picture files and only rename them.\"));\n    }\n    if (auto* button = raw_ptr(deps_.primary.image_options_toggle_button)) {\n        button->setToolTip(tr(\"Show or hide picture analysis options\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.analyze_documents_checkbox)) {\n        checkbox->setText(tr(\"Analyze document files by content\"));\n        checkbox->setToolTip(tr(\"Summarize document contents with the selected LLM.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.process_documents_only_checkbox)) {\n        checkbox->setText(tr(\"Process document files only (ignore any other files)\"));\n        checkbox->setToolTip(tr(\"Ignore non-document files in this run.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.offer_rename_documents_checkbox)) {\n        checkbox->setText(tr(\"Offer to rename document files\"));\n        checkbox->setToolTip(tr(\"Show suggested filenames for document files.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.rename_documents_only_checkbox)) {\n        checkbox->setText(tr(\"Do not categorize document files (only rename)\"));\n        checkbox->setToolTip(tr(\"Skip categorization for document files and only rename them.\"));\n    }\n    if (auto* checkbox = raw_ptr(deps_.primary.add_document_date_to_category_checkbox)) {\n        checkbox->setText(tr(\"Add document creation date (if available) to category name\"));\n        checkbox->setToolTip(tr(\"Append the document creation date from metadata to the category label.\"));\n    }\n    if (auto* button = raw_ptr(deps_.primary.document_options_toggle_button)) {\n        button->setToolTip(tr(\"Show or hide document analysis options\"));\n    }\n    if (auto* button = raw_ptr(deps_.primary.analyze_button)) {\n        button->setText(analysis_in_progress ? tr(\"Stop analyzing\") : tr(\"Analyze folder\"));\n    }\n}\n\nvoid UiTranslator::translate_tree_view_labels() const\n{\n    QStandardItemModel* model = raw_ptr(deps_.tree_model);\n    if (!model) {\n        return;\n    }\n\n    model->setHorizontalHeaderLabels(QStringList{\n        tr(\"File\"),\n        tr(\"Type\"),\n        tr(\"Category\"),\n        tr(\"Subcategory\"),\n        tr(\"Status\")\n    });\n\n    for (int row = 0; row < model->rowCount(); ++row) {\n        if (auto* type_item = model->item(row, 1)) {\n            const QString type_code = type_item->data(Qt::UserRole).toString();\n            if (type_code == QStringLiteral(\"D\")) {\n                type_item->setText(tr(\"Directory\"));\n            } else if (type_code == QStringLiteral(\"F\")) {\n                type_item->setText(tr(\"File\"));\n            }\n        }\n        if (auto* status_item = model->item(row, 4)) {\n            const QString status_code = status_item->data(Qt::UserRole).toString();\n            if (status_code == QStringLiteral(\"ready\")) {\n                status_item->setText(tr(\"Ready\"));\n            }\n        }\n    }\n}\n\nvoid UiTranslator::translate_menus_and_actions() const\n{\n    struct MenuEntry {\n        QMenu* menu{nullptr};\n        const char* text{nullptr};\n    };\n\n    const MenuEntry menu_entries[] = {\n        {deps_.menus.file_menu, \"&File\"},\n        {deps_.menus.edit_menu, \"&Edit\"},\n        {deps_.menus.view_menu, \"&View\"},\n        {deps_.menus.settings_menu, \"&Settings\"},\n        {deps_.menus.development_menu, \"&Development\"},\n        {deps_.menus.development_settings_menu, \"&Settings\"},\n        {deps_.menus.language_menu, \"Interface &language\"},\n        {deps_.menus.category_language_menu, \"Category &language\"}\n    };\n\n    for (const MenuEntry& entry : menu_entries) {\n        if (entry.menu && entry.text) {\n            entry.menu->setTitle(tr(entry.text));\n        }\n    }\n\n    struct ActionEntry {\n        QAction* action{nullptr};\n        const char* text{nullptr};\n    };\n\n    const ActionEntry action_entries[] = {\n        {deps_.actions.file_quit_action, \"&Quit\"},\n        {deps_.actions.run_benchmark_action, \"System compatibility check…\"},\n        {deps_.actions.copy_action, \"&Copy\"},\n        {deps_.actions.cut_action, \"Cu&t\"},\n        {deps_.actions.undo_last_run_action, \"Undo last run\"},\n        {deps_.actions.paste_action, \"&Paste\"},\n        {deps_.actions.delete_action, \"&Delete\"},\n        {deps_.actions.toggle_explorer_action, \"File &Explorer\"},\n        {deps_.actions.toggle_llm_action, \"Select &LLM…\"},\n        {deps_.actions.manage_whitelists_action, \"Manage category whitelists…\"},\n        {deps_.actions.development_prompt_logging_action, \"Log prompts and responses to stdout\"},\n        {deps_.actions.consistency_pass_action, \"Run &consistency pass\"},\n        {deps_.actions.english_action, \"&English\"},\n        {deps_.actions.dutch_action, \"&Dutch\"},\n        {deps_.actions.french_action, \"&French\"},\n        {deps_.actions.german_action, \"&German\"},\n        {deps_.actions.italian_action, \"&Italian\"},\n        {deps_.actions.spanish_action, \"&Spanish\"},\n        {deps_.actions.turkish_action, \"&Turkish\"},\n        {deps_.actions.korean_action, \"&Korean\"},\n        {deps_.actions.category_language_dutch, \"Dutch\"},\n        {deps_.actions.category_language_english, \"English\"},\n        {deps_.actions.category_language_french, \"French\"},\n        {deps_.actions.category_language_german, \"German\"},\n        {deps_.actions.category_language_italian, \"Italian\"},\n        {deps_.actions.category_language_polish, \"Polish\"},\n        {deps_.actions.category_language_portuguese, \"Portuguese\"},\n        {deps_.actions.category_language_spanish, \"Spanish\"},\n        {deps_.actions.category_language_turkish, \"Turkish\"},\n        {deps_.actions.about_action, \"&About AI File Sorter\"},\n        {deps_.actions.about_qt_action, \"About &Qt\"},\n        {deps_.actions.about_agpl_action, \"About &AGPL\"},\n        {deps_.actions.support_project_action, \"&Support Project\"}\n    };\n\n    for (const ActionEntry& entry : action_entries) {\n        if (entry.action && entry.text) {\n            entry.action->setText(tr(entry.text));\n        }\n    }\n\n    if (auto* menu = deps_.menus.help_menu) {\n        const QString help_title = QString(QChar(0x200B)) + tr(\"&Help\");\n        menu->setTitle(help_title);\n        if (QAction* help_action = menu->menuAction()) {\n            help_action->setText(help_title);\n        }\n    }\n\n    if (auto* dock = raw_ptr(deps_.file_explorer_dock)) {\n        dock->setWindowTitle(tr(\"File Explorer\"));\n    }\n}\n\nvoid UiTranslator::translate_status_messages(const State& state) const\n{\n    QStatusBar* bar = deps_.window.statusBar();\n    if (!bar) {\n        return;\n    }\n\n    if (state.analysis_in_progress) {\n        if (state.stop_analysis_requested) {\n            bar->showMessage(tr(\"Cancelling analysis…\"), 4000);\n        } else {\n            bar->showMessage(tr(\"Analyzing…\"));\n        }\n    } else if (state.status_is_ready) {\n        bar->showMessage(tr(\"Ready\"));\n    }\n}\n\nvoid UiTranslator::update_language_checks() const\n{\n    Language configured = deps_.settings.get_language();\n    update_language_group_checks(configured);\n\n    CategoryLanguage cat_lang = deps_.settings.get_category_language();\n    update_category_language_checks(cat_lang);\n}\n\nvoid UiTranslator::update_language_group_checks(Language configured) const\n{\n    if (!deps_.language.language_group) {\n        return;\n    }\n    QSignalBlocker blocker(deps_.language.language_group);\n    if (deps_.language.english_action) {\n        deps_.language.english_action->setChecked(configured == Language::English);\n    }\n    if (deps_.language.dutch_action) {\n        deps_.language.dutch_action->setChecked(configured == Language::Dutch);\n    }\n    if (deps_.language.french_action) {\n        deps_.language.french_action->setChecked(configured == Language::French);\n    }\n    if (deps_.language.german_action) {\n        deps_.language.german_action->setChecked(configured == Language::German);\n    }\n    if (deps_.language.italian_action) {\n        deps_.language.italian_action->setChecked(configured == Language::Italian);\n    }\n    if (deps_.language.spanish_action) {\n        deps_.language.spanish_action->setChecked(configured == Language::Spanish);\n    }\n    if (deps_.language.turkish_action) {\n        deps_.language.turkish_action->setChecked(configured == Language::Turkish);\n    }\n    if (deps_.language.korean_action) {\n        deps_.language.korean_action->setChecked(configured == Language::Korean);\n    }\n}\n\nvoid UiTranslator::update_category_language_checks(CategoryLanguage configured) const\n{\n    if (!deps_.category_language.category_language_group) {\n        return;\n    }\n    QSignalBlocker blocker_cat(deps_.category_language.category_language_group);\n    if (deps_.category_language.dutch) {\n        deps_.category_language.dutch->setChecked(configured == CategoryLanguage::Dutch);\n    }\n    if (deps_.category_language.english) {\n        deps_.category_language.english->setChecked(configured == CategoryLanguage::English);\n    }\n    if (deps_.category_language.french) {\n        deps_.category_language.french->setChecked(configured == CategoryLanguage::French);\n    }\n    if (deps_.category_language.german) {\n        deps_.category_language.german->setChecked(configured == CategoryLanguage::German);\n    }\n    if (deps_.category_language.italian) {\n        deps_.category_language.italian->setChecked(configured == CategoryLanguage::Italian);\n    }\n    if (deps_.category_language.polish) {\n        deps_.category_language.polish->setChecked(configured == CategoryLanguage::Polish);\n    }\n    if (deps_.category_language.portuguese) {\n        deps_.category_language.portuguese->setChecked(configured == CategoryLanguage::Portuguese);\n    }\n    if (deps_.category_language.spanish) {\n        deps_.category_language.spanish->setChecked(configured == CategoryLanguage::Spanish);\n    }\n    if (deps_.category_language.turkish) {\n        deps_.category_language.turkish->setChecked(configured == CategoryLanguage::Turkish);\n    }\n}\n\nQString UiTranslator::tr(const char* source) const\n{\n    if (deps_.translator) {\n        return deps_.translator(source);\n    }\n    return QCoreApplication::translate(\"UiTranslator\", source);\n}\n"
  },
  {
    "path": "app/lib/UndoManager.cpp",
    "content": "#include \"UndoManager.hpp\"\n\n#include <QDir>\n#include <QFile>\n#include <QFileInfo>\n#include <QJsonArray>\n#include <QJsonDocument>\n#include <QJsonObject>\n#include <QDateTime>\n#include <QMessageBox>\n#include <spdlog/logger.h>\n\n#include <fmt/format.h>\n\nUndoManager::UndoManager(std::string undo_dir)\n    : undo_dir_(std::move(undo_dir))\n{}\n\nbool UndoManager::save_plan(const std::string& run_base_dir,\n                            const std::vector<Entry>& entries,\n                            const std::shared_ptr<spdlog::logger>& logger) const\n{\n    if (undo_dir_.empty() || entries.empty()) {\n        return false;\n    }\n\n    QDir dir(QString::fromStdString(undo_dir_));\n    if (!dir.exists()) {\n        dir.mkpath(QStringLiteral(\".\"));\n    }\n\n    QJsonArray arr;\n    for (const auto& entry : entries) {\n        QJsonObject obj;\n        obj[\"source\"] = QString::fromStdString(entry.source);\n        obj[\"destination\"] = QString::fromStdString(entry.destination);\n        obj[\"size\"] = static_cast<qint64>(entry.size_bytes);\n        obj[\"mtime\"] = static_cast<qint64>(entry.mtime);\n        arr.push_back(obj);\n    }\n\n    QJsonObject root;\n    root[\"version\"] = 1;\n    root[\"base_dir\"] = QString::fromStdString(run_base_dir);\n    root[\"created_at_utc\"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs);\n    root[\"entries\"] = arr;\n\n    const QString filename = QStringLiteral(\"undo_plan_%1.json\")\n        .arg(QDateTime::currentDateTimeUtc().toString(\"yyyyMMdd_hhmmsszzz\"));\n    QFile file(dir.filePath(filename));\n    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {\n        if (logger) {\n            logger->error(\"Failed to write undo plan '{}': {}\", filename.toStdString(), file.errorString().toStdString());\n        }\n        return false;\n    }\n\n    file.write(QJsonDocument(root).toJson(QJsonDocument::Indented));\n    file.close();\n    if (logger) {\n        logger->info(\"Saved undo plan to '{}'\", file.fileName().toStdString());\n    }\n    return true;\n}\n\nstd::optional<QString> UndoManager::latest_plan_path() const\n{\n    if (undo_dir_.empty()) {\n        return std::nullopt;\n    }\n    QDir dir(QString::fromStdString(undo_dir_));\n    if (!dir.exists()) {\n        return std::nullopt;\n    }\n    const auto files = dir.entryInfoList(QStringList() << \"undo_plan_*.json\",\n                                         QDir::Files,\n                                         QDir::Time | QDir::Reversed);\n    if (files.isEmpty()) {\n        return std::nullopt;\n    }\n    return files.back().filePath();\n}\n\nUndoManager::UndoResult UndoManager::undo_plan(const QString& plan_path) const\n{\n    UndoResult result;\n\n    QFile file(plan_path);\n    if (!file.open(QIODevice::ReadOnly)) {\n        result.details << QString(\"Failed to open plan: %1\").arg(plan_path);\n        result.skipped++;\n        return result;\n    }\n\n    const auto doc = QJsonDocument::fromJson(file.readAll());\n    if (!doc.isObject()) {\n        result.details << QString(\"Invalid plan: %1\").arg(plan_path);\n        result.skipped++;\n        return result;\n    }\n\n    const QJsonArray entries = doc.object().value(\"entries\").toArray();\n    for (const auto& val : entries) {\n        if (!val.isObject()) {\n            result.skipped++;\n            continue;\n        }\n        const QJsonObject obj = val.toObject();\n        const QString source = obj.value(\"source\").toString();\n        const QString destination = obj.value(\"destination\").toString();\n        const qint64 expected_size = obj.value(\"size\").toInteger(0);\n        const qint64 expected_mtime = obj.value(\"mtime\").toInteger(0);\n\n        QFileInfo dest_info(destination);\n        if (!dest_info.exists()) {\n            result.details << QString(\"Missing destination: %1\").arg(destination);\n            result.skipped++;\n            continue;\n        }\n\n        QFileInfo src_info(source);\n        if (src_info.exists()) {\n            result.details << QString(\"Source already exists, skipping: %1\").arg(source);\n            result.skipped++;\n            continue;\n        }\n\n        if (expected_size > 0 && dest_info.size() != expected_size) {\n            result.details << QString(\"Size mismatch for %1\").arg(destination);\n            result.skipped++;\n            continue;\n        }\n\n        if (expected_mtime > 0) {\n            const auto mtime = dest_info.lastModified().toSecsSinceEpoch();\n            if (mtime != expected_mtime) {\n                result.details << QString(\"Timestamp mismatch for %1\").arg(destination);\n                result.skipped++;\n                continue;\n            }\n        }\n\n        QDir().mkpath(src_info.path());\n        if (QFile::rename(destination, source)) {\n            result.restored++;\n        } else {\n            result.details << QString(\"Failed to move %1 back to %2\").arg(destination, source);\n            result.skipped++;\n        }\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "app/lib/UpdateArchiveExtractor.cpp",
    "content": "#include \"UpdateArchiveExtractor.hpp\"\n\n#include <algorithm>\n#include <array>\n#include <cctype>\n#include <cstdint>\n#include <filesystem>\n#include <fstream>\n#include <optional>\n#include <string>\n#include <system_error>\n#include <vector>\n\n#include <zip.h>\n\nnamespace {\n\nstd::string ascii_lower_copy(std::string value)\n{\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nbool is_directory_entry(const std::string& entry_name)\n{\n    return !entry_name.empty() && entry_name.back() == '/';\n}\n\nbool is_installer_entry(const std::string& entry_name)\n{\n    const std::string extension = ascii_lower_copy(std::filesystem::path(entry_name).extension().string());\n    return extension == \".exe\" || extension == \".msi\";\n}\n\nstd::optional<std::filesystem::path> sanitize_archive_path(const std::string& entry_name)\n{\n    const std::filesystem::path normalized = std::filesystem::path(entry_name).lexically_normal();\n    if (normalized.empty() || normalized.has_root_name() || normalized.has_root_directory()) {\n        return std::nullopt;\n    }\n\n    std::filesystem::path sanitized;\n    for (const auto& component : normalized) {\n        if (component == \".\" || component.empty()) {\n            continue;\n        }\n        if (component == \"..\") {\n            return std::nullopt;\n        }\n        sanitized /= component;\n    }\n\n    if (sanitized.empty()) {\n        return std::nullopt;\n    }\n    return sanitized;\n}\n\nstd::string archive_error_message(zip_t* archive)\n{\n    const char* message = zip_strerror(archive);\n    return message ? std::string(message) : std::string(\"Unknown ZIP archive error.\");\n}\n\nUpdateArchiveExtractor::ExtractionResult extract_entry(zip_t* archive,\n                                                       zip_uint64_t index,\n                                                       const std::filesystem::path& destination_root,\n                                                       const std::filesystem::path& relative_path)\n{\n    const auto destination_path = destination_root / relative_path;\n    const auto partial_path = std::filesystem::path(destination_path.string() + \".part\");\n\n    std::error_code ec;\n    std::filesystem::create_directories(destination_path.parent_path(), ec);\n    if (ec) {\n        return UpdateArchiveExtractor::ExtractionResult::failure(\n            \"Failed to create archive extraction directory: \" + ec.message());\n    }\n\n    zip_file_t* file = zip_fopen_index(archive, index, 0);\n    if (!file) {\n        return UpdateArchiveExtractor::ExtractionResult::failure(\n            \"Failed to open installer inside the ZIP archive.\");\n    }\n\n    std::ofstream out(partial_path, std::ios::binary | std::ios::trunc);\n    if (!out) {\n        zip_fclose(file);\n        return UpdateArchiveExtractor::ExtractionResult::failure(\n            \"Failed to create the extracted installer file.\");\n    }\n\n    std::array<char, 64 * 1024> buffer{};\n    while (true) {\n        const zip_int64_t read = zip_fread(file, buffer.data(), buffer.size());\n        if (read < 0) {\n            out.close();\n            zip_fclose(file);\n            std::filesystem::remove(partial_path, ec);\n            return UpdateArchiveExtractor::ExtractionResult::failure(archive_error_message(archive));\n        }\n        if (read == 0) {\n            break;\n        }\n        out.write(buffer.data(), static_cast<std::streamsize>(read));\n        if (!out) {\n            out.close();\n            zip_fclose(file);\n            std::filesystem::remove(partial_path, ec);\n            return UpdateArchiveExtractor::ExtractionResult::failure(\n                \"Failed while writing the extracted installer.\");\n        }\n    }\n\n    out.close();\n    zip_fclose(file);\n\n    std::filesystem::remove(destination_path, ec);\n    ec.clear();\n    std::filesystem::rename(partial_path, destination_path, ec);\n    if (ec) {\n        std::filesystem::remove(partial_path, ec);\n        return UpdateArchiveExtractor::ExtractionResult::failure(\n            \"Failed to finalize the extracted installer: \" + ec.message());\n    }\n\n    return UpdateArchiveExtractor::ExtractionResult::success(destination_path);\n}\n\n} // namespace\n\nbool UpdateArchiveExtractor::supports_archive(const std::filesystem::path& package_path)\n{\n    return ascii_lower_copy(package_path.extension().string()) == \".zip\";\n}\n\nUpdateArchiveExtractor::ExtractionResult UpdateArchiveExtractor::extract_installer(\n    const std::filesystem::path& archive_path,\n    const std::filesystem::path& destination_root)\n{\n    if (!supports_archive(archive_path)) {\n        return ExtractionResult::failure(\"Only ZIP update packages are supported.\");\n    }\n\n    int error_code = 0;\n    zip_t* archive = zip_open(archive_path.string().c_str(), ZIP_RDONLY, &error_code);\n    if (!archive) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, error_code);\n        const char* message = zip_error_strerror(&error);\n        const std::string error_message = message ? std::string(message) : std::string(\"Failed to open ZIP archive.\");\n        zip_error_fini(&error);\n        return ExtractionResult::failure(error_message);\n    }\n\n    std::vector<std::pair<zip_uint64_t, std::filesystem::path>> installer_candidates;\n    const zip_int64_t entry_count = zip_get_num_entries(archive, 0);\n    if (entry_count < 0) {\n        const std::string error_message = archive_error_message(archive);\n        zip_close(archive);\n        return ExtractionResult::failure(error_message);\n    }\n    for (zip_uint64_t index = 0; index < static_cast<zip_uint64_t>(entry_count); ++index) {\n        const char* raw_name = zip_get_name(archive, index, 0);\n        if (!raw_name) {\n            continue;\n        }\n\n        const std::string entry_name(raw_name);\n        if (is_directory_entry(entry_name) || !is_installer_entry(entry_name)) {\n            continue;\n        }\n\n        const auto sanitized = sanitize_archive_path(entry_name);\n        if (!sanitized) {\n            zip_close(archive);\n            return ExtractionResult::failure(\"The ZIP archive contains an unsafe installer path.\");\n        }\n\n        installer_candidates.emplace_back(index, *sanitized);\n    }\n\n    if (installer_candidates.empty()) {\n        zip_close(archive);\n        return ExtractionResult::failure(\n            \"The ZIP archive does not contain an installer (.exe or .msi).\");\n    }\n\n    if (installer_candidates.size() > 1) {\n        zip_close(archive);\n        return ExtractionResult::failure(\n            \"The ZIP archive contains multiple installer candidates. Keep only one .exe or .msi file in the package.\");\n    }\n\n    const auto [index, relative_path] = installer_candidates.front();\n    auto result = extract_entry(archive, index, destination_root, relative_path);\n    zip_close(archive);\n    return result;\n}\n"
  },
  {
    "path": "app/lib/UpdateFeed.cpp",
    "content": "#include \"UpdateFeed.hpp\"\n\n#include <algorithm>\n#include <cctype>\n#include <memory>\n#include <stdexcept>\n\n#if __has_include(<jsoncpp/json/json.h>)\n    #include <jsoncpp/json/json.h>\n#elif __has_include(<json/json.h>)\n    #include <json/json.h>\n#else\n    #error \"jsoncpp headers not found. Install jsoncpp development files.\"\n#endif\n\nnamespace {\n\nstd::string trim_copy(const std::string& value)\n{\n    auto trimmed = value;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    return trimmed;\n}\n\nstd::string normalized_sha256(std::string value)\n{\n    value = trim_copy(value);\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nconst char* platform_key(UpdateFeed::Platform platform)\n{\n    switch (platform) {\n        case UpdateFeed::Platform::Windows: return \"windows\";\n        case UpdateFeed::Platform::MacOS: return \"macos\";\n        case UpdateFeed::Platform::Linux: return \"linux\";\n    }\n    return \"linux\";\n}\n\nbool has_platform_streams(const Json::Value& update)\n{\n    return (update.isMember(\"windows\") && update[\"windows\"].isObject())\n        || (update.isMember(\"macos\") && update[\"macos\"].isObject())\n        || (update.isMember(\"linux\") && update[\"linux\"].isObject());\n}\n\nconst Json::Value* resolve_stream_root(const Json::Value& update, UpdateFeed::Platform platform)\n{\n    const char* key = platform_key(platform);\n\n    if (update.isMember(\"streams\") && update[\"streams\"].isObject()) {\n        const Json::Value& streams = update[\"streams\"];\n        if (streams.isMember(key) && streams[key].isObject()) {\n            return &streams[key];\n        }\n        if (has_platform_streams(streams)) {\n            return nullptr;\n        }\n    }\n\n    if (update.isMember(key) && update[key].isObject()) {\n        return &update[key];\n    }\n    if (has_platform_streams(update)) {\n        return nullptr;\n    }\n\n    if (update.isObject()) {\n        return &update;\n    }\n\n    return nullptr;\n}\n\nstd::string string_member(const Json::Value& object, const char* key)\n{\n    if (object.isMember(key) && object[key].isString()) {\n        return trim_copy(object[key].asString());\n    }\n    return {};\n}\n\n} // namespace\n\nUpdateFeed::Platform UpdateFeed::current_platform()\n{\n#if defined(_WIN32)\n    return Platform::Windows;\n#elif defined(__APPLE__)\n    return Platform::MacOS;\n#else\n    return Platform::Linux;\n#endif\n}\n\nstd::optional<UpdateInfo> UpdateFeed::parse_for_current_platform(const std::string& update_json)\n{\n    return parse_for_platform(update_json, current_platform());\n}\n\nstd::optional<UpdateInfo> UpdateFeed::parse_for_platform(const std::string& update_json, Platform platform)\n{\n    Json::CharReaderBuilder reader_builder;\n    Json::Value root;\n    std::string errors;\n\n    std::unique_ptr<Json::CharReader> reader(reader_builder.newCharReader());\n    if (!reader->parse(update_json.c_str(),\n                       update_json.c_str() + update_json.length(),\n                       &root,\n                       &errors)) {\n        throw std::runtime_error(\"JSON Parse Error: \" + errors);\n    }\n\n    if (!root.isMember(\"update\") || !root[\"update\"].isObject()) {\n        return std::nullopt;\n    }\n\n    const Json::Value& update = root[\"update\"];\n    const Json::Value* stream = resolve_stream_root(update, platform);\n    if (!stream || !stream->isObject()) {\n        return std::nullopt;\n    }\n\n    UpdateInfo info;\n    info.current_version = string_member(*stream, \"current_version\");\n    info.min_version = string_member(*stream, \"min_version\");\n    info.download_url = string_member(*stream, \"download_url\");\n    info.release_notes_url = string_member(*stream, \"release_notes_url\");\n    info.installer_url = string_member(*stream, \"installer_url\");\n    info.installer_sha256 = normalized_sha256(string_member(*stream, \"installer_sha256\"));\n\n    if (info.min_version.empty()) {\n        info.min_version = \"0.0.0\";\n    }\n    if (info.download_url.empty() && !info.installer_url.empty()) {\n        info.download_url = info.installer_url;\n    }\n\n    if (info.current_version.empty() || !info.has_download_target()) {\n        return std::nullopt;\n    }\n\n    return info;\n}\n"
  },
  {
    "path": "app/lib/UpdateInstaller.cpp",
    "content": "#include \"UpdateInstaller.hpp\"\n\n#include \"UpdateArchiveExtractor.hpp\"\n#include \"Logger.hpp\"\n#include \"Utils.hpp\"\n\n#include <algorithm>\n#include <cctype>\n#include <cstdio>\n#include <filesystem>\n#include <stdexcept>\n#include <string>\n#include <system_error>\n\n#include <curl/curl.h>\n#include <curl/easy.h>\n#include <QCryptographicHash>\n#include <QFile>\n#include <QFileInfo>\n#include <QProcess>\n#include <QUrl>\n#include <spdlog/fmt/fmt.h>\n#include <spdlog/spdlog.h>\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    #include \"UpdateInstallerTestAccess.hpp\"\n#endif\n\n#ifdef _WIN32\n    #include <windows.h>\n#endif\n\nnamespace {\n\ntemplate <typename... Args>\nvoid update_installer_log(spdlog::level::level_enum level, const char* fmt, Args&&... args)\n{\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nstd::string ascii_lower_copy(std::string value)\n{\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nvoid configure_tls(CURL* curl)\n{\n#if defined(_WIN32)\n    const auto cert_path = Utils::ensure_ca_bundle();\n    curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str());\n#else\n    (void)curl;\n#endif\n}\n\nstd::string normalize_sha256(std::string value)\n{\n    value.erase(std::remove_if(value.begin(), value.end(), [](unsigned char ch) {\n        return std::isspace(ch) != 0;\n    }), value.end());\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nstd::string safe_version_fragment(std::string version)\n{\n    std::transform(version.begin(), version.end(), version.begin(), [](unsigned char ch) {\n        if (std::isalnum(ch) || ch == '.' || ch == '_' || ch == '-') {\n            return static_cast<char>(ch);\n        }\n        return '_';\n    });\n    return version;\n}\n\nstd::string installer_file_name_from_url(const std::string& url)\n{\n    const QUrl parsed = QUrl::fromUserInput(QString::fromStdString(url));\n    QString file_name = QFileInfo(parsed.path()).fileName();\n    if (file_name.isEmpty()) {\n        file_name = QStringLiteral(\"aifs-update-installer\");\n    }\n    return file_name.toStdString();\n}\n\nbool is_archive_package(const std::filesystem::path& path)\n{\n    return UpdateArchiveExtractor::supports_archive(path);\n}\n\nbool replace_file(const std::filesystem::path& source,\n                  const std::filesystem::path& target,\n                  std::string& error)\n{\n#ifdef _WIN32\n    if (MoveFileExW(source.c_str(),\n                    target.c_str(),\n                    MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {\n        return true;\n    }\n    error = std::system_category().message(static_cast<int>(GetLastError()));\n    return false;\n#else\n    std::error_code ec;\n    std::filesystem::rename(source, target, ec);\n    if (!ec) {\n        return true;\n    }\n    error = ec.message();\n    return false;\n#endif\n}\n\nFILE* open_binary_file_for_write(const std::filesystem::path& path)\n{\n#ifdef _WIN32\n    return _wfopen(path.c_str(), L\"wb\");\n#else\n    return std::fopen(path.c_str(), \"wb\");\n#endif\n}\n\nsize_t write_data(void* ptr, size_t size, size_t nmemb, FILE* stream)\n{\n    return std::fwrite(ptr, size, nmemb, stream);\n}\n\nstruct DownloadContext {\n    UpdateInstaller::ProgressCallback progress_cb;\n    UpdateInstaller::CancelCheck cancel_check;\n};\n\nint progress_callback(void* clientp,\n                      curl_off_t dltotal,\n                      curl_off_t dlnow,\n                      curl_off_t,\n                      curl_off_t)\n{\n    auto* context = static_cast<DownloadContext*>(clientp);\n    if (context->cancel_check && context->cancel_check()) {\n        return 1;\n    }\n    if (context->progress_cb) {\n        const double progress =\n            dltotal > 0 ? static_cast<double>(dlnow) / static_cast<double>(dltotal) : 0.0;\n        const std::string message =\n            dltotal > 0\n                ? fmt::format(\"Downloaded {} / {}\",\n                              Utils::format_size(dlnow),\n                              Utils::format_size(dltotal))\n                : fmt::format(\"Downloaded {}\", Utils::format_size(dlnow));\n        context->progress_cb(progress, message);\n    }\n    return 0;\n}\n\n} // namespace\n\nUpdateInstaller::UpdateInstaller(Settings& settings,\n                                 DownloadFunction download_fn,\n                                 LaunchFunction launch_fn)\n    : settings_(settings),\n      download_fn_(download_fn ? std::move(download_fn) : UpdateInstaller::default_download),\n      launch_fn_(launch_fn ? std::move(launch_fn) : UpdateInstaller::default_launch)\n{\n}\n\nUpdateInstaller::DownloadCanceledError::DownloadCanceledError()\n    : std::runtime_error(\"Download cancelled\")\n{\n}\n\nbool UpdateInstaller::supports_auto_install(const UpdateInfo& info) const\n{\n#if defined(_WIN32)\n    return !info.installer_url.empty() && !info.installer_sha256.empty();\n#else\n    (void)info;\n    return false;\n#endif\n}\n\nUpdatePreparationResult UpdateInstaller::prepare(const UpdateInfo& info,\n                                                 ProgressCallback progress_cb,\n                                                 CancelCheck cancel_check) const\n{\n    if (info.installer_url.empty()) {\n        return UpdatePreparationResult::failed(\"No installer URL is available for this update.\");\n    }\n    if (info.installer_sha256.empty()) {\n        return UpdatePreparationResult::failed(\"No installer SHA-256 is available for this update.\");\n    }\n\n    const auto package_path = package_path_for(info);\n    const auto partial_path = std::filesystem::path(package_path.string() + \".part\");\n    const auto extracted_root = extracted_installer_root_for(package_path);\n\n    std::error_code ec;\n    std::filesystem::create_directories(package_path.parent_path(), ec);\n    if (ec) {\n        return UpdatePreparationResult::failed(\"Failed to create updater cache directory: \" + ec.message());\n    }\n\n    const auto finalize_prepared_package = [&]() -> UpdatePreparationResult {\n        if (!is_archive_package(package_path)) {\n            return UpdatePreparationResult::ready(package_path);\n        }\n\n        std::filesystem::remove_all(extracted_root, ec);\n        ec.clear();\n        if (progress_cb) {\n            progress_cb(1.0, \"Extracting installer from update package\");\n        }\n        const auto extraction = UpdateArchiveExtractor::extract_installer(package_path, extracted_root);\n        if (!extraction.ok()) {\n            return UpdatePreparationResult::failed(extraction.message);\n        }\n        return UpdatePreparationResult::ready(extraction.installer_path);\n    };\n\n    if (progress_cb) {\n        progress_cb(0.0, \"Checking cached installer\");\n    }\n    if (verify_file(package_path, info.installer_sha256)) {\n        return finalize_prepared_package();\n    }\n\n    std::filesystem::remove(package_path, ec);\n    ec.clear();\n    std::filesystem::remove(partial_path, ec);\n    ec.clear();\n    std::filesystem::remove_all(extracted_root, ec);\n\n    try {\n        download_fn_(info.installer_url, partial_path, progress_cb, cancel_check);\n        if (progress_cb) {\n            progress_cb(1.0, \"Verifying installer\");\n        }\n        if (!verify_file(partial_path, info.installer_sha256)) {\n            std::filesystem::remove(partial_path, ec);\n            return UpdatePreparationResult::failed(\"The downloaded installer failed SHA-256 verification.\");\n        }\n\n        std::string replace_error;\n        if (!replace_file(partial_path, package_path, replace_error)) {\n            std::filesystem::remove(partial_path, ec);\n            return UpdatePreparationResult::failed(\"Failed to finalize installer download: \" + replace_error);\n        }\n        return finalize_prepared_package();\n    } catch (const DownloadCanceledError&) {\n        std::filesystem::remove(partial_path, ec);\n        return UpdatePreparationResult::canceled(\"Download cancelled\");\n    } catch (const std::exception& ex) {\n        std::filesystem::remove(partial_path, ec);\n        return UpdatePreparationResult::failed(ex.what());\n    }\n}\n\nbool UpdateInstaller::launch(const std::filesystem::path& installer_path) const\n{\n    return launch_fn_(installer_path);\n}\n\nstd::filesystem::path UpdateInstaller::updates_dir() const\n{\n    return Utils::utf8_to_path(settings_.get_config_dir()) / \"updates\";\n}\n\nstd::filesystem::path UpdateInstaller::package_path_for(const UpdateInfo& info) const\n{\n    const std::string file_name = installer_file_name_from_url(info.installer_url);\n    const std::string version_prefix = \"v\" + safe_version_fragment(info.current_version) + \"-\";\n    return updates_dir() / (version_prefix + file_name);\n}\n\nstd::filesystem::path UpdateInstaller::extracted_installer_root_for(const std::filesystem::path& package_path) const\n{\n    return package_path.parent_path() / (package_path.filename().string() + \".contents\");\n}\n\nstd::string UpdateInstaller::compute_sha256(const std::filesystem::path& path) const\n{\n    QFile file(QString::fromStdString(Utils::path_to_utf8(path)));\n    if (!file.open(QIODevice::ReadOnly)) {\n        throw std::runtime_error(\"Failed to open installer for SHA-256 verification.\");\n    }\n\n    QCryptographicHash hash(QCryptographicHash::Sha256);\n    while (!file.atEnd()) {\n        const QByteArray chunk = file.read(1 << 20);\n        if (chunk.isEmpty() && file.error() != QFile::NoError) {\n            throw std::runtime_error(\"Failed while reading installer for SHA-256 verification.\");\n        }\n        hash.addData(chunk);\n    }\n\n    return hash.result().toHex().toStdString();\n}\n\nbool UpdateInstaller::verify_file(const std::filesystem::path& path, const std::string& expected_sha256) const\n{\n    if (expected_sha256.empty()) {\n        return false;\n    }\n\n    std::error_code ec;\n    if (!std::filesystem::exists(path, ec) || ec) {\n        return false;\n    }\n\n    try {\n        return compute_sha256(path) == normalize_sha256(expected_sha256);\n    } catch (const std::exception& ex) {\n        update_installer_log(spdlog::level::warn,\n                             \"Failed to verify installer '{}': {}\",\n                             path.string(),\n                             ex.what());\n        return false;\n    }\n}\n\nUpdateInstaller::LaunchRequest UpdateInstaller::build_launch_request(const std::filesystem::path& installer_path)\n{\n    const std::string installer = Utils::path_to_utf8(installer_path);\n    if (ascii_lower_copy(installer_path.extension().string()) == \".msi\") {\n        return LaunchRequest{\n            \"msiexec.exe\",\n            {\"/i\", installer}\n        };\n    }\n    return LaunchRequest{installer, {}};\n}\n\nvoid UpdateInstaller::default_download(const std::string& url,\n                                       const std::filesystem::path& destination_path,\n                                       ProgressCallback progress_cb,\n                                       CancelCheck cancel_check)\n{\n    CURL* curl = curl_easy_init();\n    if (!curl) {\n        throw std::runtime_error(\"Failed to initialize cURL for installer download.\");\n    }\n\n    FILE* file = open_binary_file_for_write(destination_path);\n    if (!file) {\n        curl_easy_cleanup(curl);\n        throw std::runtime_error(\"Failed to open the installer destination for writing.\");\n    }\n\n    DownloadContext context{\n        std::move(progress_cb),\n        std::move(cancel_check)\n    };\n\n    try {\n        configure_tls(curl);\n    } catch (const std::exception& ex) {\n        std::fclose(file);\n        curl_easy_cleanup(curl);\n        throw std::runtime_error(std::string(\"Failed to stage CA bundle: \") + ex.what());\n    }\n\n    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);\n    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);\n    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);\n    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);\n    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &progress_callback);\n    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &context);\n\n    const CURLcode res = curl_easy_perform(curl);\n    std::fclose(file);\n    curl_easy_cleanup(curl);\n\n    if (res == CURLE_ABORTED_BY_CALLBACK) {\n        throw DownloadCanceledError();\n    }\n    if (res != CURLE_OK) {\n        throw std::runtime_error(std::string(\"Installer download failed: \") + curl_easy_strerror(res));\n    }\n}\n\nbool UpdateInstaller::default_launch(const std::filesystem::path& installer_path)\n{\n#if defined(_WIN32)\n    const auto request = build_launch_request(installer_path);\n    QStringList arguments;\n    arguments.reserve(static_cast<qsizetype>(request.arguments.size()));\n    for (const auto& argument : request.arguments) {\n        arguments.push_back(QString::fromStdString(argument));\n    }\n    return QProcess::startDetached(QString::fromStdString(request.program), arguments);\n#else\n    (void)installer_path;\n    return false;\n#endif\n}\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nUpdateInstaller::LaunchRequest UpdateInstallerTestAccess::build_launch_request(const std::filesystem::path& installer_path)\n{\n    return UpdateInstaller::build_launch_request(installer_path);\n}\n#endif\n"
  },
  {
    "path": "app/lib/Updater.cpp",
    "content": "#include \"Updater.hpp\"\n#include \"Logger.hpp\"\n#include \"UpdaterBuildConfig.hpp\"\n#include \"UpdaterLaunchOptions.hpp\"\n#include \"Utils.hpp\"\n#include \"app_version.hpp\"\n#include <curl/curl.h>\n#include <algorithm>\n#include <cctype>\n#include <cstdio>\n#include <filesystem>\n#include <iostream>\n#include <optional>\n#include <sstream>\n#include <stdexcept>\n#include <curl/easy.h>\n#include <future>\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/fmt.h>\n#include <QApplication>\n#include <QDesktopServices>\n#include <QMessageBox>\n#include <QMetaObject>\n#include <QObject>\n#include <QPushButton>\n#include <QProgressDialog>\n#include <QUrl>\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\n    #include \"UpdaterTestAccess.hpp\"\n#endif\n\nnamespace {\ntemplate <typename... Args>\nvoid updater_log(spdlog::level::level_enum level, const char* fmt, Args&&... args) {\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nstd::string trim_copy(const std::string& value)\n{\n    auto trimmed = value;\n    auto not_space = [](unsigned char ch) { return !std::isspace(ch); };\n    trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), not_space));\n    trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), not_space).base(), trimmed.end());\n    return trimmed;\n}\n\nstd::optional<std::string> env_string(const char* key)\n{\n    const char* value = std::getenv(key);\n    if (!value || value[0] == '\\0') {\n        return std::nullopt;\n    }\n    const std::string trimmed = trim_copy(value);\n    if (trimmed.empty()) {\n        return std::nullopt;\n    }\n    return trimmed;\n}\n\nbool env_flag_enabled(const char* key)\n{\n    const auto value = env_string(key);\n    if (!value) {\n        return false;\n    }\n\n    std::string lowered = *value;\n    std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return lowered == \"1\" || lowered == \"true\" || lowered == \"yes\" || lowered == \"on\";\n}\n\nstd::string normalized_sha256_copy(std::string value)\n{\n    value.erase(std::remove_if(value.begin(), value.end(), [](unsigned char ch) {\n        return std::isspace(ch) != 0;\n    }), value.end());\n    std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {\n        return static_cast<char>(std::tolower(ch));\n    });\n    return value;\n}\n\nvoid throw_for_http_status(long http_code)\n{\n    if (http_code == 401) {\n        throw std::runtime_error(\"Authentication Error: Invalid or missing API key.\");\n    }\n    if (http_code == 403) {\n        throw std::runtime_error(\"Authorization Error: API key does not have sufficient permissions.\");\n    }\n    if (http_code >= 500) {\n        throw std::runtime_error(\"Server Error: The server returned an error. Status code: \" + std::to_string(http_code));\n    }\n    if (http_code >= 400) {\n        throw std::runtime_error(\"Client Error: The server returned an error. Status code: \" + std::to_string(http_code));\n    }\n}\n\nvoid configure_tls(CURL* curl)\n{\n#if defined(_WIN32)\n    const auto cert_path = Utils::ensure_ca_bundle();\n    curl_easy_setopt(curl, CURLOPT_CAINFO, cert_path.string().c_str());\n#else\n    (void)curl;\n#endif\n}\n\nvoid open_download_url(const std::string& url)\n{\n    const QUrl qurl(QString::fromStdString(url));\n    if (!QDesktopServices::openUrl(qurl)) {\n        updater_log(spdlog::level::err, \"Failed to open URL: {}\", url);\n    }\n}\n}\n\n\nUpdater::Updater(Settings& settings) \n    :\n    settings(settings),\n    installer(settings),\n    update_spec_file_url_(env_string(\"UPDATE_SPEC_FILE_URL\")),\n    open_download_url_fn_([](const std::string& url) { open_download_url(url); }),\n    quit_fn_([]() { QApplication::quit(); })\n{}\n\n\nvoid Updater::check_updates()\n{\n    if (auto live_test = resolve_live_test_update()) {\n        update_info = std::move(live_test);\n    } else {\n        std::string update_json = fetch_update_metadata();\n        update_info = UpdateFeed::parse_for_current_platform(update_json);\n    }\n    if (!update_info) {\n        update_info.reset();\n        return;\n    }\n\n    if (APP_VERSION >= string_to_Version(update_info->current_version)) {\n        update_info.reset();\n    }\n}\n\nstd::optional<UpdateInfo> Updater::resolve_live_test_update() const\n{\n#if !defined(_WIN32)\n    return std::nullopt;\n#else\n    if (!env_flag_enabled(UpdaterLaunchOptions::kLiveTestModeEnv)) {\n        return std::nullopt;\n    }\n\n    const auto installer_url = env_string(UpdaterLaunchOptions::kLiveTestUrlEnv);\n    if (!installer_url) {\n        throw std::runtime_error(\n            \"Updater live test mode requires an installer URL via \"\n            \"--updater-live-test-url or AI_FILE_SORTER_UPDATER_TEST_URL.\");\n    }\n\n    const auto installer_sha256 = env_string(UpdaterLaunchOptions::kLiveTestSha256Env);\n    if (!installer_sha256) {\n        throw std::runtime_error(\n            \"Updater live test mode requires an archive SHA-256 via \"\n            \"--updater-live-test-sha256 or AI_FILE_SORTER_UPDATER_TEST_SHA256.\");\n    }\n\n    UpdateInfo info;\n    info.current_version = env_string(UpdaterLaunchOptions::kLiveTestVersionEnv)\n                               .value_or(APP_VERSION.to_string() + \".1\");\n    info.min_version = env_string(UpdaterLaunchOptions::kLiveTestMinVersionEnv)\n                           .value_or(\"0.0.0\");\n    info.download_url = *installer_url;\n    info.installer_url = *installer_url;\n    info.installer_sha256 = normalized_sha256_copy(*installer_sha256);\n\n    updater_log(spdlog::level::info,\n                \"Updater live test mode enabled for package '{}'\",\n                info.installer_url);\n    return info;\n#endif\n}\n\n\nbool Updater::is_update_available()\n{\n    check_updates();\n    return update_info.has_value();\n}\n\n\nbool Updater::is_update_required()\n{\n    return string_to_Version(update_info.value_or(UpdateInfo()).min_version) > APP_VERSION;\n}\n\n\nvoid Updater::begin()\n{\n    if (!UpdaterBuildConfig::update_checks_enabled()) {\n        updater_log(spdlog::level::info, \"Updater checks disabled for this build.\");\n        return;\n    }\n\n    this->update_future = std::async(std::launch::async, [this]() { \n        try {\n            if (is_update_available()) {\n                QMetaObject::invokeMethod(QApplication::instance(), [this]() {\n                    if (is_update_required()) {\n                        display_update_dialog(true);\n                    } else if (!is_update_skipped()) {\n                        display_update_dialog(false);\n                    }\n                }, Qt::QueuedConnection);\n            } else {\n                QMetaObject::invokeMethod(QApplication::instance(), []() {\n                    std::cout << \"No updates available.\\n\";\n                }, Qt::QueuedConnection);\n            }\n        } catch (const std::exception &e) {\n            QMetaObject::invokeMethod(QApplication::instance(), [msg = std::string(e.what())]() {\n                updater_log(spdlog::level::err, \"Updater encountered an error: {}\", msg);\n            }, Qt::QueuedConnection);\n        }\n    });\n}\n\n\nbool Updater::is_update_skipped()\n{\n    if (!update_info) {\n        return false;\n    }\n    Version skipped_version = string_to_Version(settings.get_skipped_version());\n    return string_to_Version(update_info->current_version) <= skipped_version;\n}\n\n\nvoid Updater::display_update_dialog(bool is_required) {\n    if (!update_info) {\n        updater_log(spdlog::level::warn, \"No update information available.\");\n        return;\n    }\n\n    QWidget* parent = QApplication::activeWindow();\n    const auto& info = update_info.value();\n\n    if (is_required) {\n        show_required_update_dialog(info, parent);\n        return;\n    }\n\n    show_optional_update_dialog(info, parent);\n}\n\n\nvoid Updater::show_required_update_dialog(const UpdateInfo& info, QWidget* parent)\n{\n    while (true) {\n        QMessageBox box(parent);\n        box.setIcon(QMessageBox::Warning);\n        box.setWindowTitle(QObject::tr(\"Required Update Available\"));\n        box.setText(QObject::tr(\"A required update is available. Please update to continue.\\nIf you choose to quit, the application will close.\"));\n        QPushButton* update_now = box.addButton(QObject::tr(\"Update Now\"), QMessageBox::AcceptRole);\n        QPushButton* quit_button = box.addButton(QObject::tr(\"Quit\"), QMessageBox::RejectRole);\n        box.setDefaultButton(update_now);\n        box.exec();\n\n        if (box.clickedButton() == update_now) {\n            if (trigger_update_action(info, parent, true)) {\n                return;\n            }\n            continue;\n        }\n\n        if (box.clickedButton() == quit_button) {\n            quit_fn_();\n            return;\n        }\n    }\n}\n\n\nvoid Updater::show_optional_update_dialog(const UpdateInfo& info, QWidget* parent)\n{\n    QMessageBox box(parent);\n    box.setIcon(QMessageBox::Information);\n    box.setWindowTitle(QObject::tr(\"Optional Update Available\"));\n    box.setText(QObject::tr(\"An optional update is available. Would you like to update now?\"));\n    QPushButton* update_now = box.addButton(QObject::tr(\"Update Now\"), QMessageBox::AcceptRole);\n    QPushButton* skip_button = box.addButton(QObject::tr(\"Skip This Version\"), QMessageBox::RejectRole);\n    QPushButton* cancel_button = box.addButton(QObject::tr(\"Cancel\"), QMessageBox::DestructiveRole);\n    box.setDefaultButton(update_now);\n    box.exec();\n\n    if (box.clickedButton() == update_now) {\n        trigger_update_action(info, parent, false);\n    } else if (box.clickedButton() == skip_button) {\n        settings.set_skipped_version(info.current_version);\n        if (!settings.save()) {\n            updater_log(spdlog::level::err, \"Failed to save skipped version to settings.\");\n        } else {\n            std::cout << \"User chose to skip version \" << info.current_version << \".\" << std::endl;\n        }\n    } else if (box.clickedButton() == cancel_button) {\n        // No action needed; user dismissed the dialog.\n    }\n}\n\nUpdatePreparationResult Updater::prepare_installer_update(const UpdateInfo& info, QWidget* parent)\n{\n    QProgressDialog progress(parent);\n    progress.setWindowTitle(QObject::tr(\"Downloading Update\"));\n    progress.setLabelText(QObject::tr(\"Downloading the update installer...\"));\n    progress.setCancelButtonText(QObject::tr(\"Cancel\"));\n    progress.setRange(0, 100);\n    progress.setValue(0);\n    progress.setMinimumDuration(0);\n    progress.setWindowModality(Qt::ApplicationModal);\n    progress.show();\n    QApplication::processEvents();\n\n    auto result = installer.prepare(\n        info,\n        [&](double value, const std::string& status) {\n            const double clamped = std::clamp(value, 0.0, 1.0);\n            progress.setValue(static_cast<int>(clamped * 100.0));\n            if (!status.empty()) {\n                progress.setLabelText(QString::fromStdString(status));\n            }\n            QApplication::processEvents();\n        },\n        [&]() {\n            QApplication::processEvents();\n            return progress.wasCanceled();\n        });\n\n    progress.setValue(result.status == UpdatePreparationResult::Status::Ready ? 100 : progress.value());\n    return result;\n}\n\nbool Updater::trigger_update_action(const UpdateInfo& info, QWidget* parent, bool quit_after_open)\n{\n#if defined(_WIN32)\n    if (UpdaterBuildConfig::auto_install_enabled() && installer.supports_auto_install(info)) {\n        const auto prepared = prepare_installer_update(info, parent);\n        if (prepared.status == UpdatePreparationResult::Status::Canceled) {\n            return false;\n        }\n        if (prepared.status == UpdatePreparationResult::Status::Failed) {\n            return handle_update_error(info,\n                                       QObject::tr(\"Failed to prepare the update installer.\\n%1\")\n                                           .arg(QString::fromStdString(prepared.message)),\n                                       parent,\n                                       quit_after_open);\n        }\n\n        QMessageBox confirm(parent);\n        confirm.setIcon(QMessageBox::Question);\n        confirm.setWindowTitle(QObject::tr(\"Installer Ready\"));\n        confirm.setText(QObject::tr(\"Quit the app and launch the installer to update\"));\n        QPushButton* launch_button = confirm.addButton(QObject::tr(\"Quit and Launch Installer\"),\n                                                       QMessageBox::AcceptRole);\n        QPushButton* cancel_button = confirm.addButton(QObject::tr(\"Cancel\"),\n                                                       QMessageBox::RejectRole);\n        confirm.setDefaultButton(launch_button);\n        confirm.exec();\n\n        if (confirm.clickedButton() != launch_button) {\n            return false;\n        }\n\n        if (!installer.launch(prepared.installer_path)) {\n            return handle_update_error(info,\n                                       QObject::tr(\"The installer could not be launched.\"),\n                                       parent,\n                                       quit_after_open);\n        }\n\n        quit_fn_();\n        return true;\n    }\n#endif\n\n    if (info.download_url.empty()) {\n        return handle_update_error(info,\n                                   QObject::tr(\"No download target is available for this update.\"),\n                                   parent,\n                                   quit_after_open);\n    }\n\n    open_download_url_fn_(info.download_url);\n    if (quit_after_open) {\n        quit_fn_();\n    }\n    return true;\n}\n\nbool Updater::handle_update_error(const UpdateInfo& info,\n                                  const QString& message,\n                                  QWidget* parent,\n                                  bool quit_after_open)\n{\n    QMessageBox box(parent);\n    box.setIcon(QMessageBox::Critical);\n    box.setWindowTitle(QObject::tr(\"Update Failed\"));\n    box.setText(message);\n    QPushButton* ok_button = box.addButton(QMessageBox::Ok);\n    QPushButton* manual_button = nullptr;\n    if (!info.download_url.empty()) {\n        manual_button = box.addButton(QObject::tr(\"Update manually\"), QMessageBox::ActionRole);\n    }\n    box.setDefaultButton(ok_button);\n    box.exec();\n\n    if (box.clickedButton() != manual_button) {\n        return false;\n    }\n\n    open_download_url_fn_(info.download_url);\n    if (quit_after_open) {\n        quit_fn_();\n    }\n    return true;\n}\n\n\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    const auto total = size * nmemb;\n    auto* buffer = static_cast<std::string*>(userp);\n    buffer->append(static_cast<const char*>(contents), total);\n    return total;\n}\n\n\nstd::string Updater::fetch_update_metadata() const {\n    if (!update_spec_file_url_) {\n        throw std::runtime_error(\"Environment variable UPDATE_SPEC_FILE_URL is not set\");\n    }\n\n    CURL *curl = curl_easy_init();\n    if (!curl) {\n        throw std::runtime_error(\"Initialization Error: Failed to initialize cURL.\");\n    }\n\n    CURLcode res;\n    std::string response_string;\n\n    try {\n        configure_tls(curl);\n    } catch (const std::exception& ex) {\n        curl_easy_cleanup(curl);\n        throw std::runtime_error(std::string(\"Failed to stage CA bundle: \") + ex.what());\n    }\n\n    curl_easy_setopt(curl, CURLOPT_URL, update_spec_file_url_->c_str());\n    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);\n\n    struct curl_slist *headers = NULL;\n    headers = curl_slist_append(headers, \"Content-Type: application/json\");\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n\n    // Perform the request\n    res = curl_easy_perform(curl);\n\n    // Handle errors\n    if (res != CURLE_OK) {\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n        throw std::runtime_error(\"Network Error: \" + std::string(curl_easy_strerror(res)));\n    }\n\n    // Check HTTP response code\n    long http_code = 0;\n    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);\n\n    curl_slist_free_all(headers);\n    curl_easy_cleanup(curl);\n\n    throw_for_http_status(http_code);\n\n    return response_string;\n}\n\n\nVersion Updater::string_to_Version(const std::string& version_str) {\n    if (version_str.empty()) {\n        return Version{0, 0, 0};\n    }\n\n    std::vector<int> digits;\n    std::istringstream stream(version_str);\n    std::string segment;\n\n    while (std::getline(stream, segment, '.')) {\n        if (segment.empty()) {\n            throw std::runtime_error(\"Invalid version string: \" + version_str);\n        }\n        digits.push_back(std::stoi(segment));\n    }\n\n    if (digits.empty()) {\n        return Version{0, 0, 0};\n    }\n\n    return Version{digits};\n}\n\n\nUpdater::~Updater() = default;\n\n#ifdef AI_FILE_SORTER_TEST_BUILD\nbool UpdaterTestAccess::is_update_available(Updater& updater)\n{\n    return updater.is_update_available();\n}\n\nstd::optional<UpdateInfo> UpdaterTestAccess::current_update_info(const Updater& updater)\n{\n    return updater.update_info;\n}\n\nbool UpdaterTestAccess::has_update_task(const Updater& updater)\n{\n    return updater.update_future.valid();\n}\n\nvoid UpdaterTestAccess::wait_for_update_task(Updater& updater)\n{\n    if (updater.update_future.valid()) {\n        updater.update_future.wait();\n    }\n}\n\nvoid UpdaterTestAccess::set_open_download_url_handler(Updater& updater,\n                                                      std::function<void(const std::string&)> handler)\n{\n    updater.open_download_url_fn_ = std::move(handler);\n}\n\nvoid UpdaterTestAccess::set_quit_handler(Updater& updater,\n                                         std::function<void()> handler)\n{\n    updater.quit_fn_ = std::move(handler);\n}\n\nbool UpdaterTestAccess::trigger_update_action(Updater& updater,\n                                              const UpdateInfo& info,\n                                              QWidget* parent,\n                                              bool quit_after_open)\n{\n    return updater.trigger_update_action(info, parent, quit_after_open);\n}\n\nbool UpdaterTestAccess::handle_update_error(Updater& updater,\n                                            const UpdateInfo& info,\n                                            const QString& message,\n                                            QWidget* parent,\n                                            bool quit_after_open)\n{\n    return updater.handle_update_error(info, message, parent, quit_after_open);\n}\n#endif\n"
  },
  {
    "path": "app/lib/UpdaterLiveTestConfig.cpp",
    "content": "#include \"UpdaterLiveTestConfig.hpp\"\n\n#include \"IniConfig.hpp\"\n#include \"Utils.hpp\"\n\n#include <filesystem>\n#include <optional>\n#include <stdexcept>\n#include <string>\n\nnamespace {\n\nstd::string trim_copy(const std::string& value)\n{\n    const auto begin = value.find_first_not_of(\" \\t\\r\\n\");\n    if (begin == std::string::npos) {\n        return {};\n    }\n    const auto end = value.find_last_not_of(\" \\t\\r\\n\");\n    return value.substr(begin, end - begin + 1);\n}\n\nstd::optional<std::string> read_ini_value(const IniConfig& config,\n                                          const std::string& section,\n                                          const std::initializer_list<const char*>& keys)\n{\n    for (const char* key : keys) {\n        if (!config.hasValue(section, key)) {\n            continue;\n        }\n        const std::string value = trim_copy(config.getValue(section, key));\n        if (!value.empty()) {\n            return value;\n        }\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::string> read_live_test_value(const IniConfig& config,\n                                                const std::initializer_list<const char*>& keys)\n{\n    if (auto value = read_ini_value(config, \"LiveTest\", keys)) {\n        return value;\n    }\n    return read_ini_value(config, \"\", keys);\n}\n\n} // namespace\n\nstd::optional<std::filesystem::path> find_updater_live_test_ini(const std::filesystem::path& executable_path)\n{\n    std::filesystem::path base_dir = executable_path;\n    if (!base_dir.empty()) {\n        if (!base_dir.has_filename() || base_dir.extension().empty()) {\n            // Treat an extensionless path as a directory candidate.\n        } else {\n            base_dir = base_dir.parent_path();\n        }\n    }\n\n    if (base_dir.empty()) {\n        return std::nullopt;\n    }\n\n    const auto candidate = base_dir / \"live-test.ini\";\n    std::error_code ec;\n    if (std::filesystem::exists(candidate, ec) && !ec) {\n        return candidate;\n    }\n    return std::nullopt;\n}\n\nstd::optional<std::filesystem::path> load_missing_values_from_live_test_ini(\n    UpdaterLiveTestConfig& config,\n    const std::filesystem::path& executable_path)\n{\n    if (!config.enabled) {\n        return std::nullopt;\n    }\n\n    const auto ini_path = find_updater_live_test_ini(executable_path);\n    if (!ini_path) {\n        return std::nullopt;\n    }\n\n    IniConfig ini;\n    if (!ini.load(Utils::path_to_utf8(*ini_path))) {\n        throw std::runtime_error(\"Failed to load updater live test file: \" + Utils::path_to_utf8(*ini_path));\n    }\n\n    if (!config.installer_url) {\n        config.installer_url = read_live_test_value(ini, {\"download_url\", \"installer_url\", \"url\"});\n    }\n    if (!config.installer_sha256) {\n        config.installer_sha256 = read_live_test_value(ini, {\"sha256\", \"installer_sha256\"});\n    }\n    if (!config.current_version) {\n        config.current_version = read_live_test_value(ini, {\"current_version\"});\n    }\n    if (!config.min_version) {\n        config.min_version = read_live_test_value(ini, {\"min_version\"});\n    }\n\n    return ini_path;\n}\n"
  },
  {
    "path": "app/lib/Utils.cpp",
    "content": "#include \"Utils.hpp\"\n#include \"Logger.hpp\"\n#include \"TestHooks.hpp\"\n#include <algorithm>\n#include <cstdio>\n#include <cstring>  // for memset\n#include <filesystem>\n#include <iostream>\n#include <memory>\n#include <stdlib.h>\n#include <string>\n#include <system_error>\n#include <vector>\n#include <optional>\n#include <mutex>\n#include <functional>\n#include <QCoreApplication>\n#include <QMetaObject>\n#include <QFile>\n#include <QString>\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/fmt.h>\n\nnamespace {\ntemplate <typename... Args>\nvoid log_core(spdlog::level::level_enum level, const char* fmt, Args&&... args) {\n    auto message = fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);\n    if (auto logger = Logger::get_logger(\"core_logger\")) {\n        logger->log(level, \"{}\", message);\n    } else {\n        std::fprintf(stderr, \"%s\\n\", message.c_str());\n    }\n}\n\nstd::string to_forward_slashes(std::string value) {\n    std::replace(value.begin(), value.end(), '\\\\', '/');\n    return value;\n}\n\nstd::string trim_leading_separators(std::string value) {\n    auto is_separator = [](char ch) {\n        return ch == '/' || ch == '\\\\';\n    };\n    value.erase(value.begin(), std::find_if(value.begin(), value.end(),\n        [&](char ch) { return !is_separator(ch); }));\n    return value;\n}\n\nstd::optional<std::filesystem::path> try_utf8_to_path(const std::string& value) {\n    try {\n        return Utils::utf8_to_path(value);\n    } catch (const std::exception&) {\n        return std::nullopt;\n    }\n}\n\nstd::vector<std::string> collect_user_prefixes() {\n    std::vector<std::string> prefixes;\n\n    auto append = [&](const char* candidate) {\n        if (!candidate || *candidate == '\\0') {\n            return;\n        }\n        const std::string raw(candidate);\n        if (auto converted = try_utf8_to_path(raw)) {\n            prefixes.push_back(to_forward_slashes(Utils::path_to_utf8(*converted)));\n        } else {\n            prefixes.push_back(to_forward_slashes(raw));\n        }\n    };\n\n    append(std::getenv(\"HOME\"));\n    append(std::getenv(\"USERPROFILE\"));\n\n    if (prefixes.empty() && Utils::is_os_windows()) {\n        if (const char* username = std::getenv(\"USERNAME\")) {\n            prefixes.emplace_back(std::string(\"C:/Users/\") + username);\n        }\n    }\n\n    return prefixes;\n}\n\nstd::function<bool()>& cuda_availability_probe() {\n    static std::function<bool()> probe;\n    return probe;\n}\n\nstd::function<std::optional<Utils::CudaMemoryInfo>()>& cuda_memory_probe() {\n    static std::function<std::optional<Utils::CudaMemoryInfo>()> probe;\n    return probe;\n}\n\nstd::optional<std::string> strip_prefix(const std::string& path,\n                                        const std::vector<std::string>& prefixes) {\n    for (const auto& original_prefix : prefixes) {\n        if (original_prefix.empty()) {\n            continue;\n        }\n        std::string prefix = original_prefix;\n        if (prefix.back() != '/') {\n            prefix.push_back('/');\n        }\n        if (path.size() < prefix.size()) {\n            continue;\n        }\n        if (!std::equal(prefix.begin(), prefix.end(), path.begin())) {\n            continue;\n        }\n\n        std::string trimmed = trim_leading_separators(path.substr(prefix.size()));\n        if (!trimmed.empty()) {\n            return trimmed;\n        }\n    }\n\n    return std::nullopt;\n}\n}\n#ifdef _WIN32\n    #include <windows.h>\n    #include <wininet.h>\n#elif __linux__\n    #include <dlfcn.h>\n    #include <limits.h>\n    #include <unistd.h>\n    #include <netdb.h>\n    #include <sys/socket.h>\n#elif __APPLE__\n    #include <dlfcn.h>\n    #include <mach-o/dyld.h>\n    #include <limits.h>\n    #include <netdb.h>\n    #include <sys/socket.h>\n#endif\n#include <iostream>\n#include <Types.hpp>\n#include <cstddef>\n#include <stdexcept>\n#ifdef _WIN32\n    #include <appmodel.h>\n    #include <cwchar>\n#endif\n\n// Shortcuts for loading libraries on different OSes\n#ifdef _WIN32\n    using LibraryHandle = HMODULE;\n\n    LibraryHandle loadLibrary(const char* name) {\n        return LoadLibraryA(name);\n    }\n\n    void* getSymbol(LibraryHandle lib, const char* symbol) {\n        return reinterpret_cast<void*>(GetProcAddress(lib, symbol));\n    }\n\n    void closeLibrary(LibraryHandle lib) {\n        FreeLibrary(lib);\n    }\n#else\n    using LibraryHandle = void*;\n\n    LibraryHandle loadLibrary(const char* name) {\n        return dlopen(name, RTLD_LAZY);\n    }\n\n    void* getSymbol(LibraryHandle lib, const char* symbol) {\n        return dlsym(lib, symbol);\n    }\n\n    void closeLibrary(LibraryHandle lib) {\n        dlclose(lib);\n    }\n#endif\n\n\nbool Utils::is_network_available()\n{\n#ifdef _WIN32\n    DWORD flags;\n    return InternetGetConnectedState(&flags, 0);\n#else\n    addrinfo hints{};\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n    addrinfo* result = nullptr;\n    const int rc = getaddrinfo(\"www.google.com\", \"80\", &hints, &result);\n    if (result) {\n        freeaddrinfo(result);\n    }\n    return rc == 0;\n#endif\n}\n\n\nstd::string Utils::get_executable_path()\n{\n#ifdef _WIN32\n    char result[MAX_PATH];\n    GetModuleFileNameA(NULL, result, MAX_PATH);\n    return std::string(result);\n#elif __linux__\n    char result[PATH_MAX];\n    ssize_t count = readlink(\"/proc/self/exe\", result, PATH_MAX);\n    return (count != -1) ? std::string(result, count) : \"\";\n#elif __APPLE__\n    char result[PATH_MAX];\n    uint32_t size = sizeof(result);\n    if (_NSGetExecutablePath(result, &size) == 0) {\n        return std::string(result);\n    } else {\n        throw std::runtime_error(\"Path buffer too small\");\n    }\n#else\n    throw std::runtime_error(\"Unsupported platform\");\n#endif\n}\n\n\nstd::filesystem::path Utils::ensure_ca_bundle() {\n    static std::once_flag init_flag;\n    static std::filesystem::path cached_path;\n    static std::exception_ptr init_error;\n\n    std::call_once(init_flag, []() {\n        try {\n            std::filesystem::path exe_path = std::filesystem::path(get_executable_path());\n            std::filesystem::path cert_dir = exe_path.parent_path() / \"certs\";\n            std::filesystem::path cert_file = cert_dir / \"cacert.pem\";\n\n            bool needs_write = true;\n            if (std::filesystem::exists(cert_file)) {\n                std::error_code ec;\n                auto size = std::filesystem::file_size(cert_file, ec);\n                needs_write = ec ? true : (size == 0);\n            }\n\n            if (needs_write) {\n                ensure_directory_exists(cert_dir.string());\n\n                QFile resource(QStringLiteral(\":/net/quicknode/AIFileSorter/certs/cacert.pem\"));\n                if (!resource.open(QIODevice::ReadOnly)) {\n                    throw std::runtime_error(\"Failed to open embedded CA bundle resource\");\n                }\n                const QByteArray data = resource.readAll();\n                resource.close();\n\n                QFile output(QString::fromStdString(cert_file.string()));\n                if (!output.open(QIODevice::WriteOnly | QIODevice::Truncate)) {\n                    throw std::runtime_error(\"Failed to create CA bundle file at \" + cert_file.string());\n                }\n                if (output.write(data) != data.size()) {\n                    output.close();\n                    throw std::runtime_error(\"Failed to write CA bundle file at \" + cert_file.string());\n                }\n                output.close();\n            }\n\n            cached_path = cert_file;\n        } catch (...) {\n            init_error = std::current_exception();\n        }\n    });\n\n    if (init_error) {\n        std::rethrow_exception(init_error);\n    }\n\n    return cached_path;\n}\n\n\nstd::string Utils::path_to_utf8(const std::filesystem::path& path) {\n#ifdef _WIN32\n    if (path.empty()) {\n        return {};\n    }\n\n    const std::wstring native = path.native();\n    if (native.empty()) {\n        return {};\n    }\n\n    const int required = WideCharToMultiByte(\n        CP_UTF8, 0, native.c_str(), -1, nullptr, 0, nullptr, nullptr);\n    if (required <= 0) {\n        throw std::system_error(\n            std::error_code(GetLastError(), std::system_category()),\n            \"WideCharToMultiByte failed while converting path to UTF-8\");\n    }\n\n    std::string buffer(static_cast<std::size_t>(required - 1), '\\0');\n    const int written = WideCharToMultiByte(\n        CP_UTF8, 0, native.c_str(), -1, buffer.data(), required, nullptr, nullptr);\n    if (written <= 0) {\n        throw std::system_error(\n            std::error_code(GetLastError(), std::system_category()),\n            \"WideCharToMultiByte failed while converting path to UTF-8\");\n    }\n\n    buffer.resize(static_cast<std::size_t>(written - 1));\n    return buffer;\n#else\n    return path.generic_string();\n#endif\n}\n\n\nstd::filesystem::path Utils::utf8_to_path(const std::string& utf8_path) {\n#ifdef _WIN32\n    if (utf8_path.empty()) {\n        return {};\n    }\n\n    const int required = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS, utf8_path.c_str(), -1, nullptr, 0);\n    if (required <= 0) {\n        throw std::system_error(\n            std::error_code(GetLastError(), std::system_category()),\n            \"MultiByteToWideChar failed while converting UTF-8 to path\");\n    }\n\n    std::wstring buffer(static_cast<std::size_t>(required - 1), L'\\0');\n    const int written = MultiByteToWideChar(\n        CP_UTF8, MB_ERR_INVALID_CHARS, utf8_path.c_str(), -1, buffer.data(), required);\n    if (written <= 0) {\n        throw std::system_error(\n            std::error_code(GetLastError(), std::system_category()),\n            \"MultiByteToWideChar failed while converting UTF-8 to path\");\n    }\n\n    buffer.resize(static_cast<std::size_t>(written - 1));\n    return std::filesystem::path(buffer);\n#else\n    return std::filesystem::path(utf8_path);\n#endif\n}\n\n\nbool Utils::is_valid_directory(const char *path)\n{\n    if (!path || *path == '\\0') {\n        return false;\n    }\n#ifdef _WIN32\n    std::filesystem::path fs_path;\n    try {\n        fs_path = utf8_to_path(path);\n    } catch (const std::exception&) {\n        return false;\n    }\n#else\n    std::filesystem::path fs_path(path);\n#endif\n\n    std::error_code ec;\n    return std::filesystem::is_directory(fs_path, ec);\n}\n\nnamespace {\nint hex_char_value(char c)\n{\n    if (c >= '0' && c <= '9') {\n        return c - '0';\n    }\n    if (c >= 'a' && c <= 'f') {\n        return 10 + (c - 'a');\n    }\n    if (c >= 'A' && c <= 'F') {\n        return 10 + (c - 'A');\n    }\n    return -1;\n}\n\nunsigned char combine_hex_pair(char high, char low)\n{\n    const int hi = hex_char_value(high);\n    const int lo = hex_char_value(low);\n    if (hi < 0 || lo < 0) {\n        throw std::invalid_argument(\"Hex string contains invalid characters\");\n    }\n    return static_cast<unsigned char>((hi << 4) | lo);\n}\n}\n\n\nstd::vector<unsigned char> Utils::hex_to_vector(const std::string& hex) {\n    if (hex.size() % 2 != 0) {\n        throw std::invalid_argument(\"Hex string must have even length\");\n    }\n\n    std::vector<unsigned char> data;\n    data.reserve(hex.size() / 2);\n\n    for (std::size_t i = 0; i < hex.size(); i += 2) {\n        data.push_back(combine_hex_pair(hex[i], hex[i + 1]));\n    }\n\n    return data;\n}\n\n\nconst char* Utils::to_cstr(const std::u8string& u8str) {\n    return reinterpret_cast<const char*>(u8str.c_str());\n}\n\n\nvoid Utils::ensure_directory_exists(const std::string &dir)\n{\n    try {\n        if (!std::filesystem::exists(dir)) {\n            std::filesystem::create_directories(dir);\n        }\n    } catch (const std::exception &e) {\n        log_core(spdlog::level::err, \"Error creating log directory: {}\", e.what());\n        throw;\n    }\n}\n\n\nbool Utils::is_os_windows() {\n#if defined(_WIN32)\n    return true;\n#else\n    return false;\n#endif\n}\n\n    \nbool Utils::is_os_macos() {\n#if defined(__APPLE__)\n    return true;\n#else\n    return false;\n#endif\n}\n\n    \nbool Utils::is_os_linux() {\n#if defined(__linux__)\n    return true;\n#else\n    return false;\n#endif\n}\n\n\nstd::string Utils::format_size(curl_off_t bytes)\n{\n    char buffer[64];\n    if (bytes >= (1LL << 30))\n        snprintf(buffer, sizeof(buffer), \"%.2f GB\",\n                 bytes / (double)(1LL << 30));\n    else if (bytes >= (1LL << 20))\n        snprintf(buffer, sizeof(buffer), \"%.2f MB\", bytes / (double)(1LL << 20));\n    else if (bytes >= (1LL << 10))\n        snprintf(buffer, sizeof(buffer), \"%.2f KB\", bytes / (double)(1LL << 10));\n    else\n        snprintf(buffer, sizeof(buffer), \"%.2f B\", bytes / (double)(1LL << 10));\n    return buffer;\n}\n\n\nint Utils::get_ngl(int vram_mb) {\n    if (vram_mb < 2048) return 0;\n\n    int step = (vram_mb - 2048) / 512;\n    return std::min(14 + step * 2, 32);\n}\n\n\nstd::optional<Utils::CudaMemoryInfo> Utils::query_cuda_memory() {\n    if (auto& probe = cuda_memory_probe()) {\n        return probe();\n    }\n#ifdef _WIN32\n    std::string dllName = get_cudart_dll_name();\n    LibraryHandle lib = loadLibrary(dllName.c_str());\n#else\n    LibraryHandle lib = loadLibrary(\"libcudart.so\");\n    if (!lib) {\n        lib = loadLibrary(\"libcudart.so.12\");\n    }\n#endif\n\n    if (!lib) {\n        log_core(spdlog::level::err, \"Failed to load CUDA runtime library.\");\n        return std::nullopt;\n    }\n\n    using cudaMemGetInfo_t = int (*)(size_t*, size_t*);\n    using cudaGetDeviceProperties_t = int (*)(void*, int);\n\n    auto cudaMemGetInfo = reinterpret_cast<cudaMemGetInfo_t>(getSymbol(lib, \"cudaMemGetInfo\"));\n    auto cudaGetDeviceProperties = reinterpret_cast<cudaGetDeviceProperties_t>(getSymbol(lib, \"cudaGetDeviceProperties\"));\n\n    if (!cudaMemGetInfo) {\n        log_core(spdlog::level::err, \"Failed to resolve required CUDA runtime symbols.\");\n        closeLibrary(lib);\n        return std::nullopt;\n    }\n\n    size_t free_bytes = 0;\n    size_t total_bytes = 0;\n    size_t device_total_bytes = 0;\n\n    if (cudaMemGetInfo(&free_bytes, &total_bytes) != 0) {\n        log_core(spdlog::level::warn, \"Warning: cudaMemGetInfo failed\");\n        free_bytes = 0;\n        total_bytes = 0;\n    }\n\n    if (cudaGetDeviceProperties) {\n        // Query total device memory from cudaGetDeviceProperties for reference.\n        constexpr size_t cudaDevicePropSize = 2560;\n        alignas(std::max_align_t) uint8_t prop_buffer[cudaDevicePropSize];\n        std::memset(prop_buffer, 0, sizeof(prop_buffer));\n        if (cudaGetDeviceProperties(prop_buffer, 0) == 0) {\n            struct DevicePropShim {\n                char name[256];\n                size_t totalGlobalMem;\n            };\n            auto *prop = reinterpret_cast<DevicePropShim*>(prop_buffer);\n            device_total_bytes = prop->totalGlobalMem;\n            constexpr size_t kMinReasonableBytes = 64ULL * 1024ULL * 1024ULL;\n            constexpr size_t kMaxReasonableBytes = 1ULL << 50; // 1 PiB\n            if (device_total_bytes < kMinReasonableBytes ||\n                device_total_bytes > kMaxReasonableBytes) {\n                device_total_bytes = 0;\n            }\n        }\n    }\n\n    if (total_bytes == 0 && device_total_bytes != 0) {\n        total_bytes = device_total_bytes;\n    }\n\n    closeLibrary(lib);\n\n    if (free_bytes == 0 && total_bytes == 0) {\n        log_core(spdlog::level::warn, \"CUDA memory metrics unavailable (both free and total bytes are zero).\");\n        return std::nullopt;\n    }\n\n    CudaMemoryInfo info;\n    info.free_bytes = free_bytes;\n    info.total_bytes = total_bytes;\n    info.device_total_bytes = device_total_bytes;\n    return info;\n}\n\n\nint Utils::compute_ngl_from_cuda_memory(const CudaMemoryInfo& info) {\n    size_t usable_bytes = (info.free_bytes > 0) ? info.free_bytes : info.total_bytes;\n    if (usable_bytes == 0) {\n        return 0;\n    }\n    int vram_mb = static_cast<int>(usable_bytes / (1024 * 1024));\n    return get_ngl(vram_mb);\n}\n\n\nint Utils::determine_ngl_cuda() {\n    auto info = query_cuda_memory();\n    if (!info.has_value()) {\n        return 0;\n    }\n\n    return compute_ngl_from_cuda_memory(*info);\n}\n\n\n#ifdef _WIN32\nstd::optional<std::filesystem::path> packaged_llm_path()\n{\n    // Detect MSIX/packaged context and build LocalCache path that is removed on uninstall.\n    UINT32 length = 0;\n    LONG rc = GetCurrentPackageFamilyName(&length, nullptr);\n    if (rc == APPMODEL_ERROR_NO_PACKAGE) {\n        return std::nullopt; // not packaged\n    }\n    if (rc != ERROR_INSUFFICIENT_BUFFER) {\n        return std::nullopt;\n    }\n\n    std::wstring family;\n    family.resize(length);\n    rc = GetCurrentPackageFamilyName(&length, family.data());\n    if (rc != ERROR_SUCCESS) {\n        return std::nullopt;\n    }\n    if (length > 0 && family[length - 1] == L'\\0') {\n        family.resize(length - 1);\n    }\n\n    const wchar_t* localAppData = _wgetenv(L\"LOCALAPPDATA\");\n    if (!localAppData || *localAppData == L'\\0') {\n        return std::nullopt;\n    }\n\n    std::filesystem::path base(localAppData);\n    return base / L\"Packages\" / std::filesystem::path(family) / L\"LocalCache\" / L\"aifilesorter\" / L\"llms\";\n}\n#endif\n\ntemplate <typename Func>\nvoid Utils::run_on_main_thread(Func&& func)\n{\n    auto task = std::make_shared<std::function<void()>>(std::forward<Func>(func));\n    if (auto* app = QCoreApplication::instance()) {\n        QMetaObject::invokeMethod(app, [task]() { (*task)(); }, Qt::QueuedConnection);\n    } else {\n        (*task)();\n    }\n}\n\n\nstd::string Utils::get_default_llm_destination()\n{\n    const char* home = std::getenv(\"HOME\");\n\n    if (Utils::is_os_windows()) {\n        const char* appdata = std::getenv(\"APPDATA\");\n        if (!appdata) throw std::runtime_error(\"APPDATA not set\");\n        std::filesystem::path legacy = std::filesystem::path(appdata) / \"aifilesorter\" / \"llms\";\n\n#ifdef _WIN32\n        if (auto packaged = packaged_llm_path()) {\n            // Prefer the packaged LocalCache path; fall back to legacy if it already exists (backward compatibility).\n            if (std::filesystem::exists(legacy)) {\n                return legacy.string();\n            }\n            return packaged->string();\n        }\n#endif\n        return legacy.string();\n    }\n\n    if (!home) throw std::runtime_error(\"HOME not set\");\n\n    if (Utils::is_os_macos()) {\n        return (std::filesystem::path(home) / \"Library\" / \"Application Support\" / \"aifilesorter\" / \"llms\").string();\n    }\n\n    return (std::filesystem::path(home) / \".local\" / \"share\" / \"aifilesorter\" / \"llms\").string();\n}\n\n\nstd::string Utils::get_file_name_from_url(std::string url)\n{\n    auto last_slash = url.find_last_of('/');\n    if (last_slash == std::string::npos || last_slash == url.length() - 1) {\n        throw std::runtime_error(\"Invalid download URL: can't extract filename\");\n    }\n    std::string filename = url.substr(last_slash + 1);\n\n    return filename;\n}\n\n\nstd::string Utils::make_default_path_to_file_from_download_url(std::string url)\n{\n    std::string filename = get_file_name_from_url(url);\n    std::string path_to_file = (std::filesystem::path(get_default_llm_destination()) / filename).string();\n    return path_to_file;\n}\n\n\nnamespace {\nusing cudaGetDeviceCount_t = int (*)(int*);\nusing cudaSetDevice_t = int (*)(int);\nusing cudaMemGetInfo_t = int (*)(size_t*, size_t*);\n\nLibraryHandle open_cuda_runtime() {\n#ifdef _WIN32\n    std::string dllName = Utils::get_cudart_dll_name();\n    if (dllName.empty()) {\n        log_core(spdlog::level::warn, \"[CUDA] DLL name is empty — likely failed to get CUDA version.\");\n        return nullptr;\n    }\n    LibraryHandle handle = loadLibrary(dllName.c_str());\n    log_core(spdlog::level::info, \"[CUDA] Trying to load: {} => {}\", dllName, handle ? \"Success\" : \"Failure\");\n    return handle;\n#else\n    return loadLibrary(\"libcudart.so\");\n#endif\n}\n\nbool resolve_cuda_symbols(LibraryHandle handle,\n                          cudaGetDeviceCount_t& get_device_count,\n                          cudaSetDevice_t& set_device,\n                          cudaMemGetInfo_t& mem_get_info) {\n    get_device_count = reinterpret_cast<cudaGetDeviceCount_t>(getSymbol(handle, \"cudaGetDeviceCount\"));\n    set_device = reinterpret_cast<cudaSetDevice_t>(getSymbol(handle, \"cudaSetDevice\"));\n    mem_get_info = reinterpret_cast<cudaMemGetInfo_t>(getSymbol(handle, \"cudaMemGetInfo\"));\n\n    log_core(spdlog::level::info, \"[CUDA] Lookup cudaGetDeviceCount symbol: {}\",\n             get_device_count ? \"Found\" : \"Not Found\");\n\n    return get_device_count && set_device && mem_get_info;\n}\n} // namespace\n\nbool Utils::is_cuda_available() {\n    log_core(spdlog::level::info, \"[CUDA] Checking CUDA availability...\");\n\n    if (auto& probe = cuda_availability_probe()) {\n        return probe();\n    }\n\n    LibraryHandle handle = open_cuda_runtime();\n    if (!handle) {\n        log_core(spdlog::level::warn, \"[CUDA] Failed to load CUDA runtime library.\");\n        return false;\n    }\n\n    cudaGetDeviceCount_t cudaGetDeviceCount = nullptr;\n    cudaSetDevice_t cudaSetDevice = nullptr;\n    cudaMemGetInfo_t cudaMemGetInfo = nullptr;\n    if (!resolve_cuda_symbols(handle, cudaGetDeviceCount, cudaSetDevice, cudaMemGetInfo)) {\n        closeLibrary(handle);\n        return false;\n    }\n\n    int count = 0;\n    int status = cudaGetDeviceCount(&count);\n    log_core(spdlog::level::info, \"[CUDA] cudaGetDeviceCount returned status: {}, device count: {}\", status, count);\n\n    if (status != 0 || count == 0) {\n        log_core(spdlog::level::warn,\n                 status != 0 ? \"[CUDA] CUDA error: {} from cudaGetDeviceCount\" : \"[CUDA] No CUDA devices found\",\n                 status);\n        closeLibrary(handle);\n        return false;\n    }\n\n    if (int set_status = cudaSetDevice(0); set_status != 0) {\n        log_core(spdlog::level::warn, \"[CUDA] Failed to set CUDA device 0 (error {})\", set_status);\n        closeLibrary(handle);\n        return false;\n    }\n\n    size_t free_bytes = 0;\n    size_t total_bytes = 0;\n    if (int mem_status = cudaMemGetInfo(&free_bytes, &total_bytes); mem_status != 0) {\n        log_core(spdlog::level::warn, \"[CUDA] cudaMemGetInfo failed (error {})\", mem_status);\n        closeLibrary(handle);\n        return false;\n    }\n\n    log_core(spdlog::level::info, \"[CUDA] CUDA is available and {} device(s) found.\", count);\n    closeLibrary(handle);\n    return true;\n}\n\nnamespace TestHooks {\n\nvoid set_cuda_availability_probe(CudaAvailabilityProbe probe) {\n    cuda_availability_probe() = std::move(probe);\n}\n\nvoid reset_cuda_availability_probe() {\n    cuda_availability_probe() = CudaAvailabilityProbe{};\n}\n\nvoid set_cuda_memory_probe(CudaMemoryProbe probe) {\n    cuda_memory_probe() = std::move(probe);\n}\n\nvoid reset_cuda_memory_probe() {\n    cuda_memory_probe() = CudaMemoryProbe{};\n}\n\n} // namespace TestHooks\n\n#ifdef _WIN32\nint Utils::get_installed_cuda_runtime_version()\n{\n    HMODULE hCuda = LoadLibraryA(\"nvcuda.dll\");\n    if (!hCuda) {\n        log_core(spdlog::level::warn, \"Failed to load nvcuda.dll\");\n        return 0;\n    }\n\n    using cudaDriverGetVersion_t = int(__cdecl *)(int*);\n    auto cudaDriverGetVersion = reinterpret_cast<cudaDriverGetVersion_t>(\n        GetProcAddress(hCuda, \"cuDriverGetVersion\")\n    );\n\n    if (!cudaDriverGetVersion) {\n        log_core(spdlog::level::warn, \"Failed to get cuDriverGetVersion symbol\");\n        FreeLibrary(hCuda);\n        return 0;\n    }\n\n    int version = 0;\n    if (cudaDriverGetVersion(&version) != 0) {\n        log_core(spdlog::level::warn, \"cuDriverGetVersion call failed\");\n        FreeLibrary(hCuda);\n        return 0;\n    }\n\n    log_core(spdlog::level::info, \"[CUDA] Detected CUDA driver version: {}\", version);\n\n    FreeLibrary(hCuda);\n    return version;\n}\n#endif\n\n\n#ifdef _WIN32\nstd::string Utils::get_cudart_dll_name() {\n    int version = get_installed_cuda_runtime_version();\n    std::vector<int> candidates;\n\n    if (version > 0) {\n        int suggested = version / 1000;\n        if (suggested > 0) {\n            candidates.push_back(suggested);\n        }\n    }\n\n    // probe the most common recent runtimes (highest first)\n    for (int v = 15; v >= 10; --v) {\n        if (std::find(candidates.begin(), candidates.end(), v) == candidates.end()) {\n            candidates.push_back(v);\n        }\n    }\n\n    for (int major : candidates) {\n        char buffer[32];\n        std::snprintf(buffer, sizeof(buffer), \"cudart64_%d.dll\", major);\n        HMODULE h = LoadLibraryA(buffer);\n        if (h) {\n            FreeLibrary(h);\n            log_core(spdlog::level::info, \"[CUDA] Selected runtime DLL: {}\", buffer);\n            return buffer;\n        }\n    }\n\n    log_core(spdlog::level::warn, \"[CUDA] Unable to locate a compatible cudart64_XX.dll\");\n    return \"\";\n}\n#endif\n\n\nstd::string Utils::abbreviate_user_path(const std::string& path) {\n    if (path.empty()) {\n        return \"\";\n    }\n\n    const auto fs_path = try_utf8_to_path(path);\n    if (!fs_path) {\n        return trim_leading_separators(to_forward_slashes(path));\n    }\n\n    const std::filesystem::path normalized = fs_path->lexically_normal();\n    const std::string generic_path = to_forward_slashes(Utils::path_to_utf8(normalized));\n\n    const std::vector<std::string> prefixes = collect_user_prefixes();\n    if (auto trimmed = strip_prefix(generic_path, prefixes)) {\n        return *trimmed;\n    }\n\n    const std::string sanitized = trim_leading_separators(generic_path);\n    if (!sanitized.empty()) {\n        return sanitized;\n    }\n\n    return to_forward_slashes(Utils::path_to_utf8(normalized.filename()));\n}\n\nnamespace {\nstd::string trim_ws(const std::string& value) {\n    const char* whitespace = \" \\t\\n\\r\\f\\v\";\n    const auto start = value.find_first_not_of(whitespace);\n    const auto end = value.find_last_not_of(whitespace);\n    if (start == std::string::npos || end == std::string::npos) {\n        return std::string();\n    }\n    return value.substr(start, end - start + 1);\n}\n}\n\nstd::string Utils::sanitize_path_label(const std::string& value) {\n    const std::string invalid = R\"(<>:\"/\\|?*)\";\n    QString normalized = QString::fromUtf8(value.c_str());\n    normalized.remove(QChar::ReplacementCharacter);\n    const QByteArray normalized_utf8 = normalized.normalized(QString::NormalizationForm_C).toUtf8();\n    const std::string utf8_value(normalized_utf8.constData(),\n                                 static_cast<std::size_t>(normalized_utf8.size()));\n    std::string cleaned;\n    cleaned.reserve(utf8_value.size());\n\n    // Replace invalid path characters and control chars with spaces.\n    for (unsigned char ch : utf8_value) {\n        if (std::iscntrl(ch)) {\n            continue;\n        }\n        if (invalid.find(static_cast<char>(ch)) != std::string::npos) {\n            cleaned.push_back(' ');\n        } else {\n            cleaned.push_back(static_cast<char>(ch));\n        }\n    }\n\n    // Collapse multiple spaces.\n    std::string collapsed;\n    collapsed.reserve(cleaned.size());\n    bool prev_space = false;\n    for (char ch : cleaned) {\n        const bool is_space = std::isspace(static_cast<unsigned char>(ch));\n        if (is_space) {\n            if (!prev_space) {\n                collapsed.push_back(' ');\n            }\n        } else {\n            collapsed.push_back(ch);\n        }\n        prev_space = is_space;\n    }\n\n    // Trim and drop trailing dots/spaces (Windows safety).\n    std::string trimmed = trim_ws(collapsed);\n    while (!trimmed.empty() && (trimmed.back() == '.' || std::isspace(static_cast<unsigned char>(trimmed.back())))) {\n        trimmed.pop_back();\n    }\n\n    return trim_ws(trimmed);\n}\n"
  },
  {
    "path": "app/lib/Version.cpp",
    "content": "#include \"Version.hpp\"\n#include <algorithm>\n#include <sstream>\n#include <string>\n\n\nVersion::Version(std::initializer_list<int> version_digits)\n    : digits(version_digits) {}\n\n\nVersion::Version(const std::vector<int>& version_digits)\n    : digits(version_digits) {}\n\n\nbool Version::operator>=(const Version& other) const {\n    for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) {\n        int lhs = (i < digits.size()) ? digits[i] : 0;\n        int rhs = (i < other.digits.size()) ? other.digits[i] : 0;\n\n        if (lhs > rhs) return true;\n        if (lhs < rhs) return false;\n    }\n    return true;\n}\n\n\nbool Version::operator>(const Version& other) const\n{\n    for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) {\n        int lhs = (i < digits.size()) ? digits[i] : 0;\n        int rhs = (i < other.digits.size()) ? other.digits[i] : 0;\n\n        if (lhs > rhs) return true;\n        if (lhs < rhs) return false;\n    }\n    return false;\n}\n\n\nbool Version::operator<=(const Version& other) const\n{\n    for (size_t i = 0; i < std::max(digits.size(), other.digits.size()); ++i) {\n        int lhs = (i < digits.size()) ? digits[i] : 0;\n        int rhs = (i < other.digits.size()) ? other.digits[i] : 0;\n\n        if (lhs > rhs) return false;\n        if (lhs < rhs) return true;\n    }\n    return true;\n}\n\n\nstd::string Version::to_string() const\n{\n    if (digits.empty()) return \"0\";\n    std::ostringstream oss;\n    for (size_t i = 0; i < digits.size(); ++i) {\n        if (i > 0) oss << '.';\n        oss << digits[i];\n    }\n    return oss.str();\n}"
  },
  {
    "path": "app/lib/WhitelistManagerDialog.cpp",
    "content": "#include \"WhitelistManagerDialog.hpp\"\n\n#include <QListWidget>\n#include <QPushButton>\n#include <QVBoxLayout>\n#include <QHBoxLayout>\n#include <QDialogButtonBox>\n#include <QInputDialog>\n#include <QMessageBox>\n#include <QLabel>\n#include <QTextEdit>\n#include <QLineEdit>\n#include <QAbstractItemView>\n\nnamespace {\nQString join_lines(const std::vector<std::string>& items) {\n    QStringList list;\n    for (const auto& i : items) {\n        list << QString::fromStdString(i);\n    }\n    return list.join(\", \");\n}\n\nstd::vector<std::string> split_lines(const QString& text) {\n    std::vector<std::string> items;\n    for (const auto& part : text.split(\",\")) {\n        const QString trimmed = part.trimmed();\n        if (!trimmed.isEmpty()) {\n            items.emplace_back(trimmed.toStdString());\n        }\n    }\n    return items;\n}\n\nstruct EditDialogResult {\n    QString name;\n    std::vector<std::string> categories;\n    std::vector<std::string> subcategories;\n};\n\nstd::optional<EditDialogResult> show_edit_dialog(QWidget* parent,\n                                                 const QString& initial_name,\n                                                 const WhitelistEntry& entry)\n{\n    QDialog dialog(parent);\n    dialog.setWindowTitle(QObject::tr(\"Edit whitelist\"));\n    auto* layout = new QVBoxLayout(&dialog);\n\n    auto* name_edit = new QLineEdit(&dialog);\n    name_edit->setText(initial_name);\n    layout->addWidget(new QLabel(QObject::tr(\"Name:\"), &dialog));\n    layout->addWidget(name_edit);\n\n    auto* cats_edit = new QTextEdit(&dialog);\n    cats_edit->setPlainText(join_lines(entry.categories));\n    layout->addWidget(new QLabel(QObject::tr(\"Categories (comma separated):\"), &dialog));\n    layout->addWidget(cats_edit);\n\n    auto* subs_edit = new QTextEdit(&dialog);\n    subs_edit->setPlainText(join_lines(entry.subcategories));\n    layout->addWidget(new QLabel(QObject::tr(\"Subcategories (comma separated):\"), &dialog));\n    layout->addWidget(subs_edit);\n\n    auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);\n    layout->addWidget(buttons);\n    QObject::connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);\n    QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);\n\n    if (dialog.exec() != QDialog::Accepted) {\n        return std::nullopt;\n    }\n\n    EditDialogResult result;\n    result.name = name_edit->text().trimmed();\n    if (result.name.isEmpty()) {\n        return std::nullopt;\n    }\n    result.categories = split_lines(cats_edit->toPlainText());\n    result.subcategories = split_lines(subs_edit->toPlainText());\n    return result;\n}\n}\n\nWhitelistManagerDialog::WhitelistManagerDialog(WhitelistStore& store, QWidget* parent)\n    : QDialog(parent), store_(store)\n{\n    setWindowTitle(tr(\"Category whitelists\"));\n    auto* layout = new QVBoxLayout(this);\n\n    list_widget_ = new QListWidget(this);\n    layout->addWidget(list_widget_);\n\n    auto* button_row = new QHBoxLayout();\n    add_button_ = new QPushButton(tr(\"Add\"), this);\n    edit_button_ = new QPushButton(tr(\"Edit\"), this);\n    remove_button_ = new QPushButton(tr(\"Remove\"), this);\n    button_row->addWidget(add_button_);\n    button_row->addWidget(edit_button_);\n    button_row->addWidget(remove_button_);\n    button_row->addStretch();\n    layout->addLayout(button_row);\n\n    auto* close_box = new QDialogButtonBox(QDialogButtonBox::Close, this);\n    layout->addWidget(close_box);\n\n    connect(add_button_, &QPushButton::clicked, this, [this]() { on_add_clicked(); });\n    connect(edit_button_, &QPushButton::clicked, this, [this]() { on_edit_clicked(); });\n    connect(remove_button_, &QPushButton::clicked, this, [this]() { on_remove_clicked(); });\n    connect(list_widget_, &QListWidget::currentRowChanged, this, [this](int row) { on_selection_changed(row); });\n    connect(close_box, &QDialogButtonBox::rejected, this, &QDialog::reject);\n\n    refresh_list();\n}\n\nvoid WhitelistManagerDialog::refresh_list()\n{\n    if (!list_widget_) return;\n    if (store_.empty()) {\n        store_.ensure_default_from_legacy({}, {});\n        store_.save();\n    }\n    list_widget_->clear();\n    for (const auto& name : store_.list_names()) {\n        auto* item = new QListWidgetItem(QString::fromStdString(name));\n        item->setData(Qt::UserRole, QString::fromStdString(name));\n        list_widget_->addItem(item);\n    }\n    on_selection_changed(list_widget_->currentRow());\n}\n\nbool WhitelistManagerDialog::edit_entry(const QString& name, WhitelistEntry& entry)\n{\n    auto result = show_edit_dialog(this, name, entry);\n    if (!result.has_value()) {\n        return false;\n    }\n\n    store_.remove(name.toStdString());\n    store_.set(result->name.toStdString(), WhitelistEntry{result->categories, result->subcategories});\n    store_.save();\n    refresh_list();\n    notify_changed();\n    return true;\n}\n\nvoid WhitelistManagerDialog::on_add_clicked()\n{\n    WhitelistEntry entry;\n    edit_entry(QString(), entry);\n}\n\nvoid WhitelistManagerDialog::on_edit_clicked()\n{\n    if (!list_widget_) return;\n    auto* item = list_widget_->currentItem();\n    if (!item) return;\n    const QString name = item->text();\n    if (auto existing = store_.get(name.toStdString())) {\n        edit_entry(name, *existing);\n    }\n}\n\nvoid WhitelistManagerDialog::on_remove_clicked()\n{\n    if (!list_widget_) return;\n    auto* item = list_widget_->currentItem();\n    if (!item) return;\n    const QString name = item->text();\n    if (name == QString::fromStdString(store_.default_name())) {\n        QMessageBox::warning(this, tr(\"Cannot remove\"), tr(\"The default list cannot be removed.\"));\n        return;\n    }\n    store_.remove(name.toStdString());\n    store_.save();\n    refresh_list();\n    notify_changed();\n}\n\nvoid WhitelistManagerDialog::on_selection_changed(int row)\n{\n    const bool has_selection = row >= 0;\n    edit_button_->setEnabled(has_selection);\n    remove_button_->setEnabled(has_selection);\n}\n\nvoid WhitelistManagerDialog::notify_changed()\n{\n    if (on_lists_changed_) {\n        on_lists_changed_();\n    }\n}\n"
  },
  {
    "path": "app/lib/WhitelistStore.cpp",
    "content": "#include \"WhitelistStore.hpp\"\n#include \"Logger.hpp\"\n#include \"Settings.hpp\"\n\n#include <QSettings>\n#include <algorithm>\n\nnamespace {\nstd::vector<std::string> split_csv(const QString& value) {\n    std::vector<std::string> out;\n    const auto parts = value.split(\",\");\n    for (const auto& part : parts) {\n        QString trimmed = part.trimmed();\n        if (!trimmed.isEmpty()) {\n            out.emplace_back(trimmed.toStdString());\n        }\n    }\n    return out;\n}\n\nQString join_csv(const std::vector<std::string>& values) {\n    QStringList list;\n    for (const auto& v : values) {\n        list << QString::fromStdString(v);\n    }\n    return list.join(\", \");\n}\n}\n\nWhitelistStore::WhitelistStore(std::string config_dir)\n    : file_path_(std::move(config_dir) + \"/whitelists.ini\") {}\n\nbool WhitelistStore::load()\n{\n    entries_.clear();\n    QSettings settings(QString::fromStdString(file_path_), QSettings::IniFormat);\n    const QStringList groups = settings.childGroups();\n    for (const auto& group : groups) {\n        settings.beginGroup(group);\n        const auto cats = split_csv(settings.value(\"Categories\").toString());\n        const auto subs = split_csv(settings.value(\"Subcategories\").toString());\n        settings.endGroup();\n        if (!cats.empty() || !subs.empty()) {\n            entries_[group.toStdString()] = WhitelistEntry{cats, subs};\n        }\n    }\n    if (entries_.empty()) {\n        ensure_default_from_legacy({}, {});\n        save();\n    }\n    return true;\n}\n\nbool WhitelistStore::save() const\n{\n    QSettings settings(QString::fromStdString(file_path_), QSettings::IniFormat);\n    settings.clear();\n    for (const auto& pair : entries_) {\n        settings.beginGroup(QString::fromStdString(pair.first));\n        settings.setValue(\"Categories\", join_csv(pair.second.categories));\n        settings.setValue(\"Subcategories\", join_csv(pair.second.subcategories));\n        settings.endGroup();\n    }\n    settings.sync();\n    return settings.status() == QSettings::NoError;\n}\n\nstd::vector<std::string> WhitelistStore::list_names() const\n{\n    std::vector<std::string> names;\n    names.reserve(entries_.size());\n    for (const auto& entry : entries_) {\n        names.push_back(entry.first);\n    }\n    std::sort(names.begin(), names.end());\n    return names;\n}\n\nstd::optional<WhitelistEntry> WhitelistStore::get(const std::string& name) const\n{\n    if (auto it = entries_.find(name); it != entries_.end()) {\n        return it->second;\n    }\n    return std::nullopt;\n}\n\nvoid WhitelistStore::set(const std::string& name, WhitelistEntry entry)\n{\n    entries_[name] = std::move(entry);\n}\n\nvoid WhitelistStore::remove(const std::string& name)\n{\n    entries_.erase(name);\n}\n\nvoid WhitelistStore::ensure_default_from_legacy(const std::vector<std::string>& cats,\n                                                const std::vector<std::string>& subs)\n{\n    if (!entries_.empty()) {\n        return;\n    }\n    std::vector<std::string> use_cats = cats;\n    std::vector<std::string> use_subs = subs;\n    if (use_cats.empty()) {\n        use_cats = {\n            \"Archives\", \"Backups\", \"Books\", \"Configs\", \"Data Exports\",\n            \"Development\", \"Documents\", \"Drivers\", \"Ebooks\", \"Firmware\",\n            \"Guides\", \"Images\", \"Installers\", \"Licenses\", \"Manuals\",\n            \"Music\", \"Operating Systems\", \"Presentations\", \"Software\", \"Spreadsheets\", \"System\",\n            \"Temporary\", \"Videos\"\n        };\n    }\n    if (use_subs.empty()) {\n        use_subs = {};\n    }\n    entries_[default_name_] = WhitelistEntry{use_cats, use_subs};\n}\n\nvoid WhitelistStore::initialize_from_settings(Settings& settings)\n{\n    load();\n    ensure_default_from_legacy(settings.get_allowed_categories(),\n                               settings.get_allowed_subcategories());\n    save();\n\n    if (settings.get_active_whitelist().empty()) {\n        settings.set_active_whitelist(default_name_);\n    }\n\n    auto active = settings.get_active_whitelist();\n    if (auto entry = get(active)) {\n        settings.set_allowed_categories(entry->categories);\n        settings.set_allowed_subcategories(entry->subcategories);\n    }\n}\n"
  },
  {
    "path": "app/main.cpp",
    "content": "#include \"AppInfo.hpp\"\n#include \"EmbeddedEnv.hpp\"\n#include \"GgmlRuntimePaths.hpp\"\n#include \"Logger.hpp\"\n#include \"MainApp.hpp\"\n#include \"UpdaterBuildConfig.hpp\"\n#include \"UpdaterLaunchOptions.hpp\"\n#include \"UpdaterLiveTestConfig.hpp\"\n#include \"Utils.hpp\"\n#include \"LLMSelectionDialog.hpp\"\n#include <app_version.hpp>\n\n#include <QApplication>\n#include <QDialog>\n#include <QGuiApplication>\n#include <QSplashScreen>\n#include <QPixmap>\n#include <QSize>\n#include <QElapsedTimer>\n#include <QTimer>\n\n#include <functional>\n#include <algorithm>\n#include <vector>\n#include <cstring>\n#include <cstdlib>\n#include <filesystem>\n#include <optional>\n#include <QPainter>\n#include <memory>\n\n#include <curl/curl.h>\n#include <locale.h>\n#include <libintl.h>\n#include <cstdio>\n#include <iostream>\n#ifdef _WIN32\n#include <windows.h>\n#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2\n#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)\n#endif\nusing SetProcessDpiAwarenessContextFn = BOOL (WINAPI *)(HANDLE);\nusing SetProcessDpiAwarenessFn = HRESULT (WINAPI *)(int); // 2 = PROCESS_PER_MONITOR_DPI_AWARE\n#endif\n\n\nbool initialize_loggers()\n{\n    try {\n        Logger::setup_loggers();\n        return true;\n    } catch (const std::exception &e) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->critical(\"Failed to initialize loggers: {}\", e.what());\n        } else {\n            std::fprintf(stderr, \"Failed to initialize loggers: %s\\n\", e.what());\n        }\n        return false;\n    }\n}\n\nnamespace {\n\nstruct ParsedArguments {\n    bool development_mode{false};\n    bool console_log{false};\n    bool force_direct_run{false};\n    UpdaterLiveTestConfig updater_live_test;\n    std::vector<char*> qt_args;\n};\n\nbool consume_prefixed_value(const char* argument,\n                            const char* prefix,\n                            std::optional<std::string>& target)\n{\n    const std::size_t prefix_length = std::strlen(prefix);\n    if (std::strncmp(argument, prefix, prefix_length) != 0) {\n        return false;\n    }\n    target = std::string(argument + prefix_length);\n    return true;\n}\n\nbool env_has_value(const char* key)\n{\n    const char* value = std::getenv(key);\n    return value && value[0] != '\\0';\n}\n\nvoid set_process_env(const char* key, const std::string& value)\n{\n#ifdef _WIN32\n    _putenv_s(key, value.c_str());\n#else\n    setenv(key, value.c_str(), 1);\n#endif\n}\n\nvoid apply_updater_live_test_environment(const UpdaterLiveTestConfig& args)\n{\n    if (!args.enabled) {\n        return;\n    }\n\n    set_process_env(UpdaterLaunchOptions::kLiveTestModeEnv, \"1\");\n\n    if (args.installer_url) {\n        set_process_env(UpdaterLaunchOptions::kLiveTestUrlEnv, *args.installer_url);\n    }\n    if (args.installer_sha256) {\n        set_process_env(UpdaterLaunchOptions::kLiveTestSha256Env, *args.installer_sha256);\n    }\n    if (args.current_version) {\n        set_process_env(UpdaterLaunchOptions::kLiveTestVersionEnv, *args.current_version);\n    } else if (!env_has_value(UpdaterLaunchOptions::kLiveTestVersionEnv)) {\n        set_process_env(UpdaterLaunchOptions::kLiveTestVersionEnv, APP_VERSION.to_string() + \".1\");\n    }\n    if (args.min_version) {\n        set_process_env(UpdaterLaunchOptions::kLiveTestMinVersionEnv, *args.min_version);\n    }\n\n    if (!env_has_value(UpdaterLaunchOptions::kLiveTestUrlEnv)) {\n        throw std::runtime_error(\n            \"--updater-live-test requires --updater-live-test-url or AI_FILE_SORTER_UPDATER_TEST_URL.\");\n    }\n    if (!env_has_value(UpdaterLaunchOptions::kLiveTestSha256Env)) {\n        throw std::runtime_error(\n            \"--updater-live-test requires --updater-live-test-sha256 or AI_FILE_SORTER_UPDATER_TEST_SHA256.\");\n    }\n}\n\nParsedArguments parse_command_line(int argc, char** argv)\n{\n    ParsedArguments parsed;\n    parsed.qt_args.reserve(static_cast<size_t>(argc) + 1);\n\n    for (int i = 0; i < argc; ++i) {\n        const bool is_flag = (i > 0);\n        if (is_flag && std::strcmp(argv[i], \"--development\") == 0) {\n            parsed.development_mode = true;\n            continue;\n        }\n        if (is_flag && std::strcmp(argv[i], \"--allow-direct-launch\") == 0) {\n            continue;\n        }\n        if (is_flag && std::strcmp(argv[i], \"--console-log\") == 0) {\n            parsed.console_log = true;\n            continue;\n        }\n        if (is_flag && std::strcmp(argv[i], \"--force-direct-run\") == 0) {\n            parsed.force_direct_run = true;\n            continue;\n        }\n        if (is_flag && std::strcmp(argv[i], UpdaterLaunchOptions::kLiveTestFlag) == 0) {\n            parsed.updater_live_test.enabled = true;\n            continue;\n        }\n        if (is_flag && consume_prefixed_value(argv[i],\n                                              UpdaterLaunchOptions::kLiveTestUrlFlag,\n                                              parsed.updater_live_test.installer_url)) {\n            continue;\n        }\n        if (is_flag && consume_prefixed_value(argv[i],\n                                              UpdaterLaunchOptions::kLiveTestSha256Flag,\n                                              parsed.updater_live_test.installer_sha256)) {\n            continue;\n        }\n        if (is_flag && consume_prefixed_value(argv[i],\n                                              UpdaterLaunchOptions::kLiveTestVersionFlag,\n                                              parsed.updater_live_test.current_version)) {\n            continue;\n        }\n        if (is_flag && consume_prefixed_value(argv[i],\n                                              UpdaterLaunchOptions::kLiveTestMinVersionFlag,\n                                              parsed.updater_live_test.min_version)) {\n            continue;\n        }\n        parsed.qt_args.push_back(argv[i]);\n    }\n    parsed.qt_args.push_back(nullptr);\n    return parsed;\n}\n\n#if defined(__APPLE__)\n#ifndef AI_FILE_SORTER_GGML_SUBDIR\n#define AI_FILE_SORTER_GGML_SUBDIR \"precompiled\"\n#endif\n\nvoid ensure_ggml_backend_dir()\n{\n    std::optional<std::filesystem::path> current_dir;\n    const char* current = std::getenv(\"AI_FILE_SORTER_GGML_DIR\");\n    if (current && current[0] != '\\0') {\n        current_dir = std::filesystem::path(current);\n    }\n\n    std::filesystem::path exe_path;\n    try {\n        exe_path = Utils::get_executable_path();\n    } catch (const std::exception&) {\n        return;\n    }\n    if (exe_path.empty()) {\n        return;\n    }\n\n    const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir(\n        current_dir,\n        exe_path,\n        AI_FILE_SORTER_GGML_SUBDIR);\n    if (!resolved) {\n        return;\n    }\n\n    setenv(\"AI_FILE_SORTER_GGML_DIR\", resolved->string().c_str(), 1);\n}\n#endif\n\n#ifdef _WIN32\nbool allow_direct_launch(int argc, char** argv)\n{\n    for (int i = 1; i < argc; ++i) {\n        if (std::strcmp(argv[i], \"--force-direct-run\") == 0) {\n            return true;\n        }\n    }\n    for (int i = 1; i < argc; ++i) {\n        if (std::strcmp(argv[i], \"--allow-direct-launch\") == 0) {\n            return true;\n        }\n    }\n    return false;\n}\n\nvoid enable_per_monitor_dpi_awareness()\n{\n    HMODULE user32 = GetModuleHandleW(L\"user32.dll\");\n    if (user32) {\n        const auto set_ctx = reinterpret_cast<SetProcessDpiAwarenessContextFn>(\n            GetProcAddress(user32, \"SetProcessDpiAwarenessContext\"));\n        if (set_ctx && set_ctx(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {\n            return;\n        }\n    }\n    HMODULE shcore = LoadLibraryW(L\"Shcore.dll\");\n    if (shcore) {\n        const auto set_awareness = reinterpret_cast<SetProcessDpiAwarenessFn>(\n            GetProcAddress(shcore, \"SetProcessDpiAwareness\"));\n        if (set_awareness) {\n            // 2 == PROCESS_PER_MONITOR_DPI_AWARE\n            set_awareness(2);\n        }\n        FreeLibrary(shcore);\n    }\n}\n\nvoid attach_console_if_requested(bool enable)\n{\n    if (!enable) {\n        return;\n    }\n    if (AttachConsole(ATTACH_PARENT_PROCESS)) {\n        FILE* f = nullptr;\n        freopen_s(&f, \"CONOUT$\", \"w\", stdout);\n        freopen_s(&f, \"CONOUT$\", \"w\", stderr);\n        freopen_s(&f, \"CONIN$\", \"r\", stdin);\n    }\n}\n#endif\n\n[[maybe_unused]] QPixmap build_splash_pixmap()\n{\n    QPixmap splash_pix(QStringLiteral(\":/net/quicknode/AIFileSorter/images/icon_512x512.png\"));\n    if (splash_pix.isNull()) {\n        splash_pix = QPixmap(256, 256);\n        splash_pix.fill(Qt::black);\n    }\n\n    const QSize base_size(320, 320);\n    const QSize padded_size(static_cast<int>(base_size.width() * 1.2),\n                            static_cast<int>(base_size.height() * 1.1));\n\n    QPixmap scaled_splash = splash_pix.scaled(base_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);\n    QPixmap splash_canvas(padded_size);\n    splash_canvas.fill(QColor(QStringLiteral(\"#f5e6d3\")));\n\n    QPainter painter(&splash_canvas);\n    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);\n\n    const QPoint centered_icon((padded_size.width() - scaled_splash.width()) / 2,\n                               (padded_size.height() - scaled_splash.height()) / 2 - 10);\n    painter.drawPixmap(centered_icon, scaled_splash);\n    painter.end();\n\n    return splash_canvas;\n}\n\nclass SplashController {\npublic:\n    explicit SplashController(QApplication& app)\n        : app_(app)\n    {\n        Q_UNUSED(app_);\n    }\n\n    void set_target(QWidget* target)\n    {\n        target_ = target;\n    }\n\n    void keep_visible_for(int minimum_duration_ms)\n    {\n        Q_UNUSED(minimum_duration_ms);\n    }\n\n    void finish()\n    {\n        finished_ = true;\n    }\n\nprivate:\n    QApplication& app_;\n    bool finished_{false};\n    QWidget* target_{nullptr};\n};\n\nbool file_exists(const std::string& path)\n{\n    if (path.empty()) {\n        return false;\n    }\n    std::error_code ec;\n    return std::filesystem::exists(std::filesystem::path(path), ec);\n}\n\nbool has_local_model_for_env(const char* env_key)\n{\n    if (!env_key) {\n        return false;\n    }\n    const char* url = std::getenv(env_key);\n    if (!url || *url == '\\0') {\n        return false;\n    }\n    try {\n        const std::string path = Utils::make_default_path_to_file_from_download_url(url);\n        return file_exists(path);\n    } catch (...) {\n        return false;\n    }\n}\n\nbool llm_choice_is_ready(const Settings& settings)\n{\n    const LLMChoice choice = settings.get_llm_choice();\n    if (choice == LLMChoice::Unset) {\n        return false;\n    }\n    if (choice == LLMChoice::Remote_OpenAI) {\n        return !settings.get_openai_api_key().empty()\n            && !settings.get_openai_model().empty();\n    }\n    if (choice == LLMChoice::Remote_Gemini) {\n        return !settings.get_gemini_api_key().empty()\n            && !settings.get_gemini_model().empty();\n    }\n    if (choice == LLMChoice::Remote_Custom) {\n        const auto id = settings.get_active_custom_api_id();\n        if (id.empty()) {\n            return false;\n        }\n        const CustomApiEndpoint endpoint = settings.find_custom_api_endpoint(id);\n        return !endpoint.id.empty()\n            && !endpoint.base_url.empty()\n            && !endpoint.model.empty();\n    }\n    if (choice == LLMChoice::Custom) {\n        const auto id = settings.get_active_custom_llm_id();\n        if (id.empty()) {\n            return false;\n        }\n        const CustomLLM custom = settings.find_custom_llm(id);\n        return !custom.id.empty()\n            && !custom.path.empty()\n            && file_exists(custom.path);\n    }\n\n    const char* env_var = nullptr;\n    switch (choice) {\n        case LLMChoice::Local_3b:\n            env_var = \"LOCAL_LLM_3B_DOWNLOAD_URL\";\n            break;\n        case LLMChoice::Local_3b_legacy:\n            env_var = \"LOCAL_LLM_3B_LEGACY_DOWNLOAD_URL\";\n            break;\n        case LLMChoice::Local_7b:\n            env_var = \"LOCAL_LLM_7B_DOWNLOAD_URL\";\n            break;\n        default:\n            break;\n    }\n    return has_local_model_for_env(env_var);\n}\n\nbool ensure_llm_choice(Settings& settings, const std::function<void()>& finish_splash)\n{\n    if (llm_choice_is_ready(settings)) {\n        return true;\n    }\n\n    LLMSelectionDialog llm_dialog(settings);\n    if (llm_dialog.exec() != QDialog::Accepted) {\n        if (finish_splash) {\n            finish_splash();\n        }\n        return false;\n    }\n\n    settings.set_openai_api_key(llm_dialog.get_openai_api_key());\n    settings.set_openai_model(llm_dialog.get_openai_model());\n    settings.set_gemini_api_key(llm_dialog.get_gemini_api_key());\n    settings.set_gemini_model(llm_dialog.get_gemini_model());\n    settings.set_llm_choice(llm_dialog.get_selected_llm_choice());\n    settings.set_llm_downloads_expanded(llm_dialog.get_llm_downloads_expanded());\n    if (llm_dialog.get_selected_llm_choice() == LLMChoice::Custom) {\n        settings.set_active_custom_llm_id(llm_dialog.get_selected_custom_llm_id());\n    } else {\n        settings.set_active_custom_llm_id(\"\");\n    }\n    if (llm_dialog.get_selected_llm_choice() == LLMChoice::Remote_Custom) {\n        settings.set_active_custom_api_id(llm_dialog.get_selected_custom_api_id());\n    } else {\n        settings.set_active_custom_api_id(\"\");\n    }\n    settings.save();\n    return true;\n}\n\nint run_application(const ParsedArguments& parsed_args)\n{\n    EmbeddedEnv env_loader(\":/net/quicknode/AIFileSorter/.env\");\n    env_loader.load_env();\n    auto updater_live_test = parsed_args.updater_live_test;\n    if (UpdaterBuildConfig::update_checks_enabled()) {\n        load_missing_values_from_live_test_ini(\n            updater_live_test,\n            Utils::utf8_to_path(Utils::get_executable_path()));\n        apply_updater_live_test_environment(updater_live_test);\n    }\n#if defined(__APPLE__)\n    ensure_ggml_backend_dir();\n#endif\n    setlocale(LC_ALL, \"\");\n    const std::string locale_path = Utils::get_executable_path() + \"/locale\";\n    bindtextdomain(\"net.quicknode.AIFileSorter\", locale_path.c_str());\n\n    const QString display_name = app_display_name();\n    QCoreApplication::setApplicationName(display_name);\n    QGuiApplication::setApplicationDisplayName(display_name);\n\n    int qt_argc = static_cast<int>(parsed_args.qt_args.size()) - 1;\n    char** qt_argv = const_cast<char**>(parsed_args.qt_args.data());\n    QApplication app(qt_argc, qt_argv);\n\n    Settings settings;\n    settings.load();\n\n    const auto finish_splash = [&]() {};\n\n    if (!ensure_llm_choice(settings, finish_splash)) {\n        return EXIT_SUCCESS;\n    }\n\n    MainApp main_app(settings, parsed_args.development_mode);\n    main_app.run();\n\n    const int result = app.exec();\n    main_app.shutdown();\n    return result;\n}\n\n} // namespace\n\n\nint main(int argc, char **argv) {\n\n    ParsedArguments parsed = parse_command_line(argc, argv);\n\n#ifdef _WIN32\n    enable_per_monitor_dpi_awareness();\n    attach_console_if_requested(parsed.console_log);\n#endif\n\n    if (!initialize_loggers()) {\n        return EXIT_FAILURE;\n    }\n    curl_global_init(CURL_GLOBAL_DEFAULT);\n    struct CurlCleanup {\n        ~CurlCleanup() { curl_global_cleanup(); }\n    } curl_cleanup;\n\n    #ifdef _WIN32\n        _putenv(\"GSETTINGS_SCHEMA_DIR=schemas\");\n    #endif\n    try {\n        return run_application(parsed);\n    } catch (const std::exception& ex) {\n        if (auto logger = Logger::get_logger(\"core_logger\")) {\n            logger->critical(\"Error: {}\", ex.what());\n        } else {\n            std::fprintf(stderr, \"Error: %s\\n\", ex.what());\n        }\n        return EXIT_FAILURE;\n    }\n}\n"
  },
  {
    "path": "app/resources/app.qrc",
    "content": "<!DOCTYPE RCC><RCC version=\"1.0\">\n  <qresource prefix=\"/net/quicknode/AIFileSorter\">\n    <file>images/logo.png</file>\n    <file>images/qn_logo.png</file>\n    <file>images/app_icon_128.png</file>\n    <file>images/icon_512x512.png</file>\n    <file>.env</file>\n    <file>certs/cacert.pem</file>\n  </qresource>\n</RCC>\n"
  },
  {
    "path": "app/resources/certs/cacert.pem",
    "content": "##\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 updated versions here: https://curl.se/docs/caextract.html\n##\n## This is a bundle of X.509 certificates of public Certificate Authorities\n## (CA). These were automatically extracted from Mozilla's root certificates\n## file (certdata.txt).  This file can be found in the mozilla source tree:\n## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt\n##\n## It contains the certificates in PEM format and therefore\n## can be directly used with curl / libcurl / php_curl, or with\n## an Apache+mod_ssl webserver for SSL client authentication.\n## Just configure this file as the SSLCACertificateFile.\n##\n## Conversion done with mk-ca-bundle.pl version 1.29.\n## SHA256: 0078e6bdd280fd89e1b883174387aae84b3eae2ee263416a5f8a14ee7f179ae9\n##\n\n\nEntrust Root Certification Authority\n====================================\n-----BEGIN CERTIFICATE-----\nMIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV\nBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw\nb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG\nA1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0\nMloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu\nMTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu\nY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v\ndCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz\nA9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww\nCj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68\nj6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN\nrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw\nDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1\nMzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH\nhmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\nA4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM\nY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa\nv52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS\nW3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0\ntHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 2\n==================\n-----BEGIN CERTIFICATE-----\nMIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\nEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx\nODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\naW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6\nXJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk\nlvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB\nlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy\nlZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt\n66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn\nwQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh\nD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy\nBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie\nJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud\nDgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU\na6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\nElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv\nZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3\nUIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm\nVjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK\n+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW\nIozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1\nWVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X\nf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II\n4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8\nVCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 3\n==================\n-----BEGIN CERTIFICATE-----\nMIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\nEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx\nOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\naW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg\nDhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij\nKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K\nDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv\nBNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp\np5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8\nnT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX\nMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM\nGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz\nuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT\nBgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj\nYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\naWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB\nBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD\nVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4\nywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE\nAxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV\nqyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s\nhvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z\nPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2\nPb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp\n8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC\nbjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu\ng/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p\nvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr\nqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root CA\n===========================\n-----BEGIN CERTIFICATE-----\nMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\nIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx\nMTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\nExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO\n9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy\nUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW\n/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy\noeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf\nGHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF\n66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq\nhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc\nEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn\nSbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i\n8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n-----END CERTIFICATE-----\n\nDigiCert Global Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\nHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw\nMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\ndy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn\nTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5\nBmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H\n4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y\n7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB\no2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm\n8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF\nBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr\nEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt\ntep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886\nUAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\nCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n-----END CERTIFICATE-----\n\nDigiCert High Assurance EV Root CA\n==================================\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw\nKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw\nMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ\nMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu\nY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t\nMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS\nOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3\nMRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ\nNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe\nh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB\nAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY\nJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ\nV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp\nmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK\nmNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\nvEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\n-----END CERTIFICATE-----\n\nSwissSign Gold CA - G2\n======================\n-----BEGIN CERTIFICATE-----\nMIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw\nEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN\nMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp\nc3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq\nt2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C\njCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg\nvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF\nylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR\nAiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend\njIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO\npeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR\n7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi\nGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw\nAwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64\nOfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov\nL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm\n5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr\n44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf\nMke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m\nGu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp\nmo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk\nvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf\nKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br\nNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj\nviOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ\n-----END CERTIFICATE-----\n\nSecureTrust CA\n==============\n-----BEGIN CERTIFICATE-----\nMIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG\nEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy\ndXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe\nBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX\nOZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t\nDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH\nGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b\n01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH\nursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/\nBAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj\naHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\nKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu\nSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf\nmbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ\nnMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR\n3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\n-----END CERTIFICATE-----\n\nSecure Global CA\n================\n-----BEGIN CERTIFICATE-----\nMIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG\nEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH\nbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg\nMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg\nQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx\nYDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ\nbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g\n8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV\nHDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi\n0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\nEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn\noCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA\nMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+\nOYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn\nCDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5\n3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc\nf8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\n-----END CERTIFICATE-----\n\nCOMODO Certification Authority\n==============================\n-----BEGIN CERTIFICATE-----\nMIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE\nBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\nA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1\ndGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb\nMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD\nT01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH\n+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww\nxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV\n4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA\n1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI\nrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k\nb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC\nAQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP\nOGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\nRxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc\nIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN\n+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==\n-----END CERTIFICATE-----\n\nCOMODO ECC Certification Authority\n==================================\n-----BEGIN CERTIFICATE-----\nMIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC\nR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\nChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix\nGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\nQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo\nb3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X\n4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni\nwz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG\nFAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA\nU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n-----END CERTIFICATE-----\n\nCertigna\n========\n-----BEGIN CERTIFICATE-----\nMIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw\nEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3\nMDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI\nQ2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q\nXOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH\nGxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p\nogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg\nDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf\nIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ\ntCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ\nBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J\nSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA\nhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+\nImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu\nPBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY\n1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw\nWyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\n-----END CERTIFICATE-----\n\nePKI Root Certification Authority\n=================================\n-----BEGIN CERTIFICATE-----\nMIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG\nEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg\nUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx\nMjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq\nMCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs\nIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi\nlTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv\nqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX\n12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O\nWQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+\nETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao\nlQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/\nvv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi\nZo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi\nMAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH\nClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0\n1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\nKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV\nxrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP\nNXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r\nGNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE\nxJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx\ngMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy\nsP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD\nBCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=\n-----END CERTIFICATE-----\n\ncertSIGN ROOT CA\n================\n-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD\nVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa\nFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE\nCxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I\nJUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH\nrfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2\nssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD\n0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943\nAAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\nAf8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB\nAQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8\nSG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0\nx2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt\nvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz\nTogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD\n-----END CERTIFICATE-----\n\nNetLock Arany (Class Gold) Főtanúsítvány\n========================================\n-----BEGIN CERTIFICATE-----\nMIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G\nA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610\ndsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB\ncmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx\nMjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO\nZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv\nbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6\nc8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu\n0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw\n/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk\nH3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw\nfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1\nneWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB\nBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW\nqZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta\nYtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC\nbLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna\nNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu\ndZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\n-----END CERTIFICATE-----\n\nMicrosec e-Szigno Root CA 2009\n==============================\n-----BEGIN CERTIFICATE-----\nMIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER\nMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv\nc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o\ndTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE\nBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt\nU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA\nfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG\n0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA\npxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm\n1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC\nAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf\nQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE\nFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o\nlZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX\nI/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775\ntyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02\nyULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi\nLXpUq3DDfSJlgnCW\n-----END CERTIFICATE-----\n\nGlobalSign Root CA - R3\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv\nYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\nbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\naWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\nbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt\niHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ\n0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3\nrHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl\nOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2\nxmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\nFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7\nlgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8\nEpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E\nbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18\nYIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r\nkpeDMdmztcpHWD9f\n-----END CERTIFICATE-----\n\nIzenpe.com\n==========\n-----BEGIN CERTIFICATE-----\nMIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG\nEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz\nMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu\nQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ\n03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK\nClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU\n+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC\nPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT\nOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK\nF7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK\n0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+\n0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB\nleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID\nAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+\nSVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG\nNjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx\nMCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\nBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\nFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga\nkEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q\nhT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs\ng1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5\naTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5\nnXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC\nClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo\nQ0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z\nWrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==\n-----END CERTIFICATE-----\n\nGo Daddy Root Certificate Authority - G2\n========================================\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu\nMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\nMDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\nb25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G\nA1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq\n9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD\n+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd\nfMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl\nNAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC\nMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9\nBUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac\nvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r\n5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV\nN8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\nLPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1\n-----END CERTIFICATE-----\n\nStarfield Root Certificate Authority - G2\n=========================================\n-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\nb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0\neSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw\nDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg\nVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB\ndXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv\nW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs\nbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk\nN3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf\nZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU\nJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol\nTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx\n4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw\nF5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\npL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ\nc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n-----END CERTIFICATE-----\n\nStarfield Services Root Certificate Authority - G2\n==================================================\n-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\nb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl\nIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV\nBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT\ndGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg\nUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2\nh/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa\nhHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP\nLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB\nrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG\nSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP\nE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy\nxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\niEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza\nYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6\n-----END CERTIFICATE-----\n\nAffirmTrust Commercial\n======================\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw\nMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\nbVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb\nDuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV\nC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6\nBfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww\nMmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV\nHQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG\nhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi\nqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv\n0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh\nsUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n-----END CERTIFICATE-----\n\nAffirmTrust Networking\n======================\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw\nMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\nbVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE\nHi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI\ndIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24\n/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb\nh+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV\nHQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu\nUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6\n12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23\nWJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9\n/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n-----END CERTIFICATE-----\n\nAffirmTrust Premium\n===================\n-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy\nOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy\ndXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn\nBKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV\n5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs\n+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd\nGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R\np9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI\nS+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04\n6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5\n/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo\n+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB\n/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv\nMiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\nNt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC\n6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S\nL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK\n+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV\nBtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg\nIxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60\ng2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb\nzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==\n-----END CERTIFICATE-----\n\nAffirmTrust Premium ECC\n=======================\n-----BEGIN CERTIFICATE-----\nMIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV\nBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx\nMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U\ncnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ\nN8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW\nBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK\nBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X\n57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM\neQ==\n-----END CERTIFICATE-----\n\nCertum Trusted Network CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK\nExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy\nMTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU\nZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC\nl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J\nJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4\nfOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0\ncvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw\nDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj\njSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1\nmS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj\nZt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI\n03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\n-----END CERTIFICATE-----\n\nTWCA Root Certification Authority\n=================================\n-----BEGIN CERTIFICATE-----\nMIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ\nVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG\nEwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB\nIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx\nQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC\noi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP\n4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r\ny+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB\nBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG\n9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC\nmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW\nQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY\nT0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny\nYh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\n-----END CERTIFICATE-----\n\nSecurity Communication RootCA2\n==============================\n-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\nU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh\ndGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC\nSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy\naXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++\n+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R\n3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV\nspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K\nEOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8\nQIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\nCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj\nu/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk\n3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q\ntnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29\nmvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\n-----END CERTIFICATE-----\n\nActalis Authentication Root CA\n==============================\n-----BEGIN CERTIFICATE-----\nMIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM\nBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE\nAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky\nMjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz\nIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290\nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ\nwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa\nby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6\nzfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f\nYVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2\noxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l\nEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7\nhNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8\nEBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5\njF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY\niDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt\nifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI\nWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0\nJZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx\nK3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+\nXlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC\n4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo\n2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz\nlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem\nOR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9\nvwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==\n-----END CERTIFICATE-----\n\nBuypass Class 2 Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\nQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X\nDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\neXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1\ng1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn\n9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b\n/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU\nCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff\nawrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI\nzRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn\nBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX\nUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs\nM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\nAAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s\nA20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI\nosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S\naq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd\nDnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD\nLfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0\noyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC\nwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS\nCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN\nrJgWVqA=\n-----END CERTIFICATE-----\n\nBuypass Class 3 Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\nQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X\nDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\neXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH\nsJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR\n5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh\n7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ\nZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH\n2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV\n/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ\nRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA\nXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq\nj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\nAAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV\ncSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G\nuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG\nQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8\nZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2\nKSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz\n6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug\nUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe\neOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi\nCp/HuZc=\n-----END CERTIFICATE-----\n\nT-TeleSec GlobalRoot Class 3\n============================\n-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\nIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\ncnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx\nMDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\ndGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\nZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK\n9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU\nNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF\niP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W\n0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr\nAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb\nfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT\nucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h\nP0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml\ne9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==\n-----END CERTIFICATE-----\n\nD-TRUST Root Class 3 CA 2 2009\n==============================\n-----BEGIN CERTIFICATE-----\nMIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe\nFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE\nLVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD\nER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA\nBF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv\nKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z\np+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC\nAwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ\n4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y\neS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw\nMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G\nPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw\nOS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm\n2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0\no3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV\ndT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph\nX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=\n-----END CERTIFICATE-----\n\nD-TRUST Root Class 3 CA 2 EV 2009\n=================================\n-----BEGIN CERTIFICATE-----\nMIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\nOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\nOTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS\negpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh\nzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T\n7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60\nsUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35\n11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv\ncop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v\nZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El\nMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp\nb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh\nc3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+\nPPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05\nnsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX\nANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA\nNCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv\nw9y4AyHqnxbxLFS1\n-----END CERTIFICATE-----\n\nCA Disig Root R2\n================\n-----BEGIN CERTIFICATE-----\nMIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw\nEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\nZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx\nEzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\nc2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC\nw3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia\nxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7\nA7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S\nGBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV\ng8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa\n5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE\nkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A\nAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i\nFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV\nHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u\nQu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM\ntCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV\nsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je\ndR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8\n1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx\nmHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01\nutI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0\nsorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg\nUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV\n7+ZtsH8tZ/3zbBt1RqPlShfppNcL\n-----END CERTIFICATE-----\n\nACCVRAIZ1\n=========\n-----BEGIN CERTIFICATE-----\nMIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB\nSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1\nMDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH\nUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM\njmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0\nRGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD\naaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ\n0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG\nWuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7\n8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR\n5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J\n9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK\nQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw\nOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu\nY3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2\nVuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM\nHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA\nQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh\nAO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA\nYwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj\nAHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA\nIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk\naHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0\ndHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2\nMV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI\nhvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E\nR9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN\nYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49\nnCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ\nTS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3\nsCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\nI6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg\nNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd\n3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p\nEfbRD0tVNEYqi4Y7\n-----END CERTIFICATE-----\n\nTWCA Global Root CA\n===================\n-----BEGIN CERTIFICATE-----\nMIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT\nCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD\nQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK\nEwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg\nQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C\nnJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV\nr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR\nQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV\ntTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W\nKKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99\nsy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p\nyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn\nkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI\nzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g\ncFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn\nLhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M\n8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg\n/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg\nlPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP\nA9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m\ni4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8\nEHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3\nzqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=\n-----END CERTIFICATE-----\n\nTeliaSonera Root CA v1\n======================\n-----BEGIN CERTIFICATE-----\nMIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE\nCgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4\nMTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW\nVGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+\n6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA\n3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k\nB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn\nXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH\noLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3\nF0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ\noWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7\ngUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc\nTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB\nAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW\nDNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm\nzqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx\n0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW\npb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV\nG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc\nc41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT\nJsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2\nqReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6\nY2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems\nWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=\n-----END CERTIFICATE-----\n\nT-TeleSec GlobalRoot Class 2\n============================\n-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\nIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\ncnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx\nMDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\ndGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\nZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ\nSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F\nvudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970\n2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV\nWOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy\nYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4\nr6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf\nvNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR\n3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN\n9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==\n-----END CERTIFICATE-----\n\nAtos TrustedRoot 2011\n=====================\n-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU\ncnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4\nMzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG\nA1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV\nhTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr\n54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+\nDgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320\nHLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR\nz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R\nl+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ\nbNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\nCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h\nk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh\nTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9\n61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G\n3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 1 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE\nPBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm\nPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6\nPser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN\nofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l\ng6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV\n7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX\n9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f\niyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg\nt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI\nhvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC\nMTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3\nGPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct\nTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP\n+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh\n3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa\nwx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6\nO0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0\nFU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV\nhMJKzRwuJIczYOXD\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 2 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh\nZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY\nNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t\noIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o\nMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l\nV0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo\nL1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ\nsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD\n6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh\nlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI\nhvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66\nAarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K\npVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9\nx52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz\ndWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X\nU/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw\nmNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD\nzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN\nJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr\nO3jtZsSOeWmD3n+M\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 3 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286\nIxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL\nMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe\n6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3\nI4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U\nVDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7\n5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi\nMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM\ndyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt\nrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI\nhvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px\nKGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS\nt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ\nTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du\nDcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib\nIh6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD\nhPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX\n0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW\ndSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2\nPpxxVJkES/1Y+Zj0\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root G2\n===========================\n-----BEGIN CERTIFICATE-----\nMIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\nIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw\nMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\nExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH\n35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq\nbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw\nVWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP\nYLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn\nlTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO\nw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv\n0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz\nd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW\nhsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M\njomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\nIhNzbM8m9Yop5w==\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root G3\n===========================\n-----BEGIN CERTIFICATE-----\nMIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD\nVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\nMTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb\nRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs\nKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF\nUaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy\nYZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy\n1vUhZscv6pZjamVFkpUBtA==\n-----END CERTIFICATE-----\n\nDigiCert Global Root G2\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\nHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx\nMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\ndy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ\nkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO\n3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV\nBJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM\nUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB\no0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu\n5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr\nF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U\nWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH\nQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/\niyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\nMrY=\n-----END CERTIFICATE-----\n\nDigiCert Global Root G3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD\nVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw\nMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k\naWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O\nYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp\nYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y\n3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34\nVOKa5Vt8sycX\n-----END CERTIFICATE-----\n\nDigiCert Trusted Root G4\n========================\n-----BEGIN CERTIFICATE-----\nMIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw\nHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\nMTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp\npz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o\nk3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa\nvOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY\nQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6\nMUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm\nmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7\nf/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH\ndL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8\noR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\nDwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\nggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY\nZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr\nyF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy\n7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah\nixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN\n5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb\n/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa\n5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK\nG48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP\n82Z+\n-----END CERTIFICATE-----\n\nCOMODO RSA Certification Authority\n==================================\n-----BEGIN CERTIFICATE-----\nMIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\nBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\nA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC\nR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\nChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn\ndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ\nFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+\n5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG\nx8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX\n2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL\nOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3\nsgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C\nGCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5\nWdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\nFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt\nrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+\nnq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg\ntZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\nsRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\npC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA\nzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq\nZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52\n7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\nLaZRfyHBNVOFBkpdn627G190\n-----END CERTIFICATE-----\n\nUSERTrust RSA Certification Authority\n=====================================\n-----BEGIN CERTIFICATE-----\nMIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\nExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\nExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz\n0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j\nY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn\nRghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O\n+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq\n/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE\nY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM\nlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8\nyexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+\neLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\nBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW\nFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ\n7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ\nEg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM\n8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi\nFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi\nyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c\nJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw\nsAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx\nQ+6IHdfGjjxDah2nGN59PRbxYvnKkKj9\n-----END CERTIFICATE-----\n\nUSERTrust ECC Certification Authority\n=====================================\n-----BEGIN CERTIFICATE-----\nMIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC\nVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\naGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC\nVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\naGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2\n0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez\nnPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV\nHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB\nHU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu\n9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n-----END CERTIFICATE-----\n\nGlobalSign ECC Root CA - R5\n===========================\n-----BEGIN CERTIFICATE-----\nMIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb\nR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\nEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\nR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\nEwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6\nSFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS\nh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\nBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx\nuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7\nyFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3\n-----END CERTIFICATE-----\n\nIdenTrust Commercial Root CA 1\n==============================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG\nEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS\nb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES\nMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB\nIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld\nhNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/\nmNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi\n1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C\nXZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl\n3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy\nNeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV\nWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg\nxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix\nuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI\nhvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH\n6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg\nghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt\nozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV\nYjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX\nfeu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro\nkTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe\n2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz\nZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R\ncGzM7vRX+Bi6hG6H\n-----END CERTIFICATE-----\n\nIdenTrust Public Sector Root CA 1\n=================================\n-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG\nEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv\nciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV\nUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS\nb290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy\nP4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6\nHi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI\nrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf\nqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS\nmJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn\nol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh\nLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v\niDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL\n4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B\nAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw\nDQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj\nt2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A\nmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt\nGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt\nm6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx\nNRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4\nMhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI\najjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC\nZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ\n3Wl9af0AVqW3rLatt8o+Ae+c\n-----END CERTIFICATE-----\n\nEntrust Root Certification Authority - G2\n=========================================\n-----BEGIN CERTIFICATE-----\nMIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV\nBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy\nbXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug\nb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw\nHhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT\nDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx\nOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s\neTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP\n/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz\nHHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU\ns/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y\nTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx\nAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6\n0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z\niXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\nRkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi\nnWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+\nvGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO\ne4pIb4tF9g==\n-----END CERTIFICATE-----\n\nEntrust Root Certification Authority - EC1\n==========================================\n-----BEGIN CERTIFICATE-----\nMIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx\nFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn\nYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl\nZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nIC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw\nFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs\nLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg\ndXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt\nIEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy\nAsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef\n9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\nFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h\nvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8\nkmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n-----END CERTIFICATE-----\n\nCFCA EV ROOT\n============\n-----BEGIN CERTIFICATE-----\nMIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE\nCgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB\nIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw\nMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD\nDAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV\nBU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD\n7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN\nuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW\nZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7\nxzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f\npy25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K\ngWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol\nhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ\ntqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf\nBgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB\n/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\nACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q\necsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua\n4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG\nE5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX\nBDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn\naH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy\nPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX\nkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C\nekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\n-----END CERTIFICATE-----\n\nOISTE WISeKey Global Root GB CA\n===============================\n-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG\nEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl\nZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw\nMzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD\nVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds\nb2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX\nscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP\nrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk\n9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o\nQnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg\nGUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI\nhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD\ndHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0\nVQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui\nHZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic\nNc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=\n-----END CERTIFICATE-----\n\nSZAFIR ROOT CA2\n===============\n-----BEGIN CERTIFICATE-----\nMIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV\nBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ\nBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD\nVQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q\nqEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK\nDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE\n2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ\nckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi\nieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC\nAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5\nO/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67\noPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul\n4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6\n+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==\n-----END CERTIFICATE-----\n\nCertum Trusted Network CA 2\n===========================\n-----BEGIN CERTIFICATE-----\nMIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE\nBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1\nbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y\nayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ\nTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl\ncnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB\nIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9\n7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o\nCgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b\nRr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p\nuTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130\nGO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ\n9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB\nRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye\nhizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM\nBhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI\nhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW\nAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA\nL55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo\nclm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM\npkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb\nw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo\nJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm\nypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX\nis7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7\nzAYspsbiDrW5viSP\n-----END CERTIFICATE-----\n\nHellenic Academic and Research Institutions RootCA 2015\n=======================================================\n-----BEGIN CERTIFICATE-----\nMIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT\nBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0\naW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl\nYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx\nMTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg\nQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV\nBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw\nMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv\nbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh\niGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+\n6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd\nFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr\ni5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F\nGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2\nfu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu\niNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc\nBw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI\nhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+\nD1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM\nd/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y\nd+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn\n82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb\ndavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F\nJej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt\nJ94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa\nJI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q\np/UsQu0yrbYhnr68\n-----END CERTIFICATE-----\n\nHellenic Academic and Research Institutions ECC RootCA 2015\n===========================================================\n-----BEGIN CERTIFICATE-----\nMIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0\naGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\ncyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj\naCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw\nMzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj\nIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD\nVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290\nQ0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP\ndJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK\nVlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\nBBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA\nGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn\ndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR\n-----END CERTIFICATE-----\n\nISRG Root X1\n============\n-----BEGIN CERTIFICATE-----\nMIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE\nBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD\nEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG\nEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT\nDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r\nVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1\n3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K\nb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN\nAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ\n4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf\n1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu\nhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH\nusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r\nOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G\nA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY\n9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\nubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV\n0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt\nhDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw\nTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx\ne5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA\nJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD\nYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n\nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ\nm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n-----END CERTIFICATE-----\n\nAC RAIZ FNMT-RCM\n================\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT\nAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw\nMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD\nTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf\nqQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr\nbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL\nj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou\n08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw\nWsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT\ntOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ\n47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC\nll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa\ni0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\nFPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o\ndHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD\nnFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s\nD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ\nj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT\nQfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW\n+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7\nIxjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d\n8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm\n5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG\nrp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=\n-----END CERTIFICATE-----\n\nAmazon Root CA 1\n================\n-----BEGIN CERTIFICATE-----\nMIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD\nVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1\nMDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\nbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH\nFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ\ngLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t\ndHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce\nVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\n/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3\nDQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM\nCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy\n8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa\n2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2\nxJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\n-----END CERTIFICATE-----\n\nAmazon Root CA 2\n================\n-----BEGIN CERTIFICATE-----\nMIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD\nVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1\nMDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\nbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4\nkHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp\nN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9\nAElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd\nfLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx\nkv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS\nbtqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0\nQ5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN\nc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+\n3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw\nDPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA\nA7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\n+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE\nYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW\nxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ\ngj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW\naQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV\nYh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3\nKadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi\nJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=\n-----END CERTIFICATE-----\n\nAmazon Root CA 3\n================\n-----BEGIN CERTIFICATE-----\nMIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG\nEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy\nNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\nMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB\nf8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr\nZt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43\nrDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc\neGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==\n-----END CERTIFICATE-----\n\nAmazon Root CA 4\n================\n-----BEGIN CERTIFICATE-----\nMIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG\nEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy\nNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\nMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN\n/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri\n83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA\nMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1\nAE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n-----END CERTIFICATE-----\n\nTUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT\nD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr\nIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g\nTWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp\nZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD\nVQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt\nc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth\nbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11\nIFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8\n6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc\nwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0\n3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9\nWSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU\nZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ\nKoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh\nAHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc\nlNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R\ne37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j\nq5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=\n-----END CERTIFICATE-----\n\nGDCA TrustAUTH R5 ROOT\n======================\n-----BEGIN CERTIFICATE-----\nMIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw\nBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD\nDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow\nYjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ\nIENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs\nAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p\nOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr\npftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ\n9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ\nxXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM\nR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ\nD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4\noR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx\n9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg\np8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9\nH5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35\n6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd\n+PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ\nHtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD\nF8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ\n8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv\n/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT\naaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==\n-----END CERTIFICATE-----\n\nSSL.com Root Certification Authority RSA\n========================================\n-----BEGIN CERTIFICATE-----\nMIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM\nBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x\nMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw\nMjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx\nEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM\nLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD\nggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C\nFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8\nP2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge\noeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp\nk8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z\nfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ\ngUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2\nUzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8\n1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s\nbE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV\nHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE\nAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr\ndIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf\nijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl\nu1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq\nerQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj\nMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ\nvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI\nPb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y\nwKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI\nWuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=\n-----END CERTIFICATE-----\n\nSSL.com Root Certification Authority ECC\n========================================\n-----BEGIN CERTIFICATE-----\nMIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV\nBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv\nBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy\nMTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO\nBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv\nbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA\nBEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+\n8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR\nhXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT\njgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW\ne+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z\n5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl\n-----END CERTIFICATE-----\n\nSSL.com EV Root Certification Authority RSA R2\n==============================================\n-----BEGIN CERTIFICATE-----\nMIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w\nDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u\nMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy\nMB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI\nDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD\nVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh\nhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w\ncXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO\nZw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+\nB6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh\nCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim\n9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto\nRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm\nJuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48\n+qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV\nHSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp\nqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1\n++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx\nY/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G\nguDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz\nOFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7\nCTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq\nlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR\nrwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1\nhlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX\n9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==\n-----END CERTIFICATE-----\n\nSSL.com EV Root Certification Authority ECC\n===========================================\n-----BEGIN CERTIFICATE-----\nMIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV\nBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy\nBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw\nMjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx\nEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM\nLmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB\nBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy\n3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O\nBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe\n5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ\nN+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm\nm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==\n-----END CERTIFICATE-----\n\nGlobalSign Root CA - R6\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX\nR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i\nYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs\nU2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss\ngrRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE\n3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF\nvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM\nPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+\nazayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O\nWgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy\nCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP\n0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN\nb7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE\nAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV\nHSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN\nnsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0\nlV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY\nBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym\nFe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr\n3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1\n0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T\nuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK\noZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t\nJDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=\n-----END CERTIFICATE-----\n\nOISTE WISeKey Global Root GC CA\n===============================\n-----BEGIN CERTIFICATE-----\nMIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD\nSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo\nMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa\nFw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL\nExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh\nbCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr\nVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab\nNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\nBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E\nAwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk\nAjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9\n-----END CERTIFICATE-----\n\nUCA Global G2 Root\n==================\n-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG\nEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x\nNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU\ncnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT\noni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV\n8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS\nh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o\nLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/\nR+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe\nKW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa\n4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc\nOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97\n8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\nBBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo\n5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5\n1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A\nDs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9\nyBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX\nc47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo\njhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk\nbxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x\nygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn\nRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==\n-----END CERTIFICATE-----\n\nUCA Extended Validation Root\n============================\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG\nEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u\nIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G\nA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs\niWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF\nRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu\neUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR\n59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH\n0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR\nel7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv\nB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth\nWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS\nNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS\n3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL\nBQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR\nap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM\naVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4\ndxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb\n+7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW\nF3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi\nGpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc\nGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi\ndjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr\ndhh2n1ax\n-----END CERTIFICATE-----\n\nCertigna Root CA\n================\n-----BEGIN CERTIFICATE-----\nMIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE\nBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ\nMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda\nMFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz\nMDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX\nstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz\nKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8\nJXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16\nXdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq\n4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej\nwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ\nlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI\njzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/\n/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of\n1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy\ndGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h\nLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl\ncnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt\nOoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP\nTGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq\n7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3\n4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd\n8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS\n6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY\ntlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS\naX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde\nE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=\n-----END CERTIFICATE-----\n\nemSign Root CA - G1\n===================\n-----BEGIN CERTIFICATE-----\nMIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET\nMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx\nODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk\naHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN\nLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1\ncM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW\nDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ\n6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH\nhQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG\nMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2\nvZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q\nNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q\n+Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih\nU80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx\niN66zB+Afko=\n-----END CERTIFICATE-----\n\nemSign ECC Root CA - G3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG\nA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg\nMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4\nMTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11\nZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g\nRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc\n58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr\nMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D\nCBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7\njHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj\n-----END CERTIFICATE-----\n\nemSign Root CA - C1\n===================\n-----BEGIN CERTIFICATE-----\nMIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx\nEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp\nZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE\nBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD\nExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up\nufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/\nXse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX\nOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V\nI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms\nlMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+\nXJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD\nggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp\n/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1\nNnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9\nwC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ\nBmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=\n-----END CERTIFICATE-----\n\nemSign ECC Root CA - C3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG\nA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF\nQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE\nBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD\nExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd\n6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9\nSMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA\nB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA\nMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU\nZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==\n-----END CERTIFICATE-----\n\nHongkong Post Root CA 3\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG\nA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK\nEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2\nMDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv\nbmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX\nSG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz\niNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf\njTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim\n5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe\nsL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj\n0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/\nJgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u\ny1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h\n+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG\nxVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID\nAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e\ni9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN\nAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw\nW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld\ny8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov\n+BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc\neqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw\n9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7\nnwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY\nhcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB\n60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq\ndBb9HxEGmpv0\n-----END CERTIFICATE-----\n\nMicrosoft ECC Root Certificate Authority 2017\n=============================================\n-----BEGIN CERTIFICATE-----\nMIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\nUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND\nIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4\nMjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw\nNAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6\nthaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB\neMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM\n+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf\nXu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR\neNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=\n-----END CERTIFICATE-----\n\nMicrosoft RSA Root Certificate Authority 2017\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG\nEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg\nUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw\nNzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u\nMTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw\nggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml\n7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e\nS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7\n1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+\ndkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F\nyGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS\nMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr\nlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ\n0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ\nClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw\nDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC\nNxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og\n6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80\ndK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk\n+ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex\n/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy\nAmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW\nZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE\n7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT\nc0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D\n5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E\n-----END CERTIFICATE-----\n\ne-Szigno Root CA 2017\n=====================\n-----BEGIN CERTIFICATE-----\nMIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw\nDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt\nMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa\nFw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE\nCgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp\nZ25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx\ns1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G\nA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv\nvzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA\ntVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO\nsvxyqltZ+efcMQ==\n-----END CERTIFICATE-----\n\ncertSIGN Root CA G2\n===================\n-----BEGIN CERTIFICATE-----\nMIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw\nEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy\nMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH\nTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05\nN0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk\nabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg\nwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp\ndWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh\nngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732\njcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf\n95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc\nz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL\niohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud\nDgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB\nywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC\nb6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB\n/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5\n8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5\nBiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW\natKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU\nSxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M\nNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N\n0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=\n-----END CERTIFICATE-----\n\nTrustwave Global Certification Authority\n========================================\n-----BEGIN CERTIFICATE-----\nMIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV\nUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2\nZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u\nIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV\nUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2\nZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u\nIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29\nzd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf\nLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq\nstTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o\nWN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+\nOsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40\nCz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE\nuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm\n+9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj\nifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud\nEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB\nBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H\nPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H\nZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla\n4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R\nvbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd\nzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O\n856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH\nYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu\n3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP\n29FpHOTKyeC2nOnOcXHebD8WpHk=\n-----END CERTIFICATE-----\n\nTrustwave Global ECC P256 Certification Authority\n=================================================\n-----BEGIN CERTIFICATE-----\nMIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER\nMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI\nb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD\nVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy\ndXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1\nNiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj\n43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm\nP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt\n0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz\nRM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7\n-----END CERTIFICATE-----\n\nTrustwave Global ECC P384 Certification Authority\n=================================================\n-----BEGIN CERTIFICATE-----\nMIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER\nMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI\nb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD\nVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy\ndXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4\nNCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH\nBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr\n/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV\nHQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn\nADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl\nCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==\n-----END CERTIFICATE-----\n\nNAVER Global Root Certification Authority\n=========================================\n-----BEGIN CERTIFICATE-----\nMIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG\nA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD\nDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4\nNDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT\nUyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb\nUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW\n+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7\nXNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2\naacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4\nYb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z\nVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B\nA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai\ncdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy\nYhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV\nHQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB\nAf8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK\n21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB\njCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx\nhYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg\nE34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH\nD8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ\nA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY\nqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG\nI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg\nkpzNNIaRkPpkUZ3+/uul9XXeifdy\n-----END CERTIFICATE-----\n\nAC RAIZ FNMT-RCM SERVIDORES SEGUROS\n===================================\n-----BEGIN CERTIFICATE-----\nMIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF\nUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy\nNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4\nMTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt\nUkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB\nQyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA\nBPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2\nLEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG\nSM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD\nzBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c=\n-----END CERTIFICATE-----\n\nGlobalSign Root R46\n===================\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV\nBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv\nb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX\nBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es\nCVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/\nr6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje\n2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt\nbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj\nK8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4\n12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on\nccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls\neVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9\nvXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM\nBQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg\nJuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy\ngxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92\nCC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm\nOUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq\nJZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye\nqiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz\nnxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7\nDEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3\nQEUxeCp6\n-----END CERTIFICATE-----\n\nGlobalSign Root E46\n===================\n-----BEGIN CERTIFICATE-----\nMIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT\nAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg\nRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV\nBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq\nhkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB\njtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj\nQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL\ngLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk\nvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+\nCAezNIm8BZ/3Hobui3A=\n-----END CERTIFICATE-----\n\nGLOBALTRUST 2020\n================\n-----BEGIN CERTIFICATE-----\nMIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx\nIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT\nVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh\nBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy\nMDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi\nD59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO\nVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM\nCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm\nfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA\nA1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR\nJitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG\nDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU\nclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ\nmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud\nIwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA\nVC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw\n4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9\niuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS\n8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2\nHcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS\nvTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918\noa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF\nYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl\ngqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==\n-----END CERTIFICATE-----\n\nANF Secure Server Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4\nNzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv\nbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg\nQ0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw\nMQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw\nEgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz\nBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv\nT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv\nB2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse\nzx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM\nVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j\n7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z\nJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe\n8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO\nHj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj\no1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E\nBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ\nUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx\nj6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt\ndD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM\n5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb\n5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54\nEX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H\nhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy\ng77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3\nr5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=\n-----END CERTIFICATE-----\n\nCertum EC-384 CA\n================\n-----BEGIN CERTIFICATE-----\nMIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ\nTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy\ndGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2\nMDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh\ndGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx\nGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq\nvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn\niBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo\nADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0\nQoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=\n-----END CERTIFICATE-----\n\nCertum Trusted Root CA\n======================\n-----BEGIN CERTIFICATE-----\nMIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG\nEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g\nQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew\nHhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY\nQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p\nfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52\nHO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2\nfJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt\ng/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4\nNboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk\nfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ\nP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY\nnjYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK\nHRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1\nvALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL\nLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s\nALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K\nh2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8\nCYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA\n4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo\nWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj\n6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT\nOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck\nbxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb\n-----END CERTIFICATE-----\n\nTunTrust Root CA\n================\n-----BEGIN CERTIFICATE-----\nMIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG\nA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj\ndHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw\nNDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD\nZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz\n2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b\nbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7\nNegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd\ngjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW\nVSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f\nTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ\njuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas\nDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS\nVXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI\n04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0\n90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl\n0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd\nAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY\nYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp\nadbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x\nxBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP\njCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM\nMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z\nZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r\nAZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=\n-----END CERTIFICATE-----\n\nHARICA TLS RSA Root CA 2021\n===========================\n-----BEGIN CERTIFICATE-----\nMIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG\nEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\ncyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz\nOFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl\nbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB\nIFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN\nJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu\na2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y\nUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K\n5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv\ndmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR\n0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH\nGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm\nhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ\nCPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE\nAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU\nEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq\nQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD\nQpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR\nj88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5\nvZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0\nqPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6\nAlfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/\nPFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn\nkf3/W9b3raYvAwtt41dU63ZTGI0RmLo=\n-----END CERTIFICATE-----\n\nHARICA TLS ECC Root CA 2021\n===========================\n-----BEGIN CERTIFICATE-----\nMIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH\nUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD\nQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX\nDTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj\nIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv\nb3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l\nAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b\nECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW\n0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi\nrcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw\nCZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps\n-----END CERTIFICATE-----\n\nAutoridad de Certificacion Firmaprofesional CIF A62634068\n=========================================================\n-----BEGIN CERTIFICATE-----\nMIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA\nBgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\nMjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw\nQAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB\nNjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD\nUtd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P\nB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY\n7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH\nECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI\nplD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX\nMbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX\nLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK\nbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU\nvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud\nDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w\ngZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j\nb20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A\nbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL\n4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb\nLIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il\nI45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP\ncjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA\nLI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A\nlun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH\n9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf\nNIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE\nZycPvEJdvSRUDewdcAZfpLz6IHxV\n-----END CERTIFICATE-----\n\nvTrus ECC Root CA\n=================\n-----BEGIN CERTIFICATE-----\nMIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE\nBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS\nb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa\nBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw\nEAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c\nToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n\nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO\nBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT\nQJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL\nYgmRWAD5Tfs0aNoJrSEGGJTO\n-----END CERTIFICATE-----\n\nvTrus Root CA\n=============\n-----BEGIN CERTIFICATE-----\nMIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG\nA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv\nb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG\nA1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots\nSKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI\nZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF\nXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA\nYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70\nkLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2\nAXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu\n/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu\n1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO\n9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg\nscasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC\nAgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd\nnxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr\njld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4\n8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn\nxDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg\nicEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4\nsEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW\nnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc\nSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H\nl3s=\n-----END CERTIFICATE-----\n\nISRG Root X2\n============\n-----BEGIN CERTIFICATE-----\nMIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV\nUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT\nUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT\nMSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS\nRyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H\nttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb\nd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF\ncP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5\nU6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn\n-----END CERTIFICATE-----\n\nHiPKI Root CA - G1\n==================\n-----BEGIN CERTIFICATE-----\nMIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG\nEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ\nIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT\nAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg\nUm9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0\no9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k\nwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE\nYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA\nGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd\nhSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj\n1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4\n9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/\nVm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF\n8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD\nAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi\n7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl\ntJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE\nwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q\nJNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv\n5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz\njLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg\nhUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb\nyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/\nyPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==\n-----END CERTIFICATE-----\n\nGlobalSign ECC Root CA - R4\n===========================\n-----BEGIN CERTIFICATE-----\nMIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i\nYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i\nYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW\nymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E\nBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI\nKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg\nUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm\n-----END CERTIFICATE-----\n\nGTS Root R1\n===========\n-----BEGIN CERTIFICATE-----\nMIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV\nUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg\nUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE\nChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\nf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0\nxlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w\nB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW\nnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk\n9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq\nkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A\nK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX\nV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW\ncfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD\nggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe\nQkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi\nClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar\nJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci\nNuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me\nLMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF\nfbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+\n7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3\nFL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3\ngm3c\n-----END CERTIFICATE-----\n\nGTS Root R2\n===========\n-----BEGIN CERTIFICATE-----\nMIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV\nUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg\nUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE\nChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\nCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl\ne3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb\na96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS\n+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M\nkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG\nr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q\nS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV\nJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL\ndWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD\nggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8\n0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh\nswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel\n/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn\njWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5\n9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M\n7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8\n0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR\nWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW\nHYbL\n-----END CERTIFICATE-----\n\nGTS Root R3\n===========\n-----BEGIN CERTIFICATE-----\nMIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi\nMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw\nHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ\nR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO\nPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA\nMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq\nEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT\nL818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV\n11RZt+cRLInUue4X\n-----END CERTIFICATE-----\n\nGTS Root R4\n===========\n-----BEGIN CERTIFICATE-----\nMIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi\nMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw\nHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ\nR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO\nPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\nhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA\nMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1\nPsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C\nr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh\n4rsUecrNIdSUtUlD\n-----END CERTIFICATE-----\n\nTelia Root CA v2\n================\n-----BEGIN CERTIFICATE-----\nMIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT\nAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2\nMjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK\nDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI\nhvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7\n6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q\n9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn\npNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl\ntI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW\n5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr\nRBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E\nBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4\nM0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau\nBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W\nxy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD\nVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ\n8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5\ntFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H\neW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C\ny748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC\nQMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15\nh2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70\nsz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9\nxnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ\nraVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=\n-----END CERTIFICATE-----\n\nD-TRUST BR Root CA 1 2020\n=========================\n-----BEGIN CERTIFICATE-----\nMIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE\nRTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy\nMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV\nBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG\nByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7\ndPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu\nQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t\nMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu\nbmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj\ndG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP\nPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD\nAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom\nAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87\n-----END CERTIFICATE-----\n\nD-TRUST EV Root CA 1 2020\n=========================\n-----BEGIN CERTIFICATE-----\nMIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE\nRTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy\nMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV\nBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG\nByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8\nZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ\nraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL\nMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu\nbmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj\ndG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP\nPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD\nAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR\nAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW\n-----END CERTIFICATE-----\n\nDigiCert TLS ECC P384 Root G5\n=============================\n-----BEGIN CERTIFICATE-----\nMIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV\nUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4\nNCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx\nFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg\nUm9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd\nlHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj\nn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB\n/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds\nJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx\nAJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA==\n-----END CERTIFICATE-----\n\nDigiCert TLS RSA4096 Root G5\n============================\n-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG\nEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0\nMDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV\nUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2\nIFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8\n7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU\nAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces\ntyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa\nzOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV\nDdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q\nTXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy\nz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/\nMZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk\nwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E\nFgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw\nGXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN\nlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN\nMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/\nu4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G\nOUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh\n47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU\nFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ\nyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP\nbEtoL8pU9ozaMv7Da4M/OMZ+\n-----END CERTIFICATE-----\n\nCertainly Root R1\n=================\n-----BEGIN CERTIFICATE-----\nMIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE\nBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN\nMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy\ndGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O\n5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl\n8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl\nDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI\nXsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN\nKPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ\nAjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb\nrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1\nVwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS\np6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\nDgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz\nHQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d\n8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v\nMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB\nGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+\ngjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH\nJBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7\nfpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw\nx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S\nX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8=\n-----END CERTIFICATE-----\n\nCertainly Root E1\n=================\n-----BEGIN CERTIFICATE-----\nMIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV\nUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0\nMDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu\nbHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4\nfxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9\nYBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw\nDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E\nAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8\nrgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR\n-----END CERTIFICATE-----\n\nSecurity Communication ECC RootCA1\n==================================\n-----BEGIN CERTIFICATE-----\nMIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD\nVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t\ndW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL\nMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV\nBAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo\n5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW\nBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK\nBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L\nsnNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e\nN9k=\n-----END CERTIFICATE-----\n\nBJCA Global Root CA1\n====================\n-----BEGIN CERTIFICATE-----\nMIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG\nEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK\nQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG\nA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD\nDBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm\nCL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS\nsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn\nP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW\nyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj\neulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn\nMoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b\nOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh\nGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK\nH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB\nAAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G\nA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4\nYRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ\ndMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8\n60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh\nTaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW\n4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp\nGQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx\n4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps\n3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S\nSPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI=\n-----END CERTIFICATE-----\n\nBJCA Global Root CA2\n====================\n-----BEGIN CERTIFICATE-----\nMIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD\nTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg\nR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE\nBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC\nSkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl\nSR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK\n/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI\n1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8\nW9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g\nUXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==\n-----END CERTIFICATE-----\n\nSectigo Public Server Authentication Root E46\n=============================================\n-----BEGIN CERTIFICATE-----\nMIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH\nQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2\nZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5\nWjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0\naWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr\ngQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0\nNSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud\nDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH\nlAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U\nSAGKcw==\n-----END CERTIFICATE-----\n\nSectigo Public Server Authentication Root R46\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG\nEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT\nZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1\nOTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T\nZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3\nDQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k\n1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf\nGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP\nFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu\nZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz\nYw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A\nwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF\nplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ\nEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW\n6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI\nIUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c\nmTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp\nE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4\nexqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M\n0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI\n84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m\npFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd\nVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b\nE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm\nJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL\n-----END CERTIFICATE-----\n\nSSL.com TLS RSA Root CA 2022\n============================\n-----BEGIN CERTIFICATE-----\nMIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG\nEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg\nUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC\nVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv\nb3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u\n9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y\n7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac\noOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M\nR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG\nD6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW\nTO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk\n8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq\ng+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk\n7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud\nEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu\nN+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt\nhEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN\nj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by\niB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU\no3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo\nENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib\nMOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi\nvRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7\nP0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0\n9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=\n-----END CERTIFICATE-----\n\nSSL.com TLS ECC Root CA 2022\n============================\n-----BEGIN CERTIFICATE-----\nMIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV\nUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v\ndCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx\nGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg\nQ0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy\nJGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1\n5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7\n81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG\nMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w\n7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5\nZn6g6g==\n-----END CERTIFICATE-----\n\nAtos TrustedRoot Root CA ECC TLS 2021\n=====================================\n-----BEGIN CERTIFICATE-----\nMIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB\ndG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD\nVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg\nVHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT\nAkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K\nDP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS\nb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX\nNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+\nuDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY\na3cpetskz2VAv9LcjBHo9H1/IISpQuQo\n-----END CERTIFICATE-----\n\nAtos TrustedRoot Root CA RSA TLS 2021\n=====================================\n-----BEGIN CERTIFICATE-----\nMIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD\nDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw\nCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0\nb3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV\nBAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB\nl01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG\nvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK\nZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt\n0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK\nPNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY\nsluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY\nBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+\nrrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa\nfJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/\nBAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G\nCSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS\n4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl\nQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX\nAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G\nslA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt\nafcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q\nTFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj\n1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l\nPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W\nHYMfRsCbvUOZ58SWLs5fyQ==\n-----END CERTIFICATE-----\n\nTrustAsia Global Root CA G3\n===========================\n-----BEGIN CERTIFICATE-----\nMIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG\nA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM\nG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw\nMTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu\nMSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA\nA4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz\nlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ\nQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V\nP68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag\ndB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm\n9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc\nD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg\nWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea\nmseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF\nTIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj\n7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E\nBAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1\nD/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T\nG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj\nduMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl\ncHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys\n+TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli\n2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y\naFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS\nZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR\nJQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH\n-----END CERTIFICATE-----\n\nTrustAsia Global Root CA G4\n===========================\n-----BEGIN CERTIFICATE-----\nMIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE\nBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry\ndXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa\nMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw\nIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi\nAATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8\nm7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF\nMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/\npDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA\nbbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk\ndUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==\n-----END CERTIFICATE-----\n\nCommScope Public Trust ECC Root-01\n==================================\n-----BEGIN CERTIFICATE-----\nMIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE\nBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz\ndCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT\nAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg\nRUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx\neP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot\n6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\nA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2\nJpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW\npDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE=\n-----END CERTIFICATE-----\n\nCommScope Public Trust ECC Root-02\n==================================\n-----BEGIN CERTIFICATE-----\nMIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE\nBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz\ndCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT\nAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg\nRUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M\nMDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE\nSgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\nA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9\nUj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7\n3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag==\n-----END CERTIFICATE-----\n\nCommScope Public Trust RSA Root-01\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG\nA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU\ncnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV\nBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1\nc3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft\nnYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6\nuUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq\nihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs\nvCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c\nZip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif\nBSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9\nlLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo\nKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH\n+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4\n5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6\nNWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM\n3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck\njXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf\nFoom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W\nNyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+\no/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/\noAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc\n1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM\n6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw\n-----END CERTIFICATE-----\n\nCommScope Public Trust RSA Root-02\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG\nA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU\ncnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV\nBAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1\nc3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V\nrCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx\n7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC\ne5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W\nWy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp\nM9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf\nhs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr\neyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE\nVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t\nVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx\ncJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB\nKCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF\n1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa\nMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd\ngSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O\nHG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm\nYWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr\ndVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ\niRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN\nlM47ni3niAIi9G7oyOzWPPO5std3eqx7\n-----END CERTIFICATE-----\n\nTelekom Security TLS ECC Root 2020\n==================================\n-----BEGIN CERTIFICATE-----\nMIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE\nRTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl\na29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz\nNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg\nR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG\nSM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1\n2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC\nMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ\nMo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU\nga/sf+Rn27iQ7t0l\n-----END CERTIFICATE-----\n\nTelekom Security TLS RSA Root 2023\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG\nEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU\nZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy\nNzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp\ndHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC\nKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP\nGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx\nUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo\nl8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9\nFIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v\nzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg\nrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML\nKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S\nWWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV\nHQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2\np5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+\nsVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp\nkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy\n/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4\nmZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz\naL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa\noqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8\nwPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE\nHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0\no82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=\n-----END CERTIFICATE-----\n\nFIRMAPROFESIONAL CA ROOT-A WEB\n==============================\n-----BEGIN CERTIFICATE-----\nMIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF\nUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4\nMScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2\nWhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h\nbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM\nIENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6\niMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg\nst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD\nY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB\n/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL\ncFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ\npYXFuXqUPoeovQA=\n-----END CERTIFICATE-----\n\nTWCA CYBER Root CA\n==================\n-----BEGIN CERTIFICATE-----\nMIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG\nEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB\nIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG\nEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB\nIENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s\nTs6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh\nV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT\no0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT\nNq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK\n/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH\nIuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM\nfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF\n2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR\nwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO\nBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83\nQOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB\nAGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN\nc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x\nX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR\nIG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq\n/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R\nFxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe\nPm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv\nIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl\nIhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X\n-----END CERTIFICATE-----\n\nSecureSign Root CA12\n====================\n-----BEGIN CERTIFICATE-----\nMIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT\nZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ\nBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU\nU2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3\nemhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc\nJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl\nfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF\nEaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef\nNzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC\nAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi\nLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce\nmik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS\nvWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga\naaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==\n-----END CERTIFICATE-----\n\nSecureSign Root CA14\n====================\n-----BEGIN CERTIFICATE-----\nMIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG\nA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT\nZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ\nBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU\nU2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh\n1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn\nbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb\n1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa\n/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE\nkJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx\njVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz\nju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0\ndFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY\nAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB\no0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq\nYR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E\nrX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA\nymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds\nHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG\nFrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q\nnsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/\nOfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa\nOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO\npygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN\neLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S\n-----END CERTIFICATE-----\n\nSecureSign Root CA15\n====================\n-----BEGIN CERTIFICATE-----\nMIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE\nBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1\ncmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV\nBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj\ndXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G\ndCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB\n2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J\nfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ\nSwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=\n-----END CERTIFICATE-----\n\nD-TRUST BR Root CA 2 2023\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG\nEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg\nMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT\nBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT\ncfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z\nsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ\nWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6\n++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL\nQyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv\nx9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV\nMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX\n/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9\nCZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC\nMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y\nXzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr\nd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv\nU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4\nnj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij\nYQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff\n/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP\npz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB\nWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/\n5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt\nn/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA==\n-----END CERTIFICATE-----\n\nTrustAsia TLS ECC Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMwWDELMAkGA1UE\nBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMTGVRy\ndXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBY\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAG\nA1UEAxMZVHJ1c3RBc2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/\npVs/AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDpguMqWzJ8\nS5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAwDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49\nBAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15K\neAIxAKORh/IRM4PDwYqROkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ==\n-----END CERTIFICATE-----\n\nTrustAsia TLS RSA Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEMBQAwWDELMAkG\nA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMT\nGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2\nWjBYMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEi\nMCAGA1UEAxMZVHJ1c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+NmDQDIPN\nlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJQ1DNDX3eRA5gEk9bNb2/\nmThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fk\nzv93uMltrOXVmPGZLmzjyUT5tUMnCE32ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYo\nzza/+lcK7Fs/6TAWe8TbxNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyr\nz2I8sMeXi9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQUNoy\nIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+jTnhMmCWr8n4uIF6C\nFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DTbE3txci3OE9kxJRMT6DNrqXGJyV1\nJ23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnT\nq1mt1tve1CuBAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZ\nylomkadFK/hTMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3\nRz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4iqME3mmL5Dw8\nveWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt7DlK9RME7I10nYEKqG/odv6L\nTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHx\ntlotJnMnlvm5P1vQiJ3koP26TpUJg3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp\n27RIGAAtvKLEiUUjpQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87q\nqA8MpugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongPXvPKnbwb\nPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIweSsCI3zWQzj8C9GRh3sfI\nB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNz\nFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy323imttUQ/hHWKNddBWcwauwxzQ=\n-----END CERTIFICATE-----\n\nD-TRUST EV Root CA 2 2023\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG\nEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg\nMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT\nBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1\nsJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/\nMHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf\nvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM\nlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3\nYG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910\n7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo\nnMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa\nQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF\nAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC\nMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y\nXzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS\nMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2\nQHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD\nUmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V\n4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo\ndNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi\nTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi\nS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/\nHxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L\n+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==\n-----END CERTIFICATE-----\n\nSwissSign RSA TLS Root CA 2022 - 1\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UEAxMiU3dpc3NTaWduIFJTQSBU\nTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgxMTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJ\nBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0Eg\nVExTIFJvb3QgQ0EgMjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmji\nC8NXvDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7LCTLf5Im\ngKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX5XH8irCRIFucdFJtrhUn\nWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyEEPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlf\nGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36q\nOTw7D59Ke4LKa2/KIj4x0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLO\nEGrOyvi5KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM0ZPl\nEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shdOxtYk8EXlFXIC+OC\neYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrtaclXvyFu1cvh43zcgTFeRc5JzrBh3\nQ4IgaezprClG5QtO+DdziZaKHG29777YtvTKwP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQAB\no2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow\n4UD2p8P98Q+4DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL\nBQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO310aewCoSPY6W\nlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgzHqp41eZUBDqyggmNzhYzWUUo\n8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQiJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zp\ny1FVCypM9fJkT6lc/2cyjlUtMoIcgC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3Cjlvr\nzG4ngRhZi0Rjn9UMZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6M\nOuhFLhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJpzv1/THfQ\nwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/TdAo9QAwKxuDdollDruF/U\nKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0n\nhzck5npgL7XTgwSqT0N1osGDsieYK7EOgLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rw\ntnu64ZzZ\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_de.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"de_DE\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>Tipp: Klicken Sie auf die %1-Zellen, um sie umzubenennen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>Keine Elemente ausgewählt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>Markieren Sie eine oder mehrere Zeilen, um sie für die Verarbeitung auszuwählen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Sammelbearbeitung nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>Die Sammelbearbeitung von Kategorien ist nicht verfügbar, solange der Nur-Umbenennen-Modus für Bilder aktiv ist.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Markieren Sie eine oder mehrere Zeilen, um deren Kategorien zu bearbeiten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Vorschau</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Prüfen und bestätigen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Alle auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Markierte auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Ausgewählte bearbeiten...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Unterkategorie-Ordner erstellen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Probelauf (nur Vorschau, keine Dateien verschieben)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Bilddateien nicht kategorisieren (nur umbenennen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Dokumentdateien nicht kategorisieren (nur umbenennen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Bestätigen und verarbeiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Später fortsetzen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Diese Änderung rückgängig machen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Schließen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Markieren Sie hervorgehobene Zeilen zur Verarbeitung (Strg+Leertaste).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Wenden Sie Kategorie-/Unterkategorie-Werte auf die markierten Zeilen an.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>Verarbeiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>Datei</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Typ</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Vorgeschlagener Dateiname</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Kategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Unterkategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Status</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Geplantes Ziel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Verschoben</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Umbenannt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Umbenannt und verschoben</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Übersprungen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>Nicht ausgewählt</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[STOPP] Analyse wird nach dem aktuellen Element beendet.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Bildanalyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Dokumentanalyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Kategorisierung</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Ordner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Bild</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Dokument</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>Datei</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Typ</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Phase %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>Ausstehend</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>In Bearbeitung</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Abgeschlossen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>Verarbeitet 0/0  |  In Bearbeitung: 0  |  Ausstehend: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>Verarbeitet %1/%2  |  In Bearbeitung: %3  |  Ausstehend: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Dateien analysieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Aktivitätsprotokoll</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>Benutzerdefinierte OpenAI-kompatible API</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>z. B. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>z. B. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Anzeigen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Anzeigename</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Beschreibung</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>Basis-URL oder Endpunkt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Modell</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>API-Schlüssel (optional)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Geben Sie eine Basis-URL ein (z. B. http://localhost:1234/v1) oder einen vollständigen Endpunkt für /chat/completions.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>Benutzerdefiniertes lokales LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Durchsuchen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Anzeigename</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Beschreibung</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>Modelldatei (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>.gguf-Modell auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>GGUF-Modelle (*.gguf);;Alle Dateien (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Vorschau Probelauf</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>Von</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>Nach</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Schließen</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>LLM-Modus auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>LLM-Modus auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Größeres lokales Modell. Auf der CPU langsamer, mit GPU-Beschleunigung jedoch deutlich besser.\nUnterstützt: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Empfohlen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>Kleineres lokales Modell, das auch auf CPUs schnell arbeitet. Gut für leichte lokale Nutzung.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Altes Modell wird für bestehende Downloads beibehalten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (Google AI Studio API-Schlüssel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Verwenden Sie Googles Gemini-Modelle mit Ihrem AI Studio API-Schlüssel (Internet erforderlich).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Anzeigen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Gemini-API-Schlüssel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>z. B. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Modell</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>Ihr Schlüssel wird lokal in der Konfigurationsdatei dieses Geräts gespeichert.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Gemini-API-Schlüssel abrufen&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (OpenAI API-Schlüssel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>Verwenden Sie Ihren eigenen OpenAI API-Schlüssel, um auf ChatGPT-Modelle zuzugreifen (Internet erforderlich).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>OpenAI-API-Schlüssel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>z. B. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;OpenAI-API-Schlüssel abrufen&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>Benutzerdefinierte OpenAI-kompatible API (erweitert)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>Verwenden Sie OpenAI-kompatible Endpunkte wie LM Studio oder Ollama (lokal oder remote).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Hinzufügen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Bearbeiten…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Löschen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>Benutzerdefiniertes lokales LLM (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>Downloads</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>Download</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Bildanalyse-Modelle (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Laden Sie die für die Bildanalyse erforderlichen visuellen LLM-Dateien herunter.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (Textmodell)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (Vision-Encoder)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Wählen Sie ein benutzerdefiniertes Modell aus oder fügen Sie eines hinzu.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Benutzerdefiniertes Modell ausgewählt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Auswahl bereit.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Wählen Sie einen benutzerdefinierten API-Endpunkt aus oder fügen Sie einen hinzu.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>Benutzerdefinierte API ausgewählt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT verwendet Ihren API-Schlüssel und Ihr Modell.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Geben Sie Ihren OpenAI API-Schlüssel und Ihr Modell ein, um fortzufahren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini verwendet Ihren API-Schlüssel und Ihr Modell.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Geben Sie Ihren Gemini API-Schlüssel und Ihr Modell ein, um fortzufahren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Modell bereit.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>Download fortsetzen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Teilweiser Download erkannt. Sie können fortsetzen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>Download erforderlich.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Nicht unterstützte LLM-Auswahl.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>Umgebungsvariable für die Download-URL fehlt (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>Heruntergeladenes Modell löschen?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>Heruntergeladenes Modell %1 löschen?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>Heruntergeladenes Modell konnte nicht gelöscht werden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>Heruntergeladenes Modell gelöscht.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>Kein heruntergeladenes Modell zum Löschen gefunden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>Remote-URL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Lokaler Pfad</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Dateigröße</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Dateigröße: unbekannt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Benutzerdefiniertes Modell löschen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>'%1' aus Ihren benutzerdefinierten LLMs entfernen? Dadurch wird die Datei auf der Festplatte nicht gelöscht.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Benutzerdefinierte API löschen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>'%1' aus Ihrer Liste benutzerdefinierter APIs entfernen? Dies hat keine Auswirkungen auf den Server.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>Umgebungsvariable für die Download-URL fehlt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>Download läuft…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>Download abgeschlossen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>Download abgebrochen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>Download-Fehler: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Datei-Explorer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Ordner auswählen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>Ordner %1 geladen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Analyse abgebrochen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Ordner ausgewählt: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Einheitlicher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Ausführlicher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>Ordner neu kategorisieren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Dieser Ordner wurde im Modus %1 kategorisiert. Möchten Sie ihn jetzt im Modus %2 neu kategorisieren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Neu kategorisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Beibehalten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>Zurücksetzen der zwischengespeicherten Kategorisierung für diesen Ordner fehlgeschlagen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>Download erforderlich</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>Die Bildanalyse erfordert visuelle LLM-Dateien. Jetzt herunterladen?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>OK</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Analysiere…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Ordner analysieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Bereit</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Letzten Durchlauf rückgängig machen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Dadurch wird versucht, Dateien basierend auf dem letzten Durchlauf an ihre ursprünglichen Speicherorte zurückzuverschieben.\n\nPlandatei: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>%1 Datei(en) wiederhergestellt. %2 übersprungen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Rückgängig abgeschlossen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>Vielen Dank, dass du AI File Sorter verwendest! Du hast bisher %1 Dateien kategorisiert. Ich, der Autor, hoffe wirklich, dass dir die App geholfen hat.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter erfordert Hunderte Stunden Entwicklungsarbeit, Funktionsarbeit, Supportantworten und laufende Kosten wie Server sowie Infrastruktur für Remote-Modelle. Wenn die App Ihnen Zeit spart oder einen Mehrwert bietet, ziehen Sie bitte eine Unterstützung in Betracht, damit sie weiter verbessert werden kann.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>Bereits gespendet? Klicken Sie auf „Ich habe bereits gespendet“, um Ihren Spendencode einzugeben und diese Erinnerung dauerhaft zu deaktivieren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Spenden, um den Spendendialog dauerhaft auszublenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Ich bin mir noch nicht sicher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>Ich habe bereits gespendet</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Spendencode</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Geben Sie den nach Ihrer Spende erzeugten Spendencode ein.\nEin gültiger Code blendet den Spendendialog dauerhaft aus.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Ungültiger Spendencode</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>Der Spendencode ist ungültig. Bitte versuchen Sie es erneut oder klicken Sie auf Abbrechen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Spendenseite öffnen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>Der Browser konnte nicht automatisch geöffnet werden.\nBitte öffnen Sie diesen Link manuell:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Ordner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>Datei</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIV] Bereits kategorisierte Einträge:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[FERTIG] Keine Dateien zu kategorisieren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[WARTESCHLANGE] Elemente warten auf Kategorisierung:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[SCAN] Durchsuche %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[VERARBEITUNG] Die KI macht ihre Magie...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISION] Bildbatch %1/%2 wird decodiert (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>Bildanalyse auf CPU umschalten?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>Der Bildanalyse ist der GPU-Speicher ausgegangen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>Stattdessen auf der CPU erneut versuchen? Bei Abbrechen wird die visuelle Analyse übersprungen und auf dateinamenbasierte Kategorisierung zurückgegriffen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[VISION-FEHLER] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Visuelle Analyse wird auf CPU umgeschaltet.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Visuelle Analyse deaktiviert; Rückfall auf Dateinamen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISION] Verwende zwischengespeicherten Vorschlag für %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISION] Analysiere %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] GPU-Speicherproblem erkannt. Es wird auf CPU umgeschaltet.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Visuelle Analyse für die verbleibenden Bilder deaktiviert.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[DOK-FEHLER] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] Verwende zwischengespeicherten Vorschlag für %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] Analysiere %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[SORTIEREN] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analyse wird abgebrochen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>Lokale KI auf CPU umschalten?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>Das lokale Modell hat einen GPU-Fehler festgestellt oder es ist der Speicher ausgegangen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>Stattdessen auf der CPU erneut versuchen? Abbrechen beendet diese Analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] GPU-Rückfall auf CPU abgelehnt. Analyse wird abgebrochen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[WARNUNG] GPU-Beschleunigung konnte nicht initialisiert werden. Fortsetzung auf der CPU (langsamer).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[WARNUNG] %1 wird neu kategorisiert: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Ausgewählte Elemente bearbeiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Leer lassen, um vorhandene Werte beizubehalten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Kategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Unterkategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>Über %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>Über</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Danksagungen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>Über die AGPL-Lizenz</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter wird unter der GNU Affero General Public License v3.0 vertrieben.&lt;br&gt;&lt;br&gt;Den vollständigen Quellcode finden Sie unter &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Eine vollständige Lizenzkopie liegt bei und ist online verfügbar unter &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Automatisch</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (Ziel: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>GPU über Vulkan nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>GPU über CUDA nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>GPU über Metal nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>GPU-Initialisierung fehlgeschlagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Standardmodell: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Kategorisierung wird gemessen (Aufwärmen + %1 Lauf/Läufe)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Dokumentanalyse wird gemessen (Aufwärmen + %1 Lauf/Läufe)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Kategorisierung: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>abgeschlossen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>fehlgeschlagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Aufwärmen: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Initialisierung: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Pro Element (Median von %1): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Läufe pro Element: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Details: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Backend verwendet: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Dokumentanalyse: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>Modell konnte nicht geladen werden: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>optimal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>akzeptabel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>ziemlich lang</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>k. A.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Ergebnis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Kategorisierungsgeschwindigkeit: nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Dokumentanalysegeschwindigkeit: nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Kategorisierungsgeschwindigkeit: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Dokumentanalysegeschwindigkeit: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Bildanalysegeschwindigkeit: nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Bildanalysegeschwindigkeit: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>Empfohlene lokale LLM-Auswahl: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>Sie können LLMs unter Einstellungen -&gt; LLM auswählen wechseln</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Kompatibilitäts-Benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Führt eine kurze Leistungsprüfung aus, um abzuschätzen, wie Bildanalyse, Dokumentanalyse und Dateikategorisierung auf diesem System funktionieren werden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Es wird empfohlen, vor dem Ausführen dieses Tests alle CPU- und GPU-intensiven Anwendungen zu schließen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Benchmark starten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>Diesen Dialog nicht automatisch anzeigen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Benchmark stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Schließen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>Noch keine vorherigen Ergebnisse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Letzte Ausführung: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Vorherige Ergebnisse:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>Keine heruntergeladenen LLM-Dateien erkannt. Laden Sie ein Kategorisierungs- oder visuelles Modell herunter, um den Benchmark auszuführen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Starte Systemkompatibilitätsprüfung...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>CPU-Threads erkannt: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>GPU-Backend-Override: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal verfügbar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>ja</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>nein</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>GPU-Speicherzuweisung (Metal): %1 frei / %2 gesamt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>GPU-Speicherzuweisung (Metal): nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA verfügbar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>CUDA-Speicher (zuweisbar): %1 frei / %2 gesamt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (Gerät gesamt: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>GPU-Speicherzuweisung (Vulkan): %1 frei / %2 gesamt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>GPU-Speicherzuweisung (Vulkan): nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>Die Einrichtung des temporären Verzeichnisses ist fehlgeschlagen; das Erstellen der Benchmark-Beispieldatei kann fehlschlagen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>Keine Standardmodelle heruntergeladen; Kategorisierung und Dokumentenprüfungen werden übersprungen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Standardmodelle erkannt: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark gestoppt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Bildanalyse-Test wird ausgeführt...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>nicht verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Bildanalyse: übersprungen (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Bildanalyse: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Zeit: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU durch Backend-Override deaktiviert</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Backend verwendet (Bildanalyse): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark fehlgeschlagen: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] Der Benchmark stoppt nach dem aktuellen Schritt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Fehler</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>Lokales LLM (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>Lokales LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>Unterstütze %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Erforderliches Update verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>Ein erforderliches Update ist verfügbar. Bitte aktualisieren Sie, um fortzufahren.\nWenn Sie Beenden wählen, wird die Anwendung geschlossen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Jetzt aktualisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Beenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>Optionales Update verfügbar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>Ein optionales Update ist verfügbar. Möchten Sie jetzt aktualisieren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Diese Version überspringen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>Abbrechen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Update wird heruntergeladen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Das Update-Installationsprogramm wird heruntergeladen...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>Das Update-Installationsprogramm konnte nicht vorbereitet werden.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Installationsprogramm bereit</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Beenden Sie die App und starten Sie das Installationsprogramm, um zu aktualisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Beenden und Installationsprogramm starten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>Das Installationsprogramm konnte nicht gestartet werden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>Für dieses Update ist kein Download-Ziel verfügbar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>Update fehlgeschlagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Manuell aktualisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>Whitelist bearbeiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Name:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Kategorien (durch Kommas getrennt):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Unterkategorien (durch Kommas getrennt):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>CUDA Toolkit fehlt</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>Eine kompatible NVIDIA-GPU wurde erkannt, aber das CUDA Toolkit fehlt.\n\nCUDA ist für die GPU-Beschleunigung in dieser Anwendung erforderlich.\n\nMöchten Sie es jetzt herunterladen und installieren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Startfehler</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>CUDA und Vulkan können nicht gleichzeitig aktiviert werden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>GGML-Laufzeit fehlt</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>Die Laufzeit-DLLs des Backends konnten nicht gefunden werden.\nVersucht:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Start fehlgeschlagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>Die Hauptanwendung konnte nicht gestartet werden:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Ordner:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Durchsuchen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Unterkategorien verwenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Unterordner innerhalb jeder Kategorie anlegen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Kategorisierungstyp</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Festlegen, wie strikt die Kategoriebezeichnungen sein sollen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Ausführlicher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Bevorzugt detaillierte Bezeichnungen, auch wenn ähnliche Elemente variieren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Einheitlicher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Bevorzugt konsistente Bezeichnungen für ähnliche Elemente.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Whitelist verwenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Kategorien und Unterkategorien auf die ausgewählte Whitelist beschränken.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Whitelist für diesen Lauf auswählen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Dateien kategorisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Dateien in die Kategorisierung einbeziehen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Ordner kategorisieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Ordner in die Kategorisierung einbeziehen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Unterordner scannen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Dateien in Unterordnern scannen und so behandeln, als wären sie im Hauptordner.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Bilddateien nach Inhalt analysieren (kann langsam sein)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Visuelles LLM auf unterstützte Bilddateien anwenden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Nur Bilddateien verarbeiten (alle anderen Dateien ignorieren)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Nicht-Bilddateien in diesem Lauf ignorieren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Erstellungsdatum des Bildes (falls verfügbar) zum Kategorienamen hinzufügen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Erstellungsdatum des Bildes aus Metadaten an die Kategoriebezeichnung anhängen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Fotodatum und Ort zum Dateinamen hinzufügen (falls verfügbar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>Das Datum stammt aus den EXIF-Metadaten des Fotos. Ortsnamen werden online aus GPS-Koordinaten ermittelt, daher ist für Ortspräfixe eine Netzwerkverbindung erforderlich.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Audio-/Video-Metadaten zum Dateinamen hinzufügen (falls verfügbar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Eingebettete Medientags (z. B. Jahr, Interpret, Album, Titel) verwenden, um vorgeschlagene Audio-/Video-Dateinamen zu erstellen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Umbenennen von Bilddateien anbieten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Vorgeschlagene Dateinamen für Bilddateien anzeigen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Bilddateien nicht kategorisieren (nur umbenennen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Bilddateien nicht kategorisieren und nur umbenennen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Optionen für die Bildanalyse anzeigen oder ausblenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Dokumentdateien nach Inhalt analysieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Dokumentinhalte mit dem ausgewählten LLM zusammenfassen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Nur Dokumentdateien verarbeiten (alle anderen Dateien ignorieren)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Nicht-Dokumentdateien in diesem Lauf ignorieren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Umbenennen von Dokumentdateien anbieten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Vorgeschlagene Dateinamen für Dokumentdateien anzeigen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Dokumentdateien nicht kategorisieren (nur umbenennen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Dokumentdateien nicht kategorisieren und nur umbenennen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Erstellungsdatum des Dokuments (falls verfügbar) zum Kategorienamen hinzufügen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Erstellungsdatum des Dokuments aus Metadaten an die Kategoriebezeichnung anhängen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Optionen für die Dokumentanalyse anzeigen oder ausblenden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Ordner analysieren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>Datei</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Typ</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Kategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Unterkategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Status</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Ordner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Bereit</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Hilfe</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Datei-Explorer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analyse wird abgebrochen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Analysiere…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Kategorie-Whitelists</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Hinzufügen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Bearbeiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Entfernen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>Kann nicht entfernt werden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>Die Standardliste kann nicht entfernt werden.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_es.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"es_ES\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>Consejo: haz clic en las celdas %1 para renombrarlas.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>No hay elementos seleccionados</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>Resalta una o más filas para seleccionarlas para su procesamiento.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Edición masiva no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>La edición masiva de categorías no está disponible mientras el modo de solo renombrar imágenes esté activo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Resalta una o más filas para editar sus categorías.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Vista previa</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Revisar y confirmar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Seleccionar todo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Seleccionar resaltados</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Editar seleccionados...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Crear carpetas de subcategorías</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Prueba (solo vista previa, no mover archivos)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>No categorizar archivos de imagen (solo renombrar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>No categorizar archivos de documentos (solo renombrar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Confirmar y procesar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Continuar más tarde</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Deshacer este cambio</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Cerrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Marca las filas resaltadas para procesarlas (Ctrl+Espacio).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Aplica los valores de categoría/subcategoría a las filas resaltadas.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>Procesar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>Archivo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Nombre de archivo sugerido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Categoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Subcategoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Estado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Destino previsto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Movido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Renombrado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Renombrado y movido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Omitido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>No seleccionado</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[DETENER] El análisis se detendrá después del elemento actual.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Análisis de imágenes</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Análisis de documentos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Categorización</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Imagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Documento</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>Archivo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Etapa %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>Pendiente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>En curso</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Completado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>Procesados 0/0  |  En curso: 0  |  Pendientes: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>Procesados %1/%2  |  En curso: %3  |  Pendientes: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Analizando archivos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Detener análisis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Registro de actividad</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>API personalizada compatible con OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>p. ej. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>p. ej. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Mostrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Nombre para mostrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Descripción</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>URL base o endpoint</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Modelo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>Clave API (opcional)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Introduce una URL base (p. ej. http://localhost:1234/v1) o un endpoint completo de /chat/completions.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>LLM local personalizado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Explorar…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Nombre para mostrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Descripción</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>Archivo del modelo (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>Seleccionar modelo .gguf</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>Modelos GGUF (*.gguf);;Todos los archivos (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Vista previa de la prueba</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>De</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>A</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Cerrar</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>Elegir modo de LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>Seleccionar modo de LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Modelo local más grande. Es más lento en CPU, pero funciona mucho mejor con aceleración por GPU.\nCompatible con: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Recomendado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>Modelo local más pequeño que funciona rápido incluso en CPU. Bueno para un uso local ligero.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Modelo heredado conservado para descargas existentes.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (clave API de Google AI Studio)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Usa los modelos Gemini de Google con tu clave API de AI Studio (se requiere internet).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Mostrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Clave API de Gemini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>p. ej. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Modelo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>Tu clave se guarda localmente en el archivo de configuración de este dispositivo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Obtener una clave API de Gemini&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (clave API de OpenAI)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>Usa tu propia clave API de OpenAI para acceder a los modelos de ChatGPT (se requiere internet).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>Clave API de OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>p. ej. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Obtener una clave API de OpenAI&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>API personalizada compatible con OpenAI (avanzada)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>Usa endpoints compatibles con OpenAI, como LM Studio u Ollama (locales o remotos).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Añadir…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Editar…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Eliminar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>LLM local personalizado (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>Descargas</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>Descargar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Modelos de análisis de imágenes (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Descarga los archivos LLM visuales necesarios para el análisis de imágenes.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (modelo de texto)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (codificador de visión)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Elige o añade un modelo personalizado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Modelo personalizado seleccionado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Selección lista.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Elige o añade un endpoint de API personalizado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>API personalizada seleccionada.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT usará tu clave API y tu modelo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Introduce tu clave API de OpenAI y el modelo para continuar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini usará tu clave API y tu modelo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Introduce tu clave API de Gemini y el modelo para continuar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Modelo listo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>Reanudar descarga</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Descarga parcial detectada. Puedes reanudar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>Descarga requerida.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Selección de LLM no compatible.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>Falta la variable de entorno de la URL de descarga (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>¿Eliminar el modelo descargado?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>¿Eliminar el modelo descargado %1?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>No se pudo eliminar el modelo descargado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>Modelo descargado eliminado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>No se encontró ningún modelo descargado para eliminar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>URL remota</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Ruta local</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Tamaño del archivo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Tamaño del archivo: desconocido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Eliminar modelo personalizado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>¿Quitar '%1' de tus LLM personalizados? Esto no elimina el archivo del disco.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Eliminar API personalizada</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>¿Quitar '%1' de tu lista de API personalizadas? Esto no afecta al servidor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>Falta la variable de entorno de la URL de descarga.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>Descargando…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>Descarga completa.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>Descarga cancelada.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>Error de descarga: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Explorador de archivos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Seleccionar carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>Carpeta %1 cargada</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Análisis cancelado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Carpeta seleccionada: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Más coherente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Más detallada</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>¿Recategorizar la carpeta?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Esta carpeta se categorizó con el modo %1. ¿Quieres recategorizarla ahora con el modo %2?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Recategorizar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Mantener existente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>No se pudo restablecer la categorización en caché para esta carpeta.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>Descarga requerida</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>El análisis de imágenes requiere archivos LLM visuales. ¿Descargarlos ahora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>Aceptar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Detener análisis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Analizando…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Analizar carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Listo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Deshacer la última ejecución</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Esto intentará mover los archivos de vuelta a sus ubicaciones originales según la última ejecución.\n\nArchivo del plan: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>Se restauraron %1 archivo(s). Se omitieron %2.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Reversión completada</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>Gracias por usar AI File Sorter. Has categorizado %1 archivos hasta ahora. Yo, el autor, realmente espero que esta aplicación te haya sido útil.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter requiere cientos de horas de desarrollo, trabajo en funciones, respuestas de soporte y costes continuos como servidores e infraestructura de modelos remotos. Si la aplicación te ahorra tiempo o te aporta valor, considera apoyarla para que pueda seguir mejorando.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>¿Ya has donado? Haz clic en \"Ya he donado\" para introducir tu código de donación y desactivar este recordatorio de forma permanente.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Donar para ocultar permanentemente el cuadro de diálogo de donación</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Aún no estoy seguro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>Ya he donado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Código de donación</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Introduce el código de donación generado después de tu donación.\nUn código válido ocultará permanentemente el cuadro de diálogo de donación.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Código de donación no válido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>El código de donación no es válido. Inténtalo de nuevo o pulsa Cancelar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Abrir página de donación</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>No se pudo abrir el navegador automáticamente.\nAbre este enlace manualmente:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>Archivo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIVO] Elementos ya categorizados:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[LISTO] No hay archivos para categorizar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[COLA] Elementos en espera de categorización:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[ESCANEO] Explorando %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[PROCESO] La IA hace su magia...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISIÓN] Decodificando lote de imágenes %1/%2 (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>¿Cambiar el análisis de imágenes a CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>El análisis de imágenes se quedó sin memoria de GPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>¿Reintentar en la CPU? Cancelar omitirá el análisis visual y volverá a la categorización basada en nombres de archivo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[ERROR-VISIÓN] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Cambiando el análisis visual a la CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Análisis visual desactivado; se vuelve a los nombres de archivo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISIÓN] Usando sugerencia en caché para %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISIÓN] Analizando %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] Se detectó un problema de memoria de GPU. Cambiando a CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Análisis visual desactivado para las imágenes restantes.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[ERROR-DOC] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] Usando sugerencia en caché para %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] Analizando %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[ORDENAR] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Cancelando análisis…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>¿Cambiar la IA local a CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>El modelo local encontró un error de GPU o se quedó sin memoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>¿Reintentar en la CPU? Cancelar detendrá este análisis.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] Se rechazó el cambio de GPU a CPU. Cancelando análisis.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[ADVERTENCIA] No se pudo inicializar la aceleración GPU. Continuando en CPU (más lento).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[ADVERTENCIA] %1 se recategorizará: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Editar elementos seleccionados</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Déjalo vacío para mantener los valores existentes</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Categoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Subcategoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>Acerca de %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>Acerca de</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Créditos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>Acerca de la licencia AGPL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter se distribuye bajo la GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;Puedes acceder al código fuente completo en &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Se incluye una copia completa de la licencia y está disponible en línea en &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (automático)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (automático)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (automático)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Automático</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (objetivo: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>GPU vía Vulkan no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>GPU vía CUDA no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>GPU vía Metal no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>Falló la inicialización de la GPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Modelo predeterminado: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Midiendo la categorización (calentamiento + %1 ejecución(es))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Midiendo el análisis de documentos (calentamiento + %1 ejecución(es))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Categorización: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>completado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>fallido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Calentamiento: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Inicialización: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Por elemento (mediana de %1): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Ejecuciones por elemento: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Detalles: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Backend utilizado: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Análisis de documentos: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>No se pudo cargar el modelo: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>óptimo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>aceptable</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>bastante largo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>n/d</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Resultado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Velocidad de categorización: no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Velocidad de análisis de documentos: no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Velocidad de categorización: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Velocidad de análisis de documentos: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Velocidad de análisis de imágenes: no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Velocidad de análisis de imágenes: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>LLM local recomendado: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>Puedes cambiar los LLM en Configuración -&gt; Seleccionar LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Benchmark de compatibilidad</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Ejecuta una comprobación rápida de rendimiento para estimar cómo funcionarán el análisis de imágenes, el análisis de documentos y la categorización de archivos en tu sistema.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Se recomienda cerrar cualquier aplicación intensiva de CPU y GPU antes de ejecutar esta prueba.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Ejecutar benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>No mostrar automáticamente este diálogo otra vez</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Detener benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Cerrar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>No hay resultados anteriores.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Última ejecución: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Resultados anteriores:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>No se detectaron archivos LLM descargados. Descarga un modelo de categorización o visual para ejecutar el benchmark.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Iniciando la comprobación de compatibilidad del sistema...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>Hilos de CPU detectados: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>Forzado del backend GPU: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal disponible: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>sí</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>no</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>Asignación de memoria GPU (Metal): %1 libres / %2 totales</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>Asignación de memoria GPU (Metal): no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA disponible: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>Memoria CUDA (asignable): %1 libres / %2 totales</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (total del dispositivo: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>Asignación de memoria GPU (Vulkan): %1 libres / %2 totales</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>Asignación de memoria GPU (Vulkan): no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>Falló la configuración del directorio temporal; la creación del archivo de muestra para el benchmark puede fallar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>No se han descargado modelos predeterminados; se omiten la categorización y las comprobaciones de documentos.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Modelos predeterminados detectados: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark detenido.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Ejecutando prueba de análisis de imágenes...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>no disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Análisis de imágenes: omitido (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Análisis de imágenes: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Tiempo: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU deshabilitada por el forzado del backend</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Backend utilizado (análisis de imágenes): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark fallido: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] El benchmark se detendrá después del paso actual.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Error</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>LLM local (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>LLM local</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>Apoya %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Hay una actualización obligatoria disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>Hay una actualización obligatoria disponible. Actualiza para continuar.\nSi eliges salir, la aplicación se cerrará.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Actualizar ahora</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Salir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>Hay una actualización opcional disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>Hay una actualización opcional disponible. ¿Quieres actualizar ahora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Omitir esta versión</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>Cancelar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Descargando actualización</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Descargando el instalador de la actualización...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>No se pudo preparar el instalador de la actualización.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Instalador listo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Cierra la aplicación y ejecuta el instalador para actualizar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Cerrar y ejecutar instalador</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>No se pudo ejecutar el instalador.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>No hay un destino de descarga disponible para esta actualización.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>La actualización falló</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Actualizar manualmente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>Editar lista blanca</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Nombre:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Categorías (separadas por comas):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Subcategorías (separadas por comas):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>Falta el CUDA Toolkit</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>Se detectó una GPU NVIDIA compatible, pero falta el CUDA Toolkit.\n\nCUDA es necesario para la aceleración por GPU en esta aplicación.\n\n¿Quieres descargarlo e instalarlo ahora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Error de inicio</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>No se pueden activar CUDA y Vulkan al mismo tiempo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>Falta el runtime de GGML</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>No se pudieron encontrar las DLL de tiempo de ejecución del backend.\nIntentado:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Error al iniciar</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>No se pudo iniciar el ejecutable principal de la aplicación:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Carpeta:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Explorar…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Usar subcategorías</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Crear subcarpetas dentro de cada categoría.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Tipo de categorización</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Elegir cuán estrictas deben ser las etiquetas de categoría.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Más detallada</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Prioriza etiquetas detalladas aunque elementos similares varíen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Más coherente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Prioriza etiquetas coherentes entre elementos similares.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Usar lista blanca</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Restringir categorías y subcategorías a la lista blanca seleccionada.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Selecciona la lista blanca usada en esta ejecución.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Categorizar archivos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Incluir archivos en la categorización.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Categorizar directorios</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Incluir directorios en la categorización.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Escanear subcarpetas</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Escanear archivos en subcarpetas y tratarlos como si estuvieran en la carpeta principal.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Analizar archivos de imagen por contenido (puede ser lento)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Ejecutar el LLM visual en archivos de imagen compatibles.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Procesar solo archivos de imagen (ignorar cualquier otro archivo)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Ignorar archivos que no sean de imagen en esta ejecución.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Agregar la fecha de creación de la imagen (si está disponible) al nombre de la categoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Agregar la fecha de creación de la imagen desde los metadatos a la etiqueta de la categoría.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Agregar fecha y lugar de la foto al nombre de archivo (si están disponibles)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>La fecha proviene de los metadatos EXIF de la foto. Los nombres de lugares se resuelven en línea a partir de coordenadas GPS, por lo que se requiere acceso a la red para los prefijos de lugar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Agregar metadatos de audio/video al nombre de archivo (si están disponibles)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Usar etiquetas de medios incrustadas (por ejemplo año, artista, álbum, título) para crear nombres de archivo sugeridos de audio/video.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Ofrecer renombrar archivos de imagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Mostrar nombres sugeridos para archivos de imagen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>No categorizar archivos de imagen (solo renombrar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Omitir la categorización de archivos de imagen y solo renombrarlos.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Mostrar u ocultar opciones de análisis de imágenes</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Analizar archivos de documentos por contenido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Resumir el contenido de los documentos con el LLM seleccionado.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Procesar solo archivos de documentos (ignorar cualquier otro archivo)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Ignorar archivos que no sean documentos en esta ejecución.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Ofrecer renombrar archivos de documentos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Mostrar nombres sugeridos para archivos de documentos.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>No categorizar archivos de documentos (solo renombrar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Omitir la categorización de archivos de documentos y solo renombrarlos.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Agregar la fecha de creación del documento (si está disponible) al nombre de la categoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Agregar la fecha de creación del documento desde los metadatos a la etiqueta de la categoría.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Mostrar u ocultar opciones de análisis de documentos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Detener análisis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Analizar carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>Archivo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Categoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Subcategoría</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Estado</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Carpeta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Listo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Ayuda</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Explorador de archivos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Cancelando análisis…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Analizando…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Listas blancas de categorías</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Añadir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Editar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Quitar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>No se puede quitar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>La lista predeterminada no se puede quitar.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_fr.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"fr_FR\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>Astuce : cliquez sur les cellules %1 pour les renommer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>Aucun élément sélectionné</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>Surlignez une ou plusieurs lignes pour les sélectionner pour le traitement.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Modification groupée indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>La modification groupée des catégories n'est pas disponible lorsque le mode de renommage seul des images est actif.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Surlignez une ou plusieurs lignes pour modifier leurs catégories.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Aperçu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Vérifier et confirmer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Tout sélectionner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Sélectionner les lignes surlignées</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Modifier la sélection...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Créer des dossiers de sous-catégories</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Simulation (aperçu uniquement, ne déplace pas les fichiers)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Ne pas catégoriser les fichiers image (renommer uniquement)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Ne pas catégoriser les fichiers de documents (renommer uniquement)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Confirmer et traiter</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Continuer plus tard</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Annuler cette modification</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Fermer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Marquez les lignes surlignées pour le traitement (Ctrl+Espace).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Appliquez les valeurs de catégorie/sous-catégorie aux lignes surlignées.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>Traiter</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>Fichier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Nom de fichier suggéré</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Sous-catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Statut</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Destination prévue</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Déplacé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Renommé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Renommé et déplacé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Ignoré</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>Non sélectionné</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[ARRÊT] L'analyse s'arrêtera après le traitement de l'élément en cours.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Analyse d'image</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Analyse de documents</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Catégorisation</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Image</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Document</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>Fichier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Étape %1 : %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>En attente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>En cours</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Terminé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>Traités 0/0  |  En cours : 0  |  En attente : 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>Traités %1/%2  |  En cours : %3  |  En attente : %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Analyse des fichiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Arrêter l'analyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Journal d'activité</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>API personnalisée compatible OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>p. ex. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>p. ex. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Afficher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Nom d'affichage</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Description</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>URL de base ou point de terminaison</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Modèle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>Clé API (facultative)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Saisissez une URL de base (p. ex. http://localhost:1234/v1) ou un point de terminaison /chat/completions complet.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>LLM local personnalisé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Parcourir…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Nom d'affichage</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Description</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>Fichier modèle (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>Sélectionner un modèle .gguf</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>Modèles GGUF (*.gguf);;Tous les fichiers (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Aperçu de la simulation</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>De</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>Vers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Fermer</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>Choisir le mode LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>Sélectionner le mode LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Modèle local plus grand. Plus lent sur CPU, mais nettement plus performant avec l'accélération GPU.\nPrend en charge : Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Recommandé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>Modèle local plus petit, qui fonctionne rapidement même sur CPU. Bien adapté à un usage local léger.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Modèle hérité conservé pour les téléchargements existants.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (clé API Google AI Studio)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Utilisez les modèles Gemini de Google avec votre clé API AI Studio (connexion Internet requise).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Afficher</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Clé API Gemini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>p. ex. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Modèle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>Votre clé est stockée localement dans le fichier de configuration de cet appareil.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Obtenir une clé API Gemini&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (clé API OpenAI)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>Utilisez votre propre clé API OpenAI pour accéder aux modèles ChatGPT (connexion Internet requise).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>Clé API OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>p. ex. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Obtenir une clé API OpenAI&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>API personnalisée compatible OpenAI (avancée)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>Utilisez des points de terminaison compatibles OpenAI tels que LM Studio ou Ollama (locaux ou distants).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Ajouter…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Modifier…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Supprimer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>LLM local personnalisé (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>Téléchargements</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>Télécharger</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Modèles d'analyse d'images (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Téléchargez les fichiers LLM visuels nécessaires à l'analyse d'images.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (modèle texte)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (encodeur de vision)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Choisissez ou ajoutez un modèle personnalisé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Modèle personnalisé sélectionné.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Sélection prête.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Choisissez ou ajoutez un point de terminaison API personnalisé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>API personnalisée sélectionnée.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT utilisera votre clé API et votre modèle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Saisissez votre clé API OpenAI et votre modèle pour continuer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini utilisera votre clé API et votre modèle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Saisissez votre clé API Gemini et votre modèle pour continuer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Modèle prêt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>Reprendre le téléchargement</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Téléchargement partiel détecté. Vous pouvez reprendre.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>Téléchargement requis.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Sélection de LLM non prise en charge.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>Variable d'environnement de l'URL de téléchargement manquante (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>Supprimer le modèle téléchargé ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>Supprimer le modèle téléchargé %1 ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>Échec de la suppression du modèle téléchargé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>Modèle téléchargé supprimé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>Aucun modèle téléchargé à supprimer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>URL distante</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Chemin local</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Taille du fichier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Taille du fichier : inconnue</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Supprimer le modèle personnalisé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>Supprimer '%1' de vos LLM personnalisés ? Cela ne supprime pas le fichier du disque.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Supprimer l'API personnalisée</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>Supprimer '%1' de votre liste d'API personnalisées ? Cela n'affecte pas le serveur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>Variable d'environnement de l'URL de téléchargement manquante.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>Téléchargement…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>Téléchargement terminé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>Téléchargement annulé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>Erreur de téléchargement : %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Explorateur de fichiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Sélectionner un dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>Dossier chargé %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Analyse annulée</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Dossier sélectionné : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Plus cohérent</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Plus précis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>Recatégoriser le dossier ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Ce dossier a été catégorisé en mode %1. Voulez-vous le recatégoriser maintenant en mode %2 ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Recatégoriser</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Conserver l'existant</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>Impossible de réinitialiser la catégorisation en cache pour ce dossier.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>Téléchargement requis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>L'analyse d'images nécessite les fichiers LLM visuels. Les télécharger maintenant ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>OK</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Arrêter l'analyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Analyse en cours…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Analyser le dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Prêt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Annuler la dernière exécution</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Cela tentera de remettre les fichiers à leur emplacement d'origine en se basant sur la dernière exécution.\n\nFichier de plan : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>%1 fichier(s) restauré(s). %2 ignoré(s).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Annulation terminée</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>Merci d'utiliser AI File Sorter ! Vous avez déjà catégorisé %1 fichiers. Moi, l'auteur, j'espère vraiment que cette application vous a été utile.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter demande des centaines d'heures de développement, de travail sur les fonctionnalités, de réponses au support et des coûts continus tels que les serveurs et l'infrastructure des modèles distants. Si l'application vous fait gagner du temps ou vous apporte de la valeur, envisagez de la soutenir afin qu'elle puisse continuer à s'améliorer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>Déjà fait un don ? Cliquez sur « J'ai déjà fait un don » pour saisir votre code de don et désactiver définitivement ce rappel.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Faire un don pour masquer définitivement la boîte de dialogue de don</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Je ne suis pas encore sûr</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>J'ai déjà fait un don</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Code de don</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Saisissez le code de don généré après votre don.\nUn code valide masquera définitivement la boîte de dialogue de don.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Code de don invalide</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>Le code de don est invalide. Veuillez réessayer ou appuyer sur Annuler.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Ouvrir la page de don</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>Impossible d'ouvrir votre navigateur automatiquement.\nVeuillez ouvrir ce lien manuellement :\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>Fichier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIVE] Éléments déjà catégorisés :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[TERMINÉ] Aucun fichier à catégoriser.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[ATTENTE] Éléments en attente de catégorisation :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[SCAN] Exploration de %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[TRAITEMENT] L'IA fait sa magie...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISION] Décodage du lot d'images %1/%2 (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>Basculer l'analyse d'image sur le CPU ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>L'analyse d'image a manqué de mémoire GPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>Réessayer plutôt sur le CPU ? Annuler ignorera l'analyse visuelle et reviendra à une catégorisation basée sur le nom de fichier.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[ERREUR-VISION] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Basculement de l'analyse visuelle vers le CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Analyse visuelle désactivée ; retour aux noms de fichiers.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISION] Utilisation de la suggestion en cache pour %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISION] Analyse de %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] Problème de mémoire GPU détecté. Basculement vers le CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Analyse visuelle désactivée pour les images restantes.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[ERREUR-DOC] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] Utilisation de la suggestion en cache pour %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] Analyse de %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[TRI] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Annulation de l'analyse…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>Basculer l'IA locale sur le CPU ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>Le modèle local a rencontré une erreur GPU ou a manqué de mémoire.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>Réessayer plutôt sur le CPU ? Annuler arrêtera cette analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] Repli du GPU vers le CPU refusé. Annulation de l'analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[AVERTISSEMENT] L'accélération GPU n'a pas pu être initialisée. Poursuite sur CPU (plus lent).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[AVERTISSEMENT] %1 sera recatégorisé : %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Modifier les éléments sélectionnés</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Laisser vide pour conserver l'existant</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Sous-catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>À propos de %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>À propos</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Crédits</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>À propos de la licence AGPL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter est distribué sous la licence GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;Vous pouvez accéder au code source complet sur &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Une copie complète de la licence est fournie avec cette application et disponible en ligne sur &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (auto)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (auto)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (auto)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Auto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (cible : %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>GPU via Vulkan indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>GPU via CUDA indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>GPU via Metal indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>Échec de l'initialisation du GPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Modèle par défaut : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Mesure de la catégorisation (échauffement + %1 exécution(s))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Mesure de l'analyse des documents (échauffement + %1 exécution(s))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Catégorisation : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>terminé</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>échoué</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Échauffement : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Initialisation : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Par élément (médiane de %1) : %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Exécutions par élément : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Détails : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Backend utilisé : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Analyse des documents : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>Échec du chargement du modèle : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>optimal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>acceptable</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>assez long</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>n/a</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Résultat</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Vitesse de catégorisation : indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Vitesse d'analyse des documents : indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Vitesse de catégorisation : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Vitesse d'analyse des documents : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Vitesse d'analyse des images : indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Vitesse d'analyse des images : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>LLM local recommandé : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>Vous pouvez changer de LLM dans Paramètres -&gt; Sélectionner le LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Benchmark de compatibilité</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Exécute une vérification rapide des performances pour estimer comment l'analyse d'images, l'analyse de documents et la catégorisation de fichiers fonctionneront sur votre système.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Il est recommandé de quitter toute application intensive pour le CPU ou le GPU avant d'exécuter ce test.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Lancer le benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>Ne plus afficher automatiquement ce dialogue</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Arrêter le benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Fermer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>Aucun résultat précédent.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Dernière exécution : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Résultats précédents :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>Aucun fichier LLM téléchargé détecté. Téléchargez un modèle de catégorisation ou visuel pour exécuter le benchmark.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Démarrage de la vérification de compatibilité système...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>Threads CPU détectés : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>Forçage du backend GPU : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal disponible : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>oui</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>non</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>Allocation mémoire GPU (Metal) : %1 libres / %2 au total</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>Allocation mémoire GPU (Metal) : indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA disponible : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>Mémoire CUDA (allouable) : %1 libres / %2 au total</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (total de l'appareil : %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>Allocation mémoire GPU (Vulkan) : %1 libres / %2 au total</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>Allocation mémoire GPU (Vulkan) : indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>La configuration du répertoire temporaire a échoué ; la création du fichier d'exemple du benchmark peut échouer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>Aucun modèle par défaut téléchargé ; saut des vérifications de catégorisation et d'analyse de documents.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Modèles par défaut détectés : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark arrêté.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Exécution du test d'analyse d'images...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>indisponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Analyse des images : ignorée (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Analyse des images : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Temps : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU désactivé par le forçage du backend</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Backend utilisé (analyse d'images) : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark échoué : %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] Le benchmark s'arrêtera après l'étape en cours.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Erreur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>LLM local (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>LLM local</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>Soutenir %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Mise à jour obligatoire disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>Une mise à jour obligatoire est disponible. Veuillez mettre à jour pour continuer.\nSi vous choisissez de quitter, l'application se fermera.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Mettre à jour maintenant</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Quitter</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>Mise à jour facultative disponible</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>Une mise à jour facultative est disponible. Souhaitez-vous mettre à jour maintenant ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Ignorer cette version</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>Annuler</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Téléchargement de la mise à jour</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Téléchargement du programme d'installation de la mise à jour...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>Échec de la préparation du programme d'installation de la mise à jour.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Programme d'installation prêt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Quittez l'application et lancez le programme d'installation pour effectuer la mise à jour</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Quitter et lancer le programme d'installation</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>Le programme d'installation n'a pas pu être lancé.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>Aucune cible de téléchargement n'est disponible pour cette mise à jour.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>Échec de la mise à jour</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Mettre à jour manuellement</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>Modifier la liste blanche</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Nom :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Catégories (séparées par des virgules) :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Sous-catégories (séparées par des virgules) :</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>Toolkit CUDA manquant</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>Un GPU NVIDIA compatible a été détecté, mais le toolkit CUDA est absent.\n\nCUDA est nécessaire pour l'accélération GPU dans cette application.\n\nVoulez-vous le télécharger et l'installer maintenant ?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Erreur de lancement</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>Impossible d'activer CUDA et Vulkan simultanément.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>Runtime GGML manquant</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>Impossible de localiser les DLL d'exécution du backend.\nTentatives :\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Échec du lancement</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>Échec du lancement de l'exécutable principal de l'application :\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Dossier :</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Parcourir…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Utiliser les sous-catégories</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Créer des sous-dossiers dans chaque catégorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Type de catégorisation</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Choisir le niveau de précision des libellés de catégorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Plus précis</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Privilégie des libellés détaillés même si les éléments similaires varient.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Plus cohérent</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Privilégie des libellés cohérents pour les éléments similaires.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Utiliser une liste blanche</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Limiter les catégories et sous-catégories à la liste blanche sélectionnée.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Sélectionner la liste blanche utilisée pour cette analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Catégoriser les fichiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Inclure les fichiers dans la catégorisation.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Catégoriser les dossiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Inclure les dossiers dans la catégorisation.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Scanner les sous-dossiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Analyser les fichiers dans les sous-dossiers et les traiter comme s'ils étaient dans le dossier principal.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Analyser les fichiers image par contenu (peut être lent)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Exécuter le LLM visuel sur les fichiers image pris en charge.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Traiter uniquement les fichiers image (ignorer tous les autres fichiers)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Ignorer les fichiers non image lors de cette analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Ajouter la date de création de l'image (si disponible) au nom de la catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Ajouter la date de création de l'image depuis les métadonnées au libellé de la catégorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Ajouter la date et le lieu de la photo au nom de fichier (si disponibles)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>La date provient des métadonnées EXIF de la photo. Les noms de lieux sont résolus en ligne à partir des coordonnées GPS ; un accès réseau est donc requis pour les préfixes de lieu.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Ajouter les métadonnées audio/vidéo au nom de fichier (si disponibles)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Utiliser les tags média intégrés (par exemple année, artiste, album, titre) pour générer des noms de fichiers audio/vidéo suggérés.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Proposer de renommer les fichiers image</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Afficher des noms de fichiers suggérés pour les fichiers image.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Ne pas catégoriser les fichiers image (renommer uniquement)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Ignorer la catégorisation des fichiers image et les renommer uniquement.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Afficher ou masquer les options d'analyse des images</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Analyser les fichiers de documents par contenu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Résumer le contenu des documents avec le LLM sélectionné.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Traiter uniquement les fichiers de documents (ignorer tous les autres fichiers)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Ignorer les fichiers non document lors de cette analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Proposer de renommer les fichiers de documents</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Afficher des noms de fichiers suggérés pour les fichiers de documents.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Ne pas catégoriser les fichiers de documents (renommer uniquement)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Ignorer la catégorisation des fichiers de documents et les renommer uniquement.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Ajouter la date de création du document (si disponible) au nom de la catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Ajouter la date de création du document depuis les métadonnées au libellé de la catégorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Afficher ou masquer les options d'analyse des documents</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Arrêter l'analyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Analyser le dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>Fichier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Sous-catégorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Statut</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Dossier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Prêt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Aide</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Explorateur de fichiers</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Annulation de l'analyse…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Analyse en cours…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Listes blanches de catégories</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Ajouter</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Modifier</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Retirer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>Impossible de retirer</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>La liste par défaut ne peut pas être retirée.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_it.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"it_IT\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>Suggerimento: fai clic sulle celle %1 per rinominarle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>Nessun elemento selezionato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>Evidenzia una o più righe per selezionarle per l'elaborazione.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Modifica in blocco non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>La modifica in blocco delle categorie non è disponibile mentre è attiva la modalità di sola rinomina delle immagini.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Evidenzia una o più righe per modificarne le categorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Anteprima</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Rivedi e conferma</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Seleziona tutto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Seleziona evidenziati</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Modifica selezionati...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Crea cartelle di sottocategoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Prova (solo anteprima, non spostare i file)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Non categorizzare i file immagine (solo rinomina)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Non categorizzare i file di documenti (solo rinominarli)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Conferma e elabora</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Continua più tardi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Annulla questa modifica</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Chiudi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Contrassegna le righe evidenziate per l'elaborazione (Ctrl+Spazio).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Applica i valori di categoria/sottocategoria alle righe evidenziate.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>Elabora</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>File</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Nome file suggerito</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Categoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Sottocategoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Stato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Destinazione prevista</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Spostato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Rinominato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Rinominato e spostato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Saltato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>Non selezionato</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[STOP] L'analisi si interromperà dopo l'elemento corrente.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Analisi delle immagini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Analisi dei documenti</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Categorizzazione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Immagine</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Documento</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>File</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Fase %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>In attesa</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>In corso</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Completato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>Elaborati 0/0  |  In corso: 0  |  In attesa: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>Elaborati %1/%2  |  In corso: %3  |  In attesa: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Analisi dei file</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Interrompi analisi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Registro attività</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>API personalizzata compatibile con OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>ad es. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>ad es. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Mostra</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Nome visualizzato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Descrizione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>URL di base o endpoint</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Modello</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>Chiave API (opzionale)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Inserisci un URL di base (ad es. http://localhost:1234/v1) oppure un endpoint /chat/completions completo.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>LLM locale personalizzato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Sfoglia…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Nome visualizzato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Descrizione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>File del modello (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>Seleziona modello .gguf</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>Modelli GGUF (*.gguf);;Tutti i file (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Anteprima prova</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>Da</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>A</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Chiudi</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>Scegli la modalità LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>Seleziona modalità LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Modello locale più grande. Più lento su CPU, ma rende molto meglio con l'accelerazione GPU.\nSupporta: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Consigliato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>Modello locale più piccolo, rapido anche su CPU. Buono per un uso locale leggero.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Modello legacy mantenuto per i download esistenti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (chiave API di Google AI Studio)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Usa i modelli Gemini di Google con la tua chiave API di AI Studio (richiede Internet).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Mostra</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Chiave API Gemini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>ad es. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Modello</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>La tua chiave viene memorizzata localmente nel file di configurazione di questo dispositivo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Ottieni una chiave API Gemini&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (chiave API OpenAI)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>Usa la tua chiave API OpenAI per accedere ai modelli ChatGPT (richiede Internet).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>Chiave API OpenAI</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>ad es. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Ottieni una chiave API OpenAI&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>API personalizzata compatibile con OpenAI (avanzata)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>Usa endpoint compatibili con OpenAI come LM Studio o Ollama (locali o remoti).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Aggiungi…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Modifica…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Elimina</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>LLM locale personalizzato (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>Download</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>Scarica</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Modelli di analisi immagini (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Scarica i file LLM visivi necessari per l'analisi delle immagini.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (modello di testo)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (codificatore visivo)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Scegli o aggiungi un modello personalizzato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Modello personalizzato selezionato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Selezione pronta.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Scegli o aggiungi un endpoint API personalizzato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>API personalizzata selezionata.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT userà la tua chiave API e il tuo modello.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Inserisci la tua chiave API OpenAI e il modello per continuare.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini userà la tua chiave API e il tuo modello.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Inserisci la tua chiave API Gemini e il modello per continuare.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Modello pronto.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>Riprendi download</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Download parziale rilevato. Puoi riprendere.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>Download richiesto.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Selezione LLM non supportata.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>Variabile d'ambiente dell'URL di download mancante (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>Eliminare il modello scaricato?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>Eliminare il modello scaricato %1?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>Impossibile eliminare il modello scaricato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>Modello scaricato eliminato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>Nessun modello scaricato da eliminare.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>URL remoto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Percorso locale</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Dimensione file</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Dimensione file: sconosciuta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Elimina modello personalizzato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>Rimuovere '%1' dai tuoi LLM personalizzati? Questo non elimina il file dal disco.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Elimina API personalizzata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>Rimuovere '%1' dalla tua lista di API personalizzate? Questo non influisce sul server.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>Variabile d'ambiente dell'URL di download mancante.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>Download in corso…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>Download completato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>Download annullato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>Errore di download: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Esplora file</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Seleziona cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>Cartella %1 caricata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Analisi annullata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Cartella selezionata: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Più coerente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Più dettagliata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>Ricategorizzare la cartella?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Questa cartella è stata categorizzata in modalità %1. Vuoi ricategorizzarla ora in modalità %2?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Ricategorizza</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Mantieni</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>Impossibile ripristinare la categorizzazione memorizzata per questa cartella.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>Download richiesto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>L'analisi delle immagini richiede i file LLM visivi. Scaricarli ora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>OK</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Interrompi analisi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Analisi in corso…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Analizza cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Pronto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Annulla l'ultima esecuzione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Verrà effettuato un tentativo di riportare i file nelle loro posizioni originali in base all'ultima esecuzione.\n\nFile di piano: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>Ripristinati %1 file. Saltati %2.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Annullamento completato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>Grazie per usare AI File Sorter! Hai già categorizzato %1 file. Io, l'autore, spero davvero che questa app ti sia stata utile.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter richiede centinaia di ore di sviluppo, lavoro sulle funzionalità, risposte di supporto e costi continui come server e infrastruttura per modelli remoti. Se l'app ti fa risparmiare tempo o ti offre valore, valuta di supportarla affinché possa continuare a migliorare.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>Hai già donato? Fai clic su \"Ho già donato\" per inserire il tuo codice di donazione e disattivare definitivamente questo promemoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Fai una donazione per nascondere permanentemente la finestra di dialogo di donazione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Non sono ancora sicuro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>Ho già donato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Codice di donazione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Inserisci il codice di donazione generato dopo la tua donazione.\nUn codice valido nasconderà permanentemente la finestra di dialogo di donazione.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Codice di donazione non valido</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>Il codice di donazione non è valido. Riprova o premi Annulla.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Apri la pagina delle donazioni</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>Impossibile aprire automaticamente il browser.\nApri manualmente questo link:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>File</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIVIO] Elementi già categorizzati:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[FATTO] Nessun file da categorizzare.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[CODA] Elementi in attesa di categorizzazione:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[SCANSIONE] Esplorazione di %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[ELABORAZIONE] L'IA fa la sua magia...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISIONE] Decodifica del lotto di immagini %1/%2 (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>Passare l'analisi delle immagini alla CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>L'analisi delle immagini ha esaurito la memoria GPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>Riprovare invece sulla CPU? Annulla salterà l'analisi visiva e userà la categorizzazione basata sul nome file.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[ERRORE-VISIONE] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Passaggio dell'analisi visiva alla CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Analisi visiva disattivata; ritorno ai nomi file.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISIONE] Uso del suggerimento in cache per %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISIONE] Analisi di %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] Rilevato un problema di memoria GPU. Passaggio alla CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Analisi visiva disattivata per le immagini rimanenti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[ERRORE-DOC] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] Uso del suggerimento in cache per %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] Analisi di %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[ORDINA] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Annullamento analisi…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>Passare l'IA locale alla CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>Il modello locale ha riscontrato un errore GPU o ha esaurito la memoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>Riprovare invece sulla CPU? Annulla interromperà questa analisi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] Rifiutato il fallback da GPU a CPU. Annullamento dell'analisi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[AVVISO] Impossibile inizializzare l'accelerazione GPU. Continuo su CPU (più lento).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[AVVISO] %1 verrà ricategorizzato: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Modifica elementi selezionati</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Lascia vuoto per mantenere i valori esistenti</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Categoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Sottocategoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>Informazioni su %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>Informazioni</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Crediti</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>Informazioni sulla licenza AGPL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter è distribuito sotto la GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;Puoi accedere al codice sorgente completo su &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Una copia completa della licenza è fornita con l'applicazione ed è disponibile online su &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (automatico)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (automatico)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (automatico)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Automatico</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (destinazione: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>GPU via Vulkan non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>GPU via CUDA non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>GPU via Metal non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>Inizializzazione GPU non riuscita</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Modello predefinito: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Misurazione della categorizzazione (riscaldamento + %1 esecuzione/i)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Misurazione dell'analisi dei documenti (riscaldamento + %1 esecuzione/i)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Categorizzazione: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>completato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>fallito</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Riscaldamento: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Inizializzazione: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Per elemento (mediana di %1): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Esecuzioni per elemento: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Dettagli: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Backend utilizzato: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Analisi dei documenti: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>Impossibile caricare il modello: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>ottimale</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>accettabile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>piuttosto lungo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>n/d</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Risultato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Velocità di categorizzazione: non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Velocità analisi documenti: non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Velocità di categorizzazione: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Velocità analisi documenti: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Velocità analisi immagini: non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Velocità analisi immagini: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>LLM locale consigliato: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>Puoi cambiare i LLM in Impostazioni -&gt; Seleziona LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Benchmark di compatibilità</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Esegue una rapida verifica delle prestazioni per stimare come l'analisi delle immagini, l'analisi dei documenti e la categorizzazione dei file funzioneranno sul sistema.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Si consiglia di chiudere le applicazioni intensive per CPU e GPU prima di eseguire questo test.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Avvia benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>Non mostrare automaticamente questo dialogo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Interrompi il benchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Chiudi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>Nessun risultato precedente.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Ultima esecuzione: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Risultati precedenti:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>Nessun file LLM scaricato rilevato. Scarica un modello di categorizzazione o visivo per eseguire il benchmark.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Avvio della verifica di compatibilità del sistema...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>Thread CPU rilevati: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>Override del backend GPU: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal disponibile: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>sì</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>no</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>Allocazione memoria GPU (Metal): %1 liberi / %2 totali</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>Allocazione memoria GPU (Metal): non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA disponibile: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>Memoria CUDA (allocabile): %1 libera / %2 totale</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (totale del dispositivo: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>Allocazione memoria GPU (Vulkan): %1 liberi / %2 totali</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>Allocazione memoria GPU (Vulkan): non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>La configurazione della directory temporanea non è riuscita; la creazione del file di esempio del benchmark potrebbe non riuscire.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>Nessun modello predefinito scaricato; salto la categorizzazione e i controlli sui documenti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Modelli predefiniti rilevati: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark interrotto.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Esecuzione del test di analisi immagini...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>non disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Analisi immagini: ignorata (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Analisi immagini: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Tempo: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU disabilitata dall'override del backend</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Backend utilizzato (analisi immagini): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark non riuscito: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] Il benchmark verrà interrotto dopo lo step corrente.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Errore</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>LLM locale (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>LLM locale</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>Sostieni %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Aggiornamento obbligatorio disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>È disponibile un aggiornamento obbligatorio. Aggiorna per continuare.\nSe scegli di uscire, l'applicazione si chiuderà.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Aggiorna ora</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Esci</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>Aggiornamento opzionale disponibile</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>È disponibile un aggiornamento opzionale. Vuoi aggiornare ora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Salta questa versione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>Annulla</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Download aggiornamento</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Download del programma di installazione dell'aggiornamento...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>Impossibile preparare il programma di installazione dell'aggiornamento.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Programma di installazione pronto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Chiudi l'app e avvia il programma di installazione per aggiornare</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Chiudi e avvia il programma di installazione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>Impossibile avviare il programma di installazione.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>Nessuna destinazione di download disponibile per questo aggiornamento.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>Aggiornamento non riuscito</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Aggiorna manualmente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>Modifica whitelist</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Nome:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Categorie (separate da virgole):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Sottocategorie (separate da virgole):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>Toolkit CUDA mancante</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>È stata rilevata una GPU NVIDIA compatibile, ma manca il CUDA Toolkit.\n\nCUDA è necessario per l'accelerazione GPU in questa applicazione.\n\nVuoi scaricarlo e installarlo ora?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Errore di avvio</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>Impossibile abilitare contemporaneamente CUDA e Vulkan.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>Runtime GGML mancante</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>Impossibile trovare le DLL di runtime del backend.\nPercorsi provati:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Avvio non riuscito</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>Impossibile avviare l'eseguibile principale dell'applicazione:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Cartella:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Sfoglia…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Usa sottocategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Crea sottocartelle all'interno di ogni categoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Tipo di categorizzazione</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Scegli quanto devono essere rigorose le etichette delle categorie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Più dettagliata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Privilegia etichette dettagliate anche se gli elementi simili variano.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Più coerente</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Privilegia etichette coerenti tra elementi simili.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Usa whitelist</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Limita categorie e sottocategorie alla whitelist selezionata.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Seleziona la whitelist usata per questa analisi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Categoriza i file</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Includi i file nella categorizzazione.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Categoriza le cartelle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Includi le cartelle nella categorizzazione.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Scansiona le sottocartelle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Scansiona i file nelle sottocartelle e trattali come se fossero nella cartella principale.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Analizza i file immagine in base al contenuto (può essere lento)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Esegui il LLM visivo sui file immagine supportati.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Elabora solo i file immagine (ignora tutti gli altri file)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Ignora i file non immagine in questa analisi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Aggiungi la data di creazione dell'immagine (se disponibile) al nome della categoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Aggiungi la data di creazione dell'immagine dai metadati all'etichetta della categoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Aggiungi data e luogo della foto al nome file (se disponibili)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>La data proviene dai metadati EXIF della foto. I nomi dei luoghi vengono risolti online dalle coordinate GPS, quindi è necessaria la rete per i prefissi di luogo.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Aggiungi metadati audio/video al nome file (se disponibili)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Usa i tag multimediali incorporati (ad esempio anno, artista, album, titolo) per creare nomi file audio/video suggeriti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Offri di rinominare i file immagine</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Mostra nomi file suggeriti per i file immagine.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Non categorizzare i file immagine (solo rinomina)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Salta la categorizzazione dei file immagine e rinominali soltanto.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Mostra o nascondi le opzioni di analisi immagini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Analizza i file di documenti in base al contenuto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Riassumi il contenuto dei documenti con il LLM selezionato.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Elabora solo i file di documenti (ignora tutti gli altri file)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Ignora i file non documenti in questa analisi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Offri di rinominare i file di documenti</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Mostra nomi file suggeriti per i file di documenti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Non categorizzare i file di documenti (solo rinominarli)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Salta la categorizzazione dei file di documenti e rinominali soltanto.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Aggiungi la data di creazione del documento (se disponibile) al nome della categoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Aggiungi la data di creazione del documento dai metadati all'etichetta della categoria.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Mostra o nascondi le opzioni di analisi documenti</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Interrompi analisi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Analizza cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>File</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Tipo</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Categoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Sottocategoria</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Stato</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Cartella</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Pronto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Aiuto</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Esplora file</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Annullamento analisi…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Analisi in corso…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Whitelist delle categorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Aggiungi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Modifica</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Rimuovi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>Impossibile rimuovere</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>L'elenco predefinito non può essere rimosso.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_ko.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"ko_KR\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>팁: 이름을 바꾸려면 %1 셀을 클릭하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>선택된 항목이 없습니다</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>처리 대상으로 선택하려면 하나 이상의 행을 강조 표시하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>일괄 편집을 사용할 수 없습니다</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>사진 이름만 변경 모드가 활성화되어 있는 동안에는 카테고리를 일괄 편집할 수 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>카테고리를 편집하려면 하나 이상의 행을 강조 표시하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>미리보기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>검토 및 확인</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>모두 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>강조된 항목 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>선택 항목 편집...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>하위 카테고리 폴더 만들기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>드라이 런(미리보기만, 파일 이동 안 함)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>이미지 파일 분류 안 함(이름만 변경)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>문서 파일 분류 안 함(이름만 변경)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>확인 및 처리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>나중에 계속</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>이 변경 사항 실행 취소</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>닫기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>강조된 행을 처리 대상으로 표시합니다(Ctrl+Space).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>카테고리/하위 카테고리 값을 강조된 행에 적용합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>처리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>파일</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>유형</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>추천 파일명</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>하위 카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>상태</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>계획된 대상</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>이동됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>이름 변경됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>이름이 변경되고 이동됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>건너뜀</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>선택되지 않음</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[STOP] 현재 항목 처리가 끝나면 분석이 중지됩니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>이미지 분석</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>문서 분석</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>분류</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>폴더</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>이미지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>문서</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>파일</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>유형</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>단계 %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>대기 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>진행 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>완료됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>처리됨 0/0  |  진행 중: 0  |  대기 중: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>처리됨 %1/%2  |  진행 중: %3  |  대기 중: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>파일 분석 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>분석 중지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>활동 로그</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>사용자 지정 OpenAI 호환 API</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>예: http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>예: llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>표시</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>표시 이름</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>설명</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>기본 URL 또는 엔드포인트</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>모델</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>API 키(선택 사항)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>기본 URL(예: http://localhost:1234/v1) 또는 전체 /chat/completions 엔드포인트를 입력하세요.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>사용자 지정 로컬 LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>찾아보기…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>표시 이름</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>설명</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>모델 파일(.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>.gguf 모델 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>GGUF 모델 (*.gguf);;모든 파일 (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>드라이 런 미리보기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>원본</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>대상</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>닫기</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>LLM 모드 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>LLM 모드 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>더 큰 로컬 모델입니다. CPU에서는 느리지만 GPU 가속을 사용하면 성능이 훨씬 좋아집니다.\n지원 대상: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>권장</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>더 작은 로컬 모델로 CPU에서도 빠르게 동작합니다. 가벼운 로컬 사용에 적합합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>기존 다운로드를 위해 레거시 모델을 유지합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (Google AI Studio API 키)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>AI Studio API 키로 Google의 Gemini 모델을 사용하세요(인터넷 필요).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>표시</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Gemini API 키</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>예: gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>모델</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>키는 이 기기의 설정 파일에 로컬로 저장됩니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Gemini API 키 받기&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (OpenAI API 키)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>ChatGPT 모델에 액세스하려면 자신의 OpenAI API 키를 사용하세요(인터넷 필요).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>OpenAI API 키</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>예: gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;OpenAI API 키 받기&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>사용자 지정 OpenAI 호환 API(고급)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>LM Studio나 Ollama 같은 OpenAI 호환 엔드포인트를 사용하세요(로컬 또는 원격).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>추가…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>편집…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>삭제</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>사용자 지정 로컬 LLM (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>다운로드</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>다운로드</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>이미지 분석 모델(LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>이미지 분석에 필요한 비전 LLM 파일을 다운로드합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B(텍스트 모델)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj(비전 인코더)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>사용자 지정 모델을 선택하거나 추가하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>사용자 지정 모델이 선택되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>선택이 준비되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>사용자 지정 API 엔드포인트를 선택하거나 추가하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>사용자 지정 API가 선택되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT가 API 키와 모델을 사용합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>계속하려면 OpenAI API 키와 모델을 입력하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini가 API 키와 모델을 사용합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>계속하려면 Gemini API 키와 모델을 입력하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>모델 준비 완료.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>다운로드 재개</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>부분 다운로드가 감지되었습니다. 재개할 수 있습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>다운로드가 필요합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>지원되지 않는 LLM 선택입니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>다운로드 URL 환경 변수가 없습니다(%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>다운로드한 모델을 삭제할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>다운로드한 모델 %1을(를) 삭제할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>다운로드한 모델을 삭제하지 못했습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>다운로드한 모델을 삭제했습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>삭제할 다운로드한 모델이 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>원격 URL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>로컬 경로</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>파일 크기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>파일 크기: 알 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>사용자 지정 모델 삭제</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>사용자 지정 LLM에서 '%1'을(를) 제거할까요? 이렇게 해도 디스크의 파일은 삭제되지 않습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>사용자 지정 API 삭제</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>사용자 지정 API 목록에서 '%1'을(를) 제거할까요? 서버에는 영향을 주지 않습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>다운로드 URL 환경 변수가 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>다운로드 중…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>다운로드 완료.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>다운로드가 취소되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>다운로드 오류: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>파일 탐색기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>폴더 선택</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>폴더 %1 불러옴</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>분석이 취소됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>선택한 폴더: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>더 일관적</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>더 세분화</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>폴더를 다시 분류할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>이 폴더는 %1 모드로 분류되었습니다. 지금 %2 모드로 다시 분류할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>다시 분류</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>기존 유지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>이 폴더의 캐시된 분류를 초기화하지 못했습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>다운로드 필요</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>이미지 분석에는 비전 LLM 파일이 필요합니다. 지금 다운로드할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>확인</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>분석 중지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>분석 중…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>폴더 분석</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>준비됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>마지막 실행 취소</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>마지막 실행을 기준으로 파일을 원래 위치로 되돌리려고 시도합니다.\n\n계획 파일: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>파일 %1개를 복원했습니다. %2개는 건너뛰었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>실행 취소 완료</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>AI File Sorter를 사용해 주셔서 감사합니다! 지금까지 %1개의 파일을 분류하셨습니다. 이 앱이 도움이 되었기를 바랍니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter에는 수백 시간의 개발, 기능 작업, 지원 응답, 그리고 서버와 원격 모델 인프라 같은 지속적인 비용이 들어갑니다. 이 앱이 시간을 절약해 주거나 가치를 제공한다면 계속 개선될 수 있도록 지원을 고려해 주세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>이미 기부하셨나요? 기부 코드를 입력해 이 알림을 영구적으로 끄려면 \"이미 기부했습니다\"를 클릭하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>기부 대화 상자를 영구히 숨기려면 기부하기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>아직 모르겠어요</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>이미 기부했습니다</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>기부 코드</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>기부 후 생성된 기부 코드를 입력하세요.\n유효한 코드를 입력하면 기부 대화 상자가 영구적으로 숨겨집니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>유효하지 않은 기부 코드</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>기부 코드가 유효하지 않습니다. 다시 시도하거나 취소를 누르세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>기부 페이지 열기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>브라우저를 자동으로 열 수 없습니다.\n다음 링크를 직접 열어 주세요:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>폴더</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>파일</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIVE] 이미 분류된 항목:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[DONE] 분류할 파일이 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[QUEUE] 분류 대기 항목:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[SCAN] %1 탐색 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[PROCESS] AI가 작업 중...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISION] 이미지 배치 %1/%2 디코딩 중 (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>이미지 분석을 CPU로 전환할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>이미지 분석 중 GPU 메모리가 부족해졌습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>대신 CPU에서 다시 시도할까요? 취소하면 시각 분석을 건너뛰고 파일 이름 기반 분류로 대체합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[VISION-ERROR] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] 시각 분석을 CPU로 전환합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] 시각 분석이 비활성화되어 파일 이름으로 대체합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISION] %1에 대해 캐시된 제안 사용 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISION] %1 분석 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] GPU 메모리 문제가 감지되었습니다. CPU로 전환합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] 남은 이미지에 대한 시각 분석이 비활성화되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[DOC-ERROR] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] %1에 대해 캐시된 제안 사용 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] %1 분석 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[SORT] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>분석 취소 중…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>로컬 AI를 CPU로 전환할까요?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>로컬 모델에서 GPU 오류가 발생했거나 메모리가 부족해졌습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>대신 CPU에서 다시 시도할까요? 취소하면 이 분석이 중단됩니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] GPU에서 CPU로의 전환이 거부되었습니다. 분석을 취소합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[WARN] GPU 가속을 초기화하지 못했습니다. CPU로 계속 진행합니다(느려짐).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[WARN] %1 재분류 예정: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>선택한 항목 편집</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>기존 값을 유지하려면 비워 두세요</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>하위 카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>오류</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>로컬 LLM (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>로컬 LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>%1 지원</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>%1 정보</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>정보</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>크레딧</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>AGPL 라이선스 정보</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter는 GNU Affero General Public License v3.0에 따라 배포됩니다.&lt;br&gt;&lt;br&gt;전체 소스 코드는 &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;에서 확인할 수 있습니다.&lt;br&gt;&lt;br&gt;라이선스 전문은 이 애플리케이션과 함께 제공되며 &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;에서도 확인할 수 있습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (자동)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (자동)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (자동)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>자동</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (대상: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>Vulkan을 통한 GPU 사용 불가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>CUDA를 통한 GPU 사용 불가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan 사용 불가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>Metal을 통한 GPU 사용 불가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>GPU 초기화 실패</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>기본 모델: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    분류 측정(워밍업 + %1회 실행)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    문서 분석 측정(워밍업 + %1회 실행)...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>분류: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>완료</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>실패</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    워밍업: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    초기화: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    항목당(%1회 중앙값): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    항목당 실행: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>세부 정보: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>사용한 백엔드: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>문서 분석: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>모델을 불러오지 못했습니다: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>최적</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>수용 가능</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>꽤 김</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>해당 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>결과</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>분류 속도: 사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>문서 분석 속도: 사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>분류 속도: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>문서 분석 속도: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>이미지 분석 속도: 사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>이미지 분석 속도: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>권장 로컬 LLM 선택: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>설정 -&gt; LLM 선택에서 LLM을 전환할 수 있습니다</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>호환성 벤치마크</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>이 시스템에서 이미지 분석, 문서 분석 및 파일 분류가 어떻게 수행될지 추정하기 위해 빠른 성능 확인을 실행합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>이 테스트를 실행하기 전에 CPU 및 GPU를 많이 사용하는 응용 프로그램을 종료하는 것이 권장됩니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>벤치마크 실행</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>이 대화 상자를 자동으로 다시 표시하지 않음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>벤치마크 중지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>닫기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>이전 결과가 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>마지막 실행: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>이전 결과:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>다운로드된 LLM 파일이 없습니다. 벤치마크를 실행하려면 분류 또는 비주얼 모델을 다운로드하세요.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>시스템 호환성 확인을 시작합니다...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>CPU 스레드 감지됨: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>GPU 백엔드 강제 설정: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal 사용 가능: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>예</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>아니오</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>GPU 메모리 할당(Metal): %1 여유 / %2 전체</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>GPU 메모리 할당(Metal): 사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA 사용 가능: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>CUDA 메모리(할당 가능): %1 여유 / %2 전체</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (기기 총량: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>GPU 메모리 할당(Vulkan): %1 여유 / %2 전체</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>GPU 메모리 할당(Vulkan): 사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>임시 디렉터리 설정에 실패했습니다. 벤치마크 샘플 파일 생성이 실패할 수 있습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>기본 모델이 다운로드되지 않아 분류 및 문서 검사를 건너뜁니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>기본 모델 감지됨: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>벤치마크가 중지되었습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>이미지 분석 테스트 실행 중...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>사용할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>이미지 분석: 건너뜀(%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>이미지 분석: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    시간: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>백엔드 강제 설정으로 GPU 비활성화됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>사용한 백엔드(이미지 분석): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>벤치마크 실패: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] 벤치마크가 현재 단계가 끝난 후 중지됩니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>필수 업데이트 사용 가능</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>필수 업데이트가 있습니다. 계속하려면 업데이트하세요.\n종료를 선택하면 애플리케이션이 닫힙니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>지금 업데이트</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>종료</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>선택적 업데이트 사용 가능</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>선택적 업데이트가 있습니다. 지금 업데이트하시겠습니까?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>이 버전 건너뛰기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>취소</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>업데이트 다운로드 중</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>업데이트 설치 프로그램을 다운로드하는 중...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>업데이트 설치 프로그램을 준비하지 못했습니다.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>설치 프로그램 준비 완료</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>업데이트하려면 앱을 종료하고 설치 프로그램을 실행하세요</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>종료 후 설치 프로그램 실행</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>설치 프로그램을 실행할 수 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>이 업데이트에 사용할 다운로드 대상이 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>업데이트 실패</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>수동으로 업데이트</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>화이트리스트 편집</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>이름:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>카테고리(쉼표로 구분):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>하위 카테고리(쉼표로 구분):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>CUDA Toolkit 누락</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>호환되는 NVIDIA GPU가 감지되었지만 CUDA Toolkit이 없습니다.\n\n이 애플리케이션에서 GPU 가속을 사용하려면 CUDA가 필요합니다.\n\n지금 다운로드하여 설치하시겠습니까?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>실행 오류</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>CUDA와 Vulkan을 동시에 활성화할 수 없습니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>GGML 런타임 누락</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>백엔드 런타임 DLL을 찾을 수 없습니다.\n시도한 위치:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>실행 실패</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>메인 애플리케이션 실행 파일을 시작하지 못했습니다:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>폴더:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>찾아보기…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>하위 카테고리 사용</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>각 카테고리 안에 하위 카테고리 폴더를 생성합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>분류 유형</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>카테고리 레이블의 엄격함을 선택합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>더 세분화</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>유사한 항목 간 차이가 있더라도 자세한 레이블을 선호합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>더 일관적</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>유사한 항목에 일관된 레이블을 선호합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>화이트리스트 사용</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>선택한 화이트리스트로 카테고리와 하위 카테고리를 제한합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>이번 실행에 사용할 화이트리스트를 선택합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>파일 분류</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>분류 단계에 파일을 포함합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>폴더 분류</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>분류 단계에 폴더를 포함합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>하위 폴더 스캔</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>하위 폴더의 파일을 스캔하고 기본 폴더에 있는 것처럼 처리합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>이미지 파일을 내용으로 분석(느릴 수 있음)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>지원되는 이미지 파일에 비전 LLM을 실행합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>이미지 파일만 처리(다른 파일 무시)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>이번 실행에서 이미지가 아닌 파일은 무시합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>이미지 생성 날짜(가능한 경우)를 카테고리 이름에 추가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>메타데이터의 이미지 생성 날짜를 카테고리 라벨에 추가합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>사진 날짜와 장소를 파일명에 추가(가능한 경우)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>날짜는 사진 EXIF 메타데이터에서 가져옵니다. 장소 이름은 GPS 좌표를 바탕으로 온라인에서 확인되므로 장소 접두어에는 네트워크 연결이 필요합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>오디오/비디오 메타데이터를 파일 이름에 추가(가능한 경우)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>내장 미디어 태그(예: 연도, 아티스트, 앨범, 제목)를 사용해 오디오/비디오 추천 파일명을 만듭니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>이미지 파일 이름 바꾸기 제안</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>이미지 파일에 대한 추천 파일명을 표시합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>이미지 파일 분류 안 함(이름만 변경)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>이미지 파일의 분류를 건너뛰고 이름만 변경합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>이미지 분석 옵션 표시/숨기기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>문서 파일을 내용으로 분석</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>선택한 LLM으로 문서 내용을 요약합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>문서 파일만 처리(다른 파일 무시)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>이번 실행에서 문서가 아닌 파일은 무시합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>문서 파일 이름 바꾸기 제안</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>문서 파일에 대한 추천 파일명을 표시합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>문서 파일 분류 안 함(이름만 변경)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>문서 파일의 분류를 건너뛰고 이름만 변경합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>문서 생성 날짜(가능한 경우)를 카테고리 이름에 추가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>메타데이터의 문서 생성 날짜를 카테고리 라벨에 추가합니다.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>문서 분석 옵션 표시/숨기기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>분석 중지</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>폴더 분석</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>파일</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>유형</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>하위 카테고리</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>상태</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>폴더</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>준비됨</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;도움말</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>파일 탐색기</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>분석 취소 중…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>분석 중…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>카테고리 화이트리스트</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>추가</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>편집</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>제거</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>제거할 수 없음</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>기본 목록은 제거할 수 없습니다.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_nl.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"nl_NL\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>Tip: klik op %1-cellen om ze te hernoemen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>Geen items geselecteerd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>Markeer een of meer rijen om ze voor verwerking te selecteren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Bulkbewerking niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>Bulkbewerking van categorieën is niet beschikbaar zolang de modus Alleen afbeeldingen hernoemen actief is.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Markeer een of meer rijen om hun categorieën te bewerken.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Voorbeeld</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Beoordelen en bevestigen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Alles selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Gemarkeerde selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Geselecteerde bewerken...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Subcategoriemappen maken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Proefrun (alleen voorbeeld, verplaats geen bestanden)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Afbeeldingsbestanden niet categoriseren (alleen hernoemen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Documentbestanden niet categoriseren (alleen hernoemen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Bevestigen en verwerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Later doorgaan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Deze wijziging ongedaan maken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Sluiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Markeer gemarkeerde rijen voor verwerking (Ctrl+Spatie).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Pas categorie-/subcategoriewaarden toe op de gemarkeerde rijen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>Verwerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>Bestand</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Voorgestelde bestandsnaam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Categorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Subcategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Status</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Geplande bestemming</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Verplaatst</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Hernoemd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Hernoemd en verplaatst</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Overgeslagen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>Niet geselecteerd</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[STOP] Analyse stopt na het huidige item.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Beeldanalyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Documentanalyse</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Categorisatie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Map</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Afbeelding</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Document</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>Bestand</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Fase %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>In afwachting</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>Bezig</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Voltooid</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>Verwerkt 0/0  |  Bezig: 0  |  In afwachting: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>Verwerkt %1/%2  |  Bezig: %3  |  In afwachting: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Bestanden analyseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Activiteitenlogboek</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>Aangepaste OpenAI-compatibele API</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>bijv. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>bijv. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Tonen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Weergavenaam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Beschrijving</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>Basis-URL of eindpunt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Model</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>API-sleutel (optioneel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Voer een basis-URL in (bijv. http://localhost:1234/v1) of een volledig /chat/completions-eindpunt.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>Aangepast lokaal LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Bladeren…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Weergavenaam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Beschrijving</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>Modelbestand (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>.gguf-model selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>GGUF-modellen (*.gguf);;Alle bestanden (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Proefrun-voorbeeld</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>Van</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>Naar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Sluiten</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>LLM-modus kiezen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>LLM-modus selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Groter lokaal model. Langzamer op CPU, maar presteert veel beter met GPU-versnelling.\nOndersteunt: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Aanbevolen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>Kleiner lokaal model dat ook op CPU's snel werkt. Goed voor licht lokaal gebruik.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Verouderd model behouden voor bestaande downloads.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (Google AI Studio API-sleutel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Gebruik Google's Gemini-modellen met uw AI Studio-API-sleutel (internet vereist).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Tonen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Gemini-API-sleutel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>bijv. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Model</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>Uw sleutel wordt lokaal opgeslagen in het configuratiebestand van dit apparaat.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Een Gemini-API-sleutel ophalen&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (OpenAI API-sleutel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>Gebruik uw eigen OpenAI-API-sleutel om toegang te krijgen tot ChatGPT-modellen (internet vereist).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>OpenAI-API-sleutel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>bijv. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Een OpenAI-API-sleutel ophalen&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>Aangepaste OpenAI-compatibele API (geavanceerd)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>Gebruik OpenAI-compatibele eindpunten zoals LM Studio of Ollama (lokaal of extern).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Toevoegen…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Bewerken…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Verwijderen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>Aangepast lokaal LLM (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>Downloads</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>Downloaden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Beeldanalysemodellen (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Download de visuele LLM-bestanden die nodig zijn voor beeldanalyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (tekstmodel)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (visie-encoder)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Kies of voeg een aangepast model toe.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Aangepast model geselecteerd.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Selectie gereed.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Kies of voeg een aangepast API-eindpunt toe.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>Aangepaste API geselecteerd.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT gebruikt uw API-sleutel en model.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Voer uw OpenAI-API-sleutel en model in om door te gaan.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini gebruikt uw API-sleutel en model.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Voer uw Gemini-API-sleutel en model in om door te gaan.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Model gereed.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>Download hervatten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Gedeeltelijke download gedetecteerd. U kunt hervatten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>Download vereist.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Niet-ondersteunde LLM-selectie.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>Ontbrekende download-URL-omgevingsvariabele (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>Gedownload model verwijderen?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>Gedownload model %1 verwijderen?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>Kan gedownloade model niet verwijderen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>Gedownload model verwijderd.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>Geen gedownload model gevonden om te verwijderen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>Externe URL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Lokaal pad</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Bestandsgrootte</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Bestandsgrootte: onbekend</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Aangepast model verwijderen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>'%1' uit uw aangepaste LLM's verwijderen? Dit verwijdert het bestand niet van de schijf.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Aangepaste API verwijderen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>'%1' uit uw lijst met aangepaste API's verwijderen? Dit heeft geen invloed op de server.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>Ontbrekende download-URL-omgevingsvariabele.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>Bezig met downloaden…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>Download voltooid.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>Download geannuleerd.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>Downloadfout: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Bestandsverkenner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Map selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>Map %1 geladen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Analyse geannuleerd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Map geselecteerd: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Meer consistent</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Meer verfijnd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>Map opnieuw categoriseren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Deze map is gecategoriseerd met de modus %1. Wilt u deze nu opnieuw categoriseren met de modus %2?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Opnieuw categoriseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Bestaande behouden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>Kon de in cache opgeslagen categorisatie voor deze map niet resetten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>Download vereist</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>Beeldanalyse vereist visuele LLM-bestanden. Nu downloaden?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>OK</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Bezig met analyseren…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Map analyseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Gereed</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Laatste run ongedaan maken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Dit probeert bestanden terug te zetten naar hun oorspronkelijke locaties op basis van de laatste uitvoering.\n\nPlanbestand: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>%1 bestand(en) hersteld. %2 overgeslagen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Ongedaan maken voltooid</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>Bedankt voor het gebruiken van AI File Sorter! U heeft tot nu toe %1 bestanden gecategoriseerd. Ik, de auteur, hoop echt dat deze app nuttig voor u was.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter kost honderden uren ontwikkeling, feature-werk, supportreacties en doorlopende kosten zoals servers en infrastructuur voor externe modellen. Als de app u tijd bespaart of waarde biedt, overweeg dan om te ondersteunen zodat hij kan blijven verbeteren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>Al gedoneerd? Klik op \"Ik heb al gedoneerd\" om je donatiecode in te voeren en deze herinnering permanent uit te schakelen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Doneer om het donatiedialoogvenster permanent te verbergen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Ik weet het nog niet</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>Ik heb al gedoneerd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Donatiecode</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Voer de donatiecode in die na uw donatie is gegenereerd.\nEen geldige code verbergt het donatiedialoogvenster permanent.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Ongeldige donatiecode</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>De donatiecode is ongeldig. Probeer het opnieuw of klik op Annuleren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Donatiepagina openen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>Kon je browser niet automatisch openen.\nOpen deze link handmatig:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Map</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>Bestand</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARCHIEF] Reeds gecategoriseerde items:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[KLAAR] Geen bestanden om te categoriseren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[WACHTRIJ] Items in afwachting van categorisatie:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[SCAN] Verkennen van %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[VERWERKING] De AI doet zijn magie...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[VISIE] Afbeeldingsbatch %1/%2 decoderen (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>Beeldanalyse overschakelen naar de CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>De beeldanalyse heeft geen GPU-geheugen meer.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>Opnieuw proberen op de CPU? Annuleren slaat de visuele analyse over en valt terug op categorisering op basis van bestandsnamen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[VISIE-FOUT] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Visuele analyse wordt overgeschakeld naar de CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Visuele analyse uitgeschakeld; teruggevallen op bestandsnamen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[VISIE] Gebruik cachesuggestie voor %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[VISIE] Analyseren van %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] Probleem met GPU-geheugen gedetecteerd. Overschakelen naar CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Visuele analyse uitgeschakeld voor de resterende afbeeldingen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[DOC-FOUT] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[DOC] Gebruik cachesuggestie voor %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[DOC] Analyseren van %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[SORTEREN] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analyse wordt geannuleerd…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>Lokale AI overschakelen naar de CPU?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>Het lokale model kreeg een GPU-fout of had onvoldoende geheugen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>Opnieuw proberen op de CPU? Annuleren stopt deze analyse.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] Terugval van GPU naar CPU geweigerd. Analyse wordt geannuleerd.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[WAARSCHUWING] GPU-versnelling kon niet worden geïnitialiseerd. Doorgaan op CPU (langzamer).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[WAARSCHUWING] %1 wordt opnieuw gecategoriseerd: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Geselecteerde items bewerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Leeg laten om bestaande waarden te behouden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Categorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Subcategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>Over %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>Over</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Credits</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>Over de AGPL-licentie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter wordt verspreid onder de GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;U kunt de volledige broncode vinden op &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Een volledige kopie van de licentie wordt met deze applicatie meegeleverd en is online beschikbaar op &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (automatisch)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Automatisch</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (doel: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>GPU via Vulkan niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>GPU via CUDA niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>GPU via Metal niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>GPU-initialisatie mislukt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Standaardmodel: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Categorisatie meten (opwarming + %1 uitvoering(en))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Documentanalyse meten (opwarming + %1 uitvoering(en))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Categorisatie: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>gereed</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>mislukt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Opwarming: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Initialisatie: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Per item (mediaan van %1): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Uitvoeringen per item: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Details: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Backend gebruikt: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Documentanalyse: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>Model kon niet worden geladen: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>optimaal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>acceptabel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>behoorlijk lang</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>n.v.t.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Resultaat</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Categorisatiesnelheid: niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Documentanalysesnelheid: niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Categorisatiesnelheid: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Documentanalysesnelheid: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Beeldanalysesnelheid: niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Beeldanalysesnelheid: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>Aanbevolen lokale LLM-keuze: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>Je kunt LLM's wisselen via Instellingen -&gt; LLM selecteren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Compatibiliteitsbenchmark</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Voer een snelle prestatiecontrole uit om te schatten hoe beeldanalyse, documentanalyse en bestandscategorisatie op dit systeem zullen presteren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Het wordt aanbevolen om vóór het uitvoeren van deze test alle CPU- en GPU-intensieve toepassingen af te sluiten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Benchmark uitvoeren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>Dit dialoogvenster niet automatisch opnieuw tonen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Benchmark stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Sluiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>Nog geen eerdere resultaten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Laatste uitvoering: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Vorige resultaten:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>Geen gedownloade LLM-bestanden gevonden. Download een categorisatie- of visueel model om de benchmark uit te voeren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Systeemcompatibiliteitscontrole starten...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>CPU-threads gedetecteerd: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>GPU-backend geforceerd: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal beschikbaar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>ja</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>nee</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>GPU-geheugentoewijzing (Metal): %1 vrij / %2 totaal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>GPU-geheugentoewijzing (Metal): niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA beschikbaar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>CUDA-geheugen (toewijsbaar): %1 vrij / %2 totaal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (apparaat totaal: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>GPU-geheugentoewijzing (Vulkan): %1 vrij / %2 totaal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>GPU-geheugentoewijzing (Vulkan): niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>Het instellen van de tijdelijke map is mislukt; het aanmaken van het benchmarkvoorbeeldbestand kan mislukken.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>Geen standaardmodellen gedownload; categorisatie en documentcontroles worden overgeslagen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Standaardmodellen gedetecteerd: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark gestopt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Beeldanalysetest uitvoeren...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>niet beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Beeldanalyse: overgeslagen (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Beeldanalyse: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Tijd: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU uitgeschakeld door backend-override</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Backend gebruikt (beeldanalyse): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark mislukt: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] De benchmark stopt na de huidige stap.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Fout</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>Lokaal LLM (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>Lokaal LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>Ondersteun %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Verplichte update beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>Er is een verplichte update beschikbaar. Werk bij om door te gaan.\nAls u afsluiten kiest, wordt de toepassing gesloten.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Nu bijwerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Afsluiten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>Optionele update beschikbaar</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>Er is een optionele update beschikbaar. Wilt u nu bijwerken?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Deze versie overslaan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>Annuleren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Update downloaden</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Het installatieprogramma van de update wordt gedownload...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>Het installatieprogramma van de update kon niet worden voorbereid.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Installatieprogramma gereed</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Sluit de app af en start het installatieprogramma om bij te werken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Afsluiten en installatieprogramma starten</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>Het installatieprogramma kon niet worden gestart.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>Er is geen downloaddoel beschikbaar voor deze update.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>Bijwerken mislukt</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Handmatig bijwerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>Whitelist bewerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Naam:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Categorieën (door komma's gescheiden):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Subcategorieën (door komma's gescheiden):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>CUDA Toolkit ontbreekt</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>Er is een compatibele NVIDIA-GPU gedetecteerd, maar de CUDA Toolkit ontbreekt.\n\nCUDA is vereist voor GPU-versnelling in deze toepassing.\n\nWilt u het nu downloaden en installeren?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Startfout</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>CUDA en Vulkan kunnen niet tegelijkertijd worden ingeschakeld.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>GGML-runtime ontbreekt</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>Kon de runtime-DLL's van de backend niet vinden.\nGeprobeerd:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Start mislukt</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>Kon het hoofdprogramma niet starten:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Map:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Bladeren…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Subcategorieën gebruiken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Subcategorie-mappen binnen elke categorie maken.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Categorisatietype</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Kies hoe strikt de categorielabels moeten zijn.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Meer verfijnd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Geef de voorkeur aan gedetailleerde labels, ook als vergelijkbare items verschillen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Meer consistent</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Geef de voorkeur aan consistente labels voor vergelijkbare items.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Whitelist gebruiken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Beperk categorieën en subcategorieën tot de geselecteerde whitelist.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Selecteer de whitelist die voor deze run wordt gebruikt.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Bestanden categoriseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Neem bestanden op in de categorisatieronde.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Mappen categoriseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Neem mappen op in de categorisatieronde.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Submappen scannen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Bestanden in submappen scannen en behandelen alsof ze in de hoofdmap staan.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Afbeeldingsbestanden op inhoud analyseren (kan traag zijn)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Voer de visuele LLM uit op ondersteunde afbeeldingsbestanden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Alleen afbeeldingsbestanden verwerken (alle andere bestanden negeren)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Niet-afbeeldingsbestanden in deze run negeren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Voeg de aanmaakdatum van de afbeelding (indien beschikbaar) toe aan de categorienaam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Voeg de aanmaakdatum van de afbeelding uit metadata toe aan het categorielabel.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Voeg fotodatum en plaats toe aan bestandsnaam (indien beschikbaar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>De datum komt uit EXIF-metadata van de foto. Plaatsnamen worden online uit GPS-coördinaten bepaald, dus netwerktoegang is vereist voor plaatsvoorvoegsels.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Audio-/videometadata toevoegen aan bestandsnaam (indien beschikbaar)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Gebruik ingesloten mediatags (bijv. jaar, artiest, album, titel) om voorgestelde audio-/videobestandsnamen te maken.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Aanbieden om afbeeldingsbestanden te hernoemen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Toon voorgestelde bestandsnamen voor afbeeldingsbestanden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Afbeeldingsbestanden niet categoriseren (alleen hernoemen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Categorisatie voor afbeeldingsbestanden overslaan en alleen hernoemen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Opties voor afbeeldingsanalyse tonen of verbergen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Documentbestanden op inhoud analyseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Documentinhoud samenvatten met het geselecteerde LLM.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Alleen documentbestanden verwerken (alle andere bestanden negeren)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Niet-documentbestanden in deze run negeren.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Aanbieden om documentbestanden te hernoemen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Toon voorgestelde bestandsnamen voor documentbestanden.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Documentbestanden niet categoriseren (alleen hernoemen)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Categorisatie voor documentbestanden overslaan en alleen hernoemen.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Voeg de aanmaakdatum van het document (indien beschikbaar) toe aan de categorienaam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Voeg de aanmaakdatum van het document uit metadata toe aan het categorielabel.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Opties voor documentanalyse tonen of verbergen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Analyse stoppen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Map analyseren</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>Bestand</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Type</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Categorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Subcategorie</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Status</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Map</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Gereed</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Help</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Bestandsverkenner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analyse wordt geannuleerd…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Bezig met analyseren…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Categorie-whitelists</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Toevoegen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Bewerken</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Verwijderen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>Kan niet worden verwijderd</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>De standaardlijst kan niet worden verwijderd.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/i18n/aifilesorter_tr.ts",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<TS version=\"2.1\" language=\"tr_TR\">\n    <context>\n        <name>CategorizationDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"420\" />\n            <source>Tip: Click %1 cells to rename them.</source>\n            <translation>İpucu: Yeniden adlandırmak için %1 hücrelerine tıklayın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1936\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2088\" />\n            <source>No items selected</source>\n            <translation>Hiç öğe seçilmedi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"1937\" />\n            <source>Highlight one or more rows to select them for processing.</source>\n            <translation>İşleme için seçmek üzere bir veya daha fazla satırı vurgulayın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2081\" />\n            <source>Bulk edit unavailable</source>\n            <translation>Toplu düzenleme kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2082\" />\n            <source>Bulk editing categories is unavailable while picture rename-only mode is active.</source>\n            <translation>Resimlerde yalnızca yeniden adlandırma modu etkinken kategorilerin toplu düzenlenmesi kullanılamaz.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2089\" />\n            <source>Highlight one or more rows to edit their categories.</source>\n            <translation>Kategorilerini düzenlemek için bir veya daha fazla satırı vurgulayın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2738\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2846\" />\n            <source>Preview</source>\n            <translation>Önizleme</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2775\" />\n            <source>Review and Confirm</source>\n            <translation>Gözden geçir ve onayla</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2783\" />\n            <source>Select all</source>\n            <translation>Tümünü seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2784\" />\n            <source>Select highlighted</source>\n            <translation>Vurgulananları seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2785\" />\n            <source>Edit selected...</source>\n            <translation>Seçilenleri düzenle...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2786\" />\n            <source>Create subcategory folders</source>\n            <translation>Alt kategori klasörleri oluştur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2787\" />\n            <source>Dry run (preview only, do not move files)</source>\n            <translation>Deneme çalıştırma (yalnızca önizleme, dosyaları taşıma)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2788\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Resim dosyalarını kategorize etme (yalnızca yeniden adlandır)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2789\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Belge dosyalarını kategorize etme (yalnızca yeniden adlandır)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2790\" />\n            <source>Confirm and Process</source>\n            <translation>Onayla ve işle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2791\" />\n            <source>Continue Later</source>\n            <translation>Daha sonra devam et</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2792\" />\n            <source>Undo this change</source>\n            <translation>Bu değişikliği geri al</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2793\" />\n            <source>Close</source>\n            <translation>Kapat</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2796\" />\n            <source>Mark highlighted rows for processing (Ctrl+Space).</source>\n            <translation>Vurgulanan satırları işleme için işaretleyin (Ctrl+Boşluk).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2799\" />\n            <source>Apply category/subcategory values to highlighted rows.</source>\n            <translation>Kategori/alt kategori değerlerini vurgulanan satırlara uygulayın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2804\" />\n            <source>Process</source>\n            <translation>İşle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2805\" />\n            <source>File</source>\n            <translation>Dosya</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2806\" />\n            <source>Type</source>\n            <translation>Tür</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2807\" />\n            <source>Suggested filename</source>\n            <translation>Önerilen dosya adı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2808\" />\n            <source>Category</source>\n            <translation>Kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2809\" />\n            <source>Subcategory</source>\n            <translation>Alt kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2810\" />\n            <source>Status</source>\n            <translation>Durum</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2811\" />\n            <source>Planned destination</source>\n            <translation>Planlanan hedef</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2834\" />\n            <source>Moved</source>\n            <translation>Taşındı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2837\" />\n            <source>Renamed</source>\n            <translation>Yeniden adlandırıldı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2840\" />\n            <source>Renamed &amp; Moved</source>\n            <translation>Yeniden adlandırıldı ve taşındı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2843\" />\n            <source>Skipped</source>\n            <translation>Atlandı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"2849\" />\n            <source>Not selected</source>\n            <translation>Seçilmedi</translation>\n        </message>\n    </context>\n    <context>\n        <name>CategorizationProgressDialog</name>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"270\" />\n            <source>[STOP] Analysis will stop after the current item is processed.</source>\n            <translation>[DUR] Analiz, geçerli öğe işlendiğinde duracaktır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"302\" />\n            <source>Image analysis</source>\n            <translation>Görüntü analizi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"304\" />\n            <source>Document analysis</source>\n            <translation>Belge analizi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"307\" />\n            <source>Categorization</source>\n            <translation>Kategorizasyon</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"331\" />\n            <source>Directory</source>\n            <translation>Klasör</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"333\" />\n            <source>Image</source>\n            <translation>Görsel</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"335\" />\n            <source>Document</source>\n            <translation>Belge</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"338\" />\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>File</source>\n            <translation>Dosya</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"493\" />\n            <source>Type</source>\n            <translation>Tür</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"526\" />\n            <source>Stage %1: %2</source>\n            <translation>Aşama %1: %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"633\" />\n            <source>Pending</source>\n            <translation>Beklemede</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"638\" />\n            <source>In progress</source>\n            <translation>Devam ediyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"642\" />\n            <source>Complete</source>\n            <translation>Tamamlandı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"659\" />\n            <source>Processed 0/0  |  In progress: 0  |  Pending: 0</source>\n            <translation>İşlenen 0/0  |  Devam eden: 0  |  Bekleyen: 0</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"694\" />\n            <source>Processed %1/%2  |  In progress: %3  |  Pending: %4</source>\n            <translation>İşlenen %1/%2  |  Devam eden: %3  |  Bekleyen: %4</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"750\" />\n            <source>Analyzing Files</source>\n            <translation>Dosyalar analiz ediliyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"752\" />\n            <source>Stop Analysis</source>\n            <translation>Analizi durdur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationProgressDialog.cpp\" line=\"755\" />\n            <source>Activity log</source>\n            <translation>Etkinlik günlüğü</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomApiDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"30\" />\n            <source>Custom OpenAI-compatible API</source>\n            <translation>Özel OpenAI uyumlu API</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"39\" />\n            <source>e.g. http://localhost:1234/v1</source>\n            <translation>ör. http://localhost:1234/v1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"42\" />\n            <source>e.g. llama-3.1, gpt-4o-mini</source>\n            <translation>ör. llama-3.1, gpt-4o-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"47\" />\n            <source>Show</source>\n            <translation>Göster</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"54\" />\n            <source>Display name</source>\n            <translation>Görünen ad</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"55\" />\n            <source>Description</source>\n            <translation>Açıklama</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"56\" />\n            <source>Base URL or endpoint</source>\n            <translation>Temel URL veya uç nokta</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"57\" />\n            <source>Model</source>\n            <translation>Model</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"58\" />\n            <source>API key (optional)</source>\n            <translation>API anahtarı (isteğe bağlı)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomApiDialog.cpp\" line=\"62\" />\n            <source>Enter a base URL (e.g. http://localhost:1234/v1) or a full /chat/completions endpoint.</source>\n            <translation>Bir temel URL girin (ör. http://localhost:1234/v1) ya da tam bir /chat/completions uç noktası girin.</translation>\n        </message>\n    </context>\n    <context>\n        <name>CustomLLMDialog</name>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"31\" />\n            <source>Custom local LLM</source>\n            <translation>Özel yerel LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"39\" />\n            <source>Browse…</source>\n            <translation>Gözat…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"44\" />\n            <source>Display name</source>\n            <translation>Görünen ad</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"45\" />\n            <source>Description</source>\n            <translation>Açıklama</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"46\" />\n            <source>Model file (.gguf)</source>\n            <translation>Model dosyası (.gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"86\" />\n            <source>Select .gguf model</source>\n            <translation>.gguf modeli seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CustomLLMDialog.cpp\" line=\"88\" />\n            <source>GGUF models (*.gguf);;All files (*.*)</source>\n            <translation>GGUF modelleri (*.gguf);;Tüm dosyalar (*.*)</translation>\n        </message>\n    </context>\n    <context>\n        <name>DryRunPreviewDialog</name>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"12\" />\n            <source>Dry run preview</source>\n            <translation>Deneme çalıştırma önizlemesi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>From</source>\n            <translation>Kaynak</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source />\n            <translation />\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"23\" />\n            <source>To</source>\n            <translation>Hedef</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DryRunPreviewDialog.cpp\" line=\"50\" />\n            <source>Close</source>\n            <translation>Kapat</translation>\n        </message>\n    </context>\n    <context>\n        <name>LLMSelectionDialog</name>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"108\" />\n            <source>Choose LLM Mode</source>\n            <translation>LLM modunu seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"206\" />\n            <source>Select LLM Mode</source>\n            <translation>LLM modunu seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"218\" />\n            <source>Larger local model. Slower on CPU, but performs much better with GPU acceleration.\nSupports: Nvidia (CUDA), Apple (Metal), CPU.</source>\n            <translation>Daha büyük yerel model. CPU'da daha yavaştır, ancak GPU hızlandırmasıyla çok daha iyi performans gösterir.\nDestekler: Nvidia (CUDA), Apple (Metal), CPU.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"226\" />\n            <source>Recommended</source>\n            <translation>Önerilen</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"231\" />\n            <source>Smaller local model that works quickly even on CPUs. Good for lightweight local use.</source>\n            <translation>CPU'larda bile hızlı çalışan daha küçük yerel model. Hafif yerel kullanım için uygundur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"236\" />\n            <source>Legacy model kept for existing downloads.</source>\n            <translation>Eski model, mevcut indirmeler için korunur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"242\" />\n            <source>Gemini (Google AI Studio API key)</source>\n            <translation>Gemini (Google AI Studio API anahtarı)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"244\" />\n            <source>Use Google's Gemini models with your AI Studio API key (internet required).</source>\n            <translation>Google'ın Gemini modellerini AI Studio API anahtarınızla kullanın (internet gerekir).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"254\" />\n            <source>AIza...</source>\n            <translation>AIza...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"255\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"295\" />\n            <source>Show</source>\n            <translation>Göster</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"261\" />\n            <source>Gemini API key</source>\n            <translation>Gemini API anahtarı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"266\" />\n            <source>e.g. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</source>\n            <translation>ör. gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"267\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"308\" />\n            <source>Model</source>\n            <translation>Model</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"271\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"313\" />\n            <source>Your key is stored locally in the config file for this device.</source>\n            <translation>Anahtarınız bu cihazdaki yapılandırma dosyasında yerel olarak saklanır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"278\" />\n            <source>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Get a Gemini API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://aistudio.google.com/app/apikey\"&gt;Gemini API anahtarı alın&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"282\" />\n            <source>ChatGPT (OpenAI API key)</source>\n            <translation>ChatGPT (OpenAI API anahtarı)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"284\" />\n            <source>Use your own OpenAI API key to access ChatGPT models (internet required).</source>\n            <translation>ChatGPT modellerine erişmek için kendi OpenAI API anahtarınızı kullanın (internet gerekir).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"294\" />\n            <source>sk-...</source>\n            <translation>sk-...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"301\" />\n            <source>OpenAI API key</source>\n            <translation>OpenAI API anahtarı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"307\" />\n            <source>e.g. gpt-4o-mini, gpt-4.1, o3-mini</source>\n            <translation>ör. gpt-4o-mini, gpt-4.1, o3-mini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"322\" />\n            <source>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;Get an OpenAI API key&lt;/a&gt;</source>\n            <translation>&lt;a href=\"https://platform.openai.com/api-keys\"&gt;OpenAI API anahtarı alın&lt;/a&gt;</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"327\" />\n            <source>Custom OpenAI-compatible API (advanced)</source>\n            <translation>Özel OpenAI uyumlu API (gelişmiş)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"330\" />\n            <source>Use OpenAI-compatible endpoints such as LM Studio or Ollama (local or remote).</source>\n            <translation>LM Studio veya Ollama gibi OpenAI uyumlu uç noktaları kullanın (yerel ya da uzak).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"341\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"364\" />\n            <source>Add…</source>\n            <translation>Ekle…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"342\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"365\" />\n            <source>Edit…</source>\n            <translation>Düzenle…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"343\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"366\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"456\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1320\" />\n            <source>Delete</source>\n            <translation>Sil</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"354\" />\n            <source>Custom local LLM (gguf)</source>\n            <translation>Özel yerel LLM (gguf)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"409\" />\n            <source>Downloads</source>\n            <translation>İndirilenler</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"454\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"945\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1318\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1475\" />\n            <source>Download</source>\n            <translation>İndir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"477\" />\n            <source>Image analysis models (LLaVA)</source>\n            <translation>Görüntü analizi modelleri (LLaVA)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"479\" />\n            <source>Download the visual LLM files required for image analysis.</source>\n            <translation>Görüntü analizi için gerekli görsel LLM dosyalarını indirin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"485\" />\n            <source>LLaVA 1.6 Mistral 7B (text model)</source>\n            <translation>LLaVA 1.6 Mistral 7B (metin modeli)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"491\" />\n            <source>LLaVA mmproj (vision encoder)</source>\n            <translation>LLaVA mmproj (görüntü kodlayıcı)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Choose or add a custom model.</source>\n            <translation>Özel bir model seçin veya ekleyin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"746\" />\n            <source>Custom model selected.</source>\n            <translation>Özel model seçildi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"767\" />\n            <source>Selection ready.</source>\n            <translation>Seçim hazır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"811\" />\n            <source>Choose or add a custom API endpoint.</source>\n            <translation>Özel bir API uç noktası seçin veya ekleyin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"812\" />\n            <source>Custom API selected.</source>\n            <translation>Özel API seçildi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"831\" />\n            <source>ChatGPT will use your API key and model.</source>\n            <translation>ChatGPT API anahtarınızı ve modelinizi kullanacak.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"832\" />\n            <source>Enter your OpenAI API key and model to continue.</source>\n            <translation>Devam etmek için OpenAI API anahtarınızı ve modelinizi girin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"864\" />\n            <source>Gemini will use your API key and model.</source>\n            <translation>Gemini API anahtarınızı ve modelinizi kullanacak.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"865\" />\n            <source>Enter your Gemini API key and model to continue.</source>\n            <translation>Devam etmek için Gemini API anahtarınızı ve modelinizi girin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"923\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1449\" />\n            <source>Model ready.</source>\n            <translation>Model hazır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"929\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1458\" />\n            <source>Resume download</source>\n            <translation>İndirmeye devam et</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"937\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1464\" />\n            <source>Partial download detected. You can resume.</source>\n            <translation>Kısmi indirme tespit edildi. Devam edebilirsiniz.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"953\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1481\" />\n            <source>Download required.</source>\n            <translation>İndirme gerekli.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"964\" />\n            <source>Unsupported LLM selection.</source>\n            <translation>Desteklenmeyen LLM seçimi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"971\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1368\" />\n            <source>Missing download URL environment variable (%1).</source>\n            <translation>İndirme URL'si ortam değişkeni eksik (%1).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1003\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1587\" />\n            <source>Delete downloaded model?</source>\n            <translation>İndirilen modeli sil?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1004\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1588\" />\n            <source>Delete the downloaded model %1?</source>\n            <translation>İndirilen model %1 silinsin mi?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1028\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1612\" />\n            <source>Failed to delete downloaded model.</source>\n            <translation>İndirilen model silinemedi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1030\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1614\" />\n            <source>Deleted downloaded model.</source>\n            <translation>İndirilen model silindi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1032\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1616\" />\n            <source>No downloaded model found to delete.</source>\n            <translation>Silinecek indirilen model bulunamadı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1047\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1410\" />\n            <source>Remote URL</source>\n            <translation>Uzak URL</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1051\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1415\" />\n            <source>Local path</source>\n            <translation>Yerel yol</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1060\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1426\" />\n            <source>File size</source>\n            <translation>Dosya boyutu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1064\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1430\" />\n            <source>File size: unknown</source>\n            <translation>Dosya boyutu: bilinmiyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1225\" />\n            <source>Delete custom model</source>\n            <translation>Özel modeli sil</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1226\" />\n            <source>Remove '%1' from your custom LLMs? This does not delete the file on disk.</source>\n            <translation>'%1' özel LLM listenizden kaldırılsın mı? Bu işlem diskteki dosyayı silmez.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1248\" />\n            <source>Delete custom API</source>\n            <translation>Özel API'yi sil</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1249\" />\n            <source>Remove '%1' from your custom API list? This does not affect the server.</source>\n            <translation>'%1' özel API listenizden kaldırılsın mı? Bu işlem sunucuyu etkilemez.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1357\" />\n            <source>Missing download URL environment variable.</source>\n            <translation>İndirme URL'si ortam değişkeni eksik.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1531\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1717\" />\n            <source>Downloading…</source>\n            <translation>İndiriliyor…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1546\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1731\" />\n            <source>Download complete.</source>\n            <translation>İndirme tamamlandı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1567\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1748\" />\n            <source>Download cancelled.</source>\n            <translation>İndirme iptal edildi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1569\" />\n            <location filename=\"../../lib/LLMSelectionDialog.cpp\" line=\"1750\" />\n            <source>Download error: %1</source>\n            <translation>İndirme hatası: %1</translation>\n        </message>\n    </context>\n    <context>\n        <name>MainApp</name>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"554\" />\n            <source>File Explorer</source>\n            <translation>Dosya gezgini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"650\" />\n            <source>Select Directory</source>\n            <translation>Klasör seç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1065\" />\n            <source>Loaded folder %1</source>\n            <translation>%1 klasörü yüklendi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2156\" />\n            <source>Analysis cancelled</source>\n            <translation>Analiz iptal edildi</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1429\" />\n            <source>Folder selected: %1</source>\n            <translation>Seçilen klasör: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More consistent</source>\n            <translation>Daha tutarlı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1519\" />\n            <source>More refined</source>\n            <translation>Daha ayrıntılı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1524\" />\n            <source>Recategorize folder?</source>\n            <translation>Klasör yeniden kategorilendirilsin mi?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1525\" />\n            <source>This folder was categorized using the %1 mode. Do you want to recategorize it now using the %2 mode?</source>\n            <translation>Bu klasör %1 modunda kategorilendirildi. Şimdi %2 moduyla yeniden kategorilendirmek ister misiniz?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1527\" />\n            <source>Recategorize</source>\n            <translation>Yeniden kategorilendir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1528\" />\n            <source>Keep existing</source>\n            <translation>Mevcut kalsın</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1538\" />\n            <source>Failed to reset cached categorization for this folder.</source>\n            <translation>Bu klasör için önbellekteki kategorilendirme sıfırlanamadı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1806\" />\n            <source>Download required</source>\n            <translation>İndirme gerekli</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1807\" />\n            <source>Image analysis requires visual LLM files. Download them now?</source>\n            <translation>Görüntü analizi için görsel LLM dosyaları gerekir. Şimdi indirilsin mi?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1808\" />\n            <source>OK</source>\n            <translation>Tamam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1843\" />\n            <source>Stop analyzing</source>\n            <translation>Analizi durdur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1844\" />\n            <source>Analyzing…</source>\n            <translation>Analiz ediliyor…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1847\" />\n            <source>Analyze folder</source>\n            <translation>Klasörü analiz et</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1848\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2192\" />\n            <source>Ready</source>\n            <translation>Hazır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1932\" />\n            <source>Undo last run</source>\n            <translation>Son çalıştırmayı geri al</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1933\" />\n            <source>This will attempt to move files back to their original locations based on the last run.\n\nPlan file: %1</source>\n            <translation>Son çalıştırmaya göre dosyaları özgün konumlarına geri taşımaya çalışır.\n\nPlan dosyası: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1942\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1960\" />\n            <source>Restored %1 file(s). Skipped %2.</source>\n            <translation>%1 dosya geri yüklendi. %2 atlandı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1948\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1965\" />\n            <source>Undo complete</source>\n            <translation>Geri alma tamamlandı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1975\" />\n            <source>Thank you for using AI File Sorter! You have categorized %1 files thus far. I, the author, really hope this app was useful for you.</source>\n            <translation>AI File Sorter'ı kullandığınız için teşekkürler! Şimdiye kadar %1 dosyayı kategorilendirdiniz. Geliştirici olarak umarım bu uygulama sizin için faydalı olmuştur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1977\" />\n            <source>AI File Sorter takes hundreds of hours of development, feature work, support replies, and ongoing costs such as servers and remote-model infrastructure. If the app saves you time or brings value, please consider supporting it so it can keep improving.</source>\n            <translation>AI File Sorter yüzlerce saatlik geliştirme, özellik çalışması, destek yanıtları ve sunucular ile uzak model altyapısı gibi sürekli maliyetler gerektirir. Uygulama size zaman kazandırıyor veya değer sağlıyorsa, gelişmeye devam edebilmesi için desteklemeyi düşünün.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1979\" />\n            <source>Already donated? Click \"I have already donated\" to enter your donation code and permanently disable this reminder.</source>\n            <translation>Zaten bağış yaptınız mı? Bağış kodunuzu girmek ve bu hatırlatmayı kalıcı olarak kapatmak için \"Zaten bağış yaptım\" seçeneğine tıklayın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1984\" />\n            <source>Donate to permanently hide the donation dialog</source>\n            <translation>Bağış iletişim kutusunu kalıcı olarak gizlemek için bağış yap</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1985\" />\n            <source>I'm not yet sure</source>\n            <translation>Henüz emin değilim</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1986\" />\n            <source>I have already donated</source>\n            <translation>Zaten bağış yaptım</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2079\" />\n            <source>Donation code</source>\n            <translation>Bağış kodu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2080\" />\n            <source>Enter the donation code generated after your donation.\nA valid code will permanently hide the donation dialog.</source>\n            <translation>Bağışınızdan sonra oluşturulan bağış kodunu girin.\nGeçerli bir kod bağış iletişim kutusunu kalıcı olarak gizler.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2095\" />\n            <source>Invalid donation code</source>\n            <translation>Geçersiz bağış kodu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2096\" />\n            <source>The donation code is invalid. Please try again or press Cancel.</source>\n            <translation>Bağış kodu geçersiz. Lütfen tekrar deneyin veya İptal'e basın.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2105\" />\n            <source>Open donation page</source>\n            <translation>Bağış sayfasını aç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2106\" />\n            <source>Could not open your browser automatically.\nPlease open this link manually:\n%1</source>\n            <translation>Tarayıcınız otomatik olarak açılamadı.\nLütfen bu bağlantıyı elle açın:\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>Directory</source>\n            <translation>Klasör</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2188\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2294\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2319\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3587\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3646\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3708\" />\n            <source>File</source>\n            <translation>Dosya</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2292\" />\n            <source>[ARCHIVE] Already categorized highlights:</source>\n            <translation>[ARŞİV] Zaten kategorize edilen öğeler:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2313\" />\n            <source>[DONE] No files to categorize.</source>\n            <translation>[BİTTİ] Kategorize edilecek dosya yok.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2317\" />\n            <source>[QUEUE] Items waiting for categorization:</source>\n            <translation>[SIRA] Kategorizasyon için bekleyen öğeler:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2338\" />\n            <source>[SCAN] Exploring %1</source>\n            <translation>[TARAMA] %1 keşfediliyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2746\" />\n            <source>[PROCESS] Letting the AI do its magic...</source>\n            <translation>[İŞLEM] Yapay zeka sihrini yapıyor...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2928\" />\n            <source>[VISION] Decoding image batch %1/%2 (%3%)</source>\n            <translation>[GÖRSEL] Görüntü grubu %1/%2 çözümleniyor (%3%)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2947\" />\n            <source>Switch image analysis to CPU?</source>\n            <translation>Görüntü analizi CPU'ya geçirilsin mi?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2948\" />\n            <source>Image analysis ran out of GPU memory.</source>\n            <translation>Görüntü analizi GPU belleğini tüketti.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2949\" />\n            <source>Retry on CPU instead? Cancel will skip visual analysis and fall back to filename-based categorization.</source>\n            <translation>Bunun yerine CPU'da yeniden denensin mi? İptal, görsel analizi atlayıp dosya adına dayalı kategorizasyona döner.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"2986\" />\n            <source>[VISION-ERROR] %1 (%2)</source>\n            <translation>[GÖRSEL-HATA] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3047\" />\n            <source>[VISION] Switching visual analysis to CPU.</source>\n            <translation>[VISION] Görsel analiz CPU'ya geçiriliyor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3077\" />\n            <source>[VISION-ERROR] %1</source>\n            <translation>[VISION-ERROR] %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3080\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3222\" />\n            <source>[VISION] Visual analysis disabled; falling back to filenames.</source>\n            <translation>[VISION] Görsel analiz devre dışı; dosya adlarına geri dönülüyor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3117\" />\n            <source>[VISION] Using cached suggestion for %1</source>\n            <translation>[GÖRSEL] %1 için önbellekteki öneri kullanılıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3145\" />\n            <source>[VISION] Analyzing %1</source>\n            <translation>[GÖRSEL] %1 analiz ediliyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3190\" />\n            <source>[VISION] GPU memory issue detected. Switching to CPU.</source>\n            <translation>[VISION] GPU bellek sorunu algılandı. CPU'ya geçiliyor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3210\" />\n            <source>[VISION] Visual analysis disabled for remaining images.</source>\n            <translation>[VISION] Kalan görseller için görsel analiz devre dışı bırakıldı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3286\" />\n            <source>[DOC-ERROR] %1 (%2)</source>\n            <translation>[BELGE-HATA] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3355\" />\n            <source>[DOC] Using cached suggestion for %1</source>\n            <translation>[BELGE] %1 için önbellekteki öneri kullanılıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3375\" />\n            <source>[DOC] Analyzing %1</source>\n            <translation>[BELGE] %1 analiz ediliyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3588\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3647\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3709\" />\n            <source>[SORT] %1 (%2)</source>\n            <translation>[SIRALAMA] %1 (%2)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3834\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analiz iptal ediliyor…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3847\" />\n            <source>Switch local AI to CPU?</source>\n            <translation>Yerel yapay zeka CPU'ya geçirilsin mi?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3848\" />\n            <source>The local model encountered a GPU error or ran out of memory.</source>\n            <translation>Yerel model bir GPU hatasıyla karşılaştı veya belleği tükendi.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3849\" />\n            <source>Retry on CPU instead? Cancel will stop this analysis.</source>\n            <translation>Bunun yerine CPU'da yeniden denensin mi? İptal, bu analizi durdurur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"3869\" />\n            <source>[WARN] GPU fallback to CPU declined. Cancelling analysis.</source>\n            <translation>[WARN] GPU'dan CPU'ya geri dönüş reddedildi. Analiz iptal ediliyor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4024\" />\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4056\" />\n            <source>[WARN] GPU acceleration failed to initialize. Continuing on CPU (slower).</source>\n            <translation>[UYARI] GPU hızlandırması başlatılamadı. CPU ile devam ediliyor (daha yavaş).</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"4078\" />\n            <source>[WARN] %1 will be re-categorized: %2</source>\n            <translation>[UYARI] %1 yeniden kategorize edilecek: %2</translation>\n        </message>\n    </context>\n    <context>\n        <name>QObject</name>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"113\" />\n            <source>Edit selected items</source>\n            <translation>Seçili öğeleri düzenle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"119\" />\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"124\" />\n            <source>Leave empty to keep existing</source>\n            <translation>Mevcut değeri korumak için boş bırakın</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"120\" />\n            <source>Category</source>\n            <translation>Kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/CategorizationDialog.cpp\" line=\"125\" />\n            <source>Subcategory</source>\n            <translation>Alt kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"37\" />\n            <source>About %1</source>\n            <translation>%1 hakkında</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"77\" />\n            <source>About</source>\n            <translation>Hakkında</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"104\" />\n            <source>Credits</source>\n            <translation>Emeği geçenler</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"116\" />\n            <source>About the AGPL License</source>\n            <translation>AGPL lisansı hakkında</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainAppHelpActions.cpp\" line=\"121\" />\n            <source>AI File Sorter is distributed under the GNU Affero General Public License v3.0.&lt;br&gt;&lt;br&gt;You can access the full source code at &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;A full copy of the license is provided with this application and available online at &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt;.</source>\n            <translation>AI File Sorter, GNU Affero General Public License v3.0 kapsamında dağıtılmaktadır.&lt;br&gt;&lt;br&gt;Tam kaynak koduna şu adresten erişebilirsiniz: &lt;a href=\"https://github.com/hyperfield/ai-file-sorter\"&gt;github.com/hyperfield/ai-file-sorter&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Lisansın tam kopyası uygulama ile birlikte gelir ve çevrimiçi olarak &lt;a href=\"https://www.gnu.org/licenses/agpl-3.0.html\"&gt;gnu.org&lt;/a&gt; adresinde bulunur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"406\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"451\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"628\" />\n            <source>CPU</source>\n            <translation>CPU</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"409\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"448\" />\n            <source>Metal</source>\n            <translation>Metal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"412\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"445\" />\n            <source>CUDA</source>\n            <translation>CUDA</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"415\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"442\" />\n            <source>Vulkan</source>\n            <translation>Vulkan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"419\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"429\" />\n            <source>Metal (auto)</source>\n            <translation>Metal (otomatik)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"421\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"431\" />\n            <source>Vulkan (auto)</source>\n            <translation>Vulkan (otomatik)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"426\" />\n            <source>%1 (auto)</source>\n            <translation>%1 (otomatik)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"438\" />\n            <source>Auto</source>\n            <translation>Otomatik</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"630\" />\n            <source>CPU (%1)</source>\n            <translation>CPU (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"635\" />\n            <source>GPU (target: %1)</source>\n            <translation>GPU (hedef: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"649\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1799\" />\n            <source>GPU via Vulkan unavailable</source>\n            <translation>Vulkan üzerinden GPU kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"651\" />\n            <source>GPU via CUDA unavailable</source>\n            <translation>CUDA üzerinden GPU kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"653\" />\n            <source>Vulkan unavailable</source>\n            <translation>Vulkan kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"656\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1802\" />\n            <source>GPU via Metal unavailable</source>\n            <translation>Metal üzerinden GPU kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"658\" />\n            <source>GPU init failed</source>\n            <translation>GPU başlatma başarısız</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1079\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1081\" />\n            <source>Default model: %1</source>\n            <translation>Varsayılan model: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1103\" />\n            <source>    Measuring categorization (warm-up + %1 run(s))...</source>\n            <translation>    Kategorilendirme ölçülüyor (ısınma + %1 çalıştırma(lar))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1133\" />\n            <source>    Measuring document analysis (warm-up + %1 run(s))...</source>\n            <translation>    Belge analizi ölçülüyor (ısınma + %1 çalıştırma(lar))...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1194\" />\n            <source>Categorization: %1</source>\n            <translation>Kategorilendirme: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>done</source>\n            <translation>tamamlandı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1195\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1241\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1774\" />\n            <source>failed</source>\n            <translation>başarısız</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1197\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1211\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1243\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1257\" />\n            <source>    Warm-up: %1</source>\n            <translation>    Isınma: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1199\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1213\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1245\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1259\" />\n            <source>    Init: %1</source>\n            <translation>    Başlatma: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1201\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1215\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1247\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1261\" />\n            <source>    Per-item (median of %1): %2</source>\n            <translation>    Öğe başına (%1 medyanı): %2</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1204\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1218\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1250\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1264\" />\n            <source>    Per-item runs: %1</source>\n            <translation>    Öğe başına çalıştırmalar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1235\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1281\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1778\" />\n            <source>Details: %1</source>\n            <translation>Ayrıntılar: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1238\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1284\" />\n            <source>Backend used: %1</source>\n            <translation>Kullanılan arka uç: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1240\" />\n            <source>Document analysis: %1</source>\n            <translation>Belge analizi: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1291\" />\n            <source>Model failed to load: %1</source>\n            <translation>Model yüklenemedi: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1305\" />\n            <source>optimal</source>\n            <translation>optimal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1307\" />\n            <source>acceptable</source>\n            <translation>kabul edilebilir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1309\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1311\" />\n            <source>a bit long</source>\n            <translation>oldukça uzun</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1332\" />\n            <source>n/a</source>\n            <translation>uygulanamaz</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1349\" />\n            <source>Result</source>\n            <translation>Sonuç</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1352\" />\n            <source>Categorization speed: unavailable</source>\n            <translation>Sınıflandırma hızı: kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1353\" />\n            <source>Document analysis speed: unavailable</source>\n            <translation>Belge analizi hızı: kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1365\" />\n            <source>Categorization speed: %1</source>\n            <translation>Sınıflandırma hızı: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1366\" />\n            <source>Document analysis speed: %1</source>\n            <translation>Belge analizi hızı: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1370\" />\n            <source>Image analysis speed: unavailable</source>\n            <translation>Görüntü analizi hızı: kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1374\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1376\" />\n            <source>Image analysis speed: %1</source>\n            <translation>Görüntü analizi hızı: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1422\" />\n            <source>Recommended Local LLM choice: %1</source>\n            <translation>Önerilen yerel LLM seçimi: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1428\" />\n            <source>You can toggle LLMs in Settings -&gt; Select LLM</source>\n            <translation>LLM'leri Ayarlar -&gt; LLM seç bölümünden değiştirebilirsiniz</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1500\" />\n            <source>Compatibility Benchmark</source>\n            <translation>Uyumluluk kıyaslaması</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1502\" />\n            <source>Run a quick performance check to estimate how image analysis, document analysis, and file categorization will perform on your system.</source>\n            <translation>Bu sistemde görüntü analizi, belge analizi ve dosya kategorilendirmenin nasıl performans göstereceğini tahmin etmek için hızlı bir performans kontrolü yapar.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1503\" />\n            <source>It is recommended to quit any CPU- and GPU-intensive applications before running this test.</source>\n            <translation>Bu testi çalıştırmadan önce CPU ve GPU yoğun uygulamaları kapatmanız önerilir.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1508\" />\n            <source>Run benchmark</source>\n            <translation>Benchmark'ı çalıştır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1511\" />\n            <source>Do not auto-show this dialog again</source>\n            <translation>Bu iletişim kutusunu otomatik olarak tekrar gösterme</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1514\" />\n            <source>Stop Benchmark</source>\n            <translation>Benchmark durdur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1517\" />\n            <source>Close</source>\n            <translation>Kapat</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1551\" />\n            <source>No previous results yet.</source>\n            <translation>Henüz önceki sonuç yok.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1557\" />\n            <source>Last run: %1</source>\n            <translation>Son çalışma: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1559\" />\n            <source>Previous results:</source>\n            <translation>Önceki sonuçlar:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1596\" />\n            <source>No downloaded LLM files detected. Download a categorization or visual model to run the benchmark.</source>\n            <translation>İndirilen LLM dosyası algılanmadı. Benchmark'ı çalıştırmak için bir kategorilendirme veya görsel model indirin.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1656\" />\n            <source>Starting system compatibility check...</source>\n            <translation>Sistem uyumluluk denetimi başlatılıyor...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1667\" />\n            <source>CPU threads detected: %1</source>\n            <translation>CPU iş parçacıkları algılandı: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1672\" />\n            <source>GPU backend override: %1</source>\n            <translation>GPU arka uç zorlaması: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1682\" />\n            <source>Metal available: %1</source>\n            <translation>Metal kullanılabilir: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>yes</source>\n            <translation>evet</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1683\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1695\" />\n            <source>no</source>\n            <translation>hayır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1686\" />\n            <source>GPU memory allocation (Metal): %1 free / %2 total</source>\n            <translation>GPU bellek ayırma (Metal): %1 boş / %2 toplam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1690\" />\n            <source>GPU memory allocation (Metal): unavailable</source>\n            <translation>GPU bellek ayırma (Metal): kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1694\" />\n            <source>CUDA available: %1</source>\n            <translation>CUDA kullanılabilir: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1699\" />\n            <source>CUDA memory (allocatable): %1 free / %2 total</source>\n            <translation>CUDA belleği (ayrılabilir): %1 boş / %2 toplam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1703\" />\n            <source> (device total: %1)</source>\n            <translation> (cihaz toplamı: %1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1712\" />\n            <source>GPU memory allocation (Vulkan): %1 free / %2 total</source>\n            <translation>GPU bellek ayırma (Vulkan): %1 boş / %2 toplam</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1716\" />\n            <source>GPU memory allocation (Vulkan): unavailable</source>\n            <translation>GPU bellek ayırma (Vulkan): kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1730\" />\n            <source>Temporary directory setup failed; benchmark sample file creation may fail.</source>\n            <translation>Geçici dizin kurulumu başarısız oldu; kıyaslama örnek dosyası oluşturma başarısız olabilir.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1734\" />\n            <source>No default models downloaded; skipping categorization and document checks.</source>\n            <translation>Varsayılan model indirilmedi; kategorilendirme ve belge kontrolleri atlanıyor.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1736\" />\n            <source>Default models detected: %1</source>\n            <translation>Varsayılan modeller algılandı: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1749\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1759\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1783\" />\n            <source>Benchmark stopped.</source>\n            <translation>Benchmark durduruldu.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1755\" />\n            <source>Running image analysis test...</source>\n            <translation>Görüntü analizi testi çalıştırılıyor...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1767\" />\n            <source>unavailable</source>\n            <translation>kullanılamıyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1769\" />\n            <source>Image analysis: skipped (%1)</source>\n            <translation>Görüntü analizi: atlandı (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1773\" />\n            <source>Image analysis: %1</source>\n            <translation>Görüntü analizi: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1775\" />\n            <source>    Time: %1</source>\n            <translation>    Süre: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1796\" />\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1806\" />\n            <source>GPU disabled by backend override</source>\n            <translation>GPU, arka uç zorlamasıyla devre dışı bırakıldı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1815\" />\n            <source>Backend used (image analysis): %1</source>\n            <translation>Kullanılan arka uç (görüntü analizi): %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1832\" />\n            <source>Benchmark failed: %1</source>\n            <translation>Benchmark başarısız: %1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/SuitabilityBenchmarkDialog.cpp\" line=\"1844\" />\n            <source>[STOP] Benchmark will stop after the current step is processed.</source>\n            <translation>[STOP] Benchmark mevcut adımdan sonra duracaktır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/DialogUtils.cpp\" line=\"9\" />\n            <source>Error</source>\n            <translation>Hata</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"33\" />\n            <source>Local LLM (%1)</source>\n            <translation>Yerel LLM (%1)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/LlmCatalog.cpp\" line=\"44\" />\n            <source>Local LLM</source>\n            <translation>Yerel LLM</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/MainApp.cpp\" line=\"1973\" />\n            <source>Support %1</source>\n            <translation>%1'ı Destekle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"181\" />\n            <source>Required Update Available</source>\n            <translation>Zorunlu güncelleme mevcut</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"182\" />\n            <source>A required update is available. Please update to continue.\nIf you choose to quit, the application will close.</source>\n            <translation>Zorunlu bir güncelleme mevcut. Devam etmek için lütfen güncelleyin.\nÇıkış'ı seçerseniz uygulama kapanacaktır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"183\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"209\" />\n            <source>Update Now</source>\n            <translation>Şimdi güncelle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"184\" />\n            <source>Quit</source>\n            <translation>Çıkış</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"207\" />\n            <source>Optional Update Available</source>\n            <translation>İsteğe bağlı güncelleme mevcut</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"208\" />\n            <source>An optional update is available. Would you like to update now?</source>\n            <translation>İsteğe bağlı bir güncelleme mevcut. Şimdi güncellemek ister misiniz?</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"210\" />\n            <source>Skip This Version</source>\n            <translation>Bu sürümü atla</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"211\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"234\" />\n            <location filename=\"../../lib/Updater.cpp\" line=\"283\" />\n            <source>Cancel</source>\n            <translation>İptal</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"232\" />\n            <source>Downloading Update</source>\n            <translation>Güncelleme indiriliyor</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"233\" />\n            <source>Downloading the update installer...</source>\n            <translation>Güncelleme yükleyicisi indiriliyor...</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"271\" />\n            <source>Failed to prepare the update installer.\n%1</source>\n            <translation>Güncelleme yükleyicisi hazırlanamadı.\n%1</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"279\" />\n            <source>Installer Ready</source>\n            <translation>Yükleyici hazır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"280\" />\n            <source>Quit the app and launch the installer to update</source>\n            <translation>Güncellemek için uygulamadan çıkın ve yükleyiciyi başlatın</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"281\" />\n            <source>Quit and Launch Installer</source>\n            <translation>Çık ve yükleyiciyi başlat</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"294\" />\n            <source>The installer could not be launched.</source>\n            <translation>Yükleyici başlatılamadı.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"306\" />\n            <source>No download target is available for this update.</source>\n            <translation>Bu güncelleme için kullanılabilir bir indirme hedefi yok.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"325\" />\n            <source>Update Failed</source>\n            <translation>Güncelleme başarısız oldu</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/Updater.cpp\" line=\"330\" />\n            <source>Update manually</source>\n            <translation>Elle güncelle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"46\" />\n            <source>Edit whitelist</source>\n            <translation>İzin listesini düzenle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"51\" />\n            <source>Name:</source>\n            <translation>Ad:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"56\" />\n            <source>Categories (comma separated):</source>\n            <translation>Kategoriler (virgülle ayrılmış):</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"61\" />\n            <source>Subcategories (comma separated):</source>\n            <translation>Alt kategoriler (virgülle ayrılmış):</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"211\" />\n            <source>CUDA Toolkit Missing</source>\n            <translation>CUDA Toolkit eksik</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"212\" />\n            <source>A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\n\nCUDA is required for GPU acceleration in this application.\n\nWould you like to download and install it now?</source>\n            <translation>Uyumlu bir NVIDIA GPU algılandı, ancak CUDA Toolkit eksik.\n\nBu uygulamada GPU hızlandırması için CUDA gereklidir.\n\nŞimdi indirip kurmak ister misiniz?</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"338\" />\n            <source>Launch Error</source>\n            <translation>Başlatma hatası</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"339\" />\n            <source>Cannot enable both CUDA and Vulkan simultaneously.</source>\n            <translation>CUDA ve Vulkan aynı anda etkinleştirilemez.</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"507\" />\n            <source>Missing GGML Runtime</source>\n            <translation>GGML çalışma zamanı eksik</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"508\" />\n            <source>Could not locate the backend runtime DLLs.\nTried:\n%1\n%2</source>\n            <translation>Arka uç çalışma zamanı DLL'leri bulunamadı.\nDenenen yollar:\n%1\n%2</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"600\" />\n            <source>Launch Failed</source>\n            <translation>Başlatma başarısız</translation>\n        </message>\n        <message>\n            <location filename=\"../../startapp_windows.cpp\" line=\"601\" />\n            <source>Failed to launch the main application executable:\n%1</source>\n            <translation>Ana uygulama yürütülebilir dosyası başlatılamadı:\n%1</translation>\n        </message>\n    </context>\n    <context>\n        <name>UiTranslator</name>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"64\" />\n            <source>Folder:</source>\n            <translation>Klasör:</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"67\" />\n            <source>Browse…</source>\n            <translation>Gözat…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"70\" />\n            <source>Use subcategories</source>\n            <translation>Alt kategorileri kullan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"71\" />\n            <source>Create subcategory folders within each category.</source>\n            <translation>Her kategori içinde alt klasörler oluştur.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"74\" />\n            <source>Categorization type</source>\n            <translation>Kategorilendirme türü</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"75\" />\n            <source>Choose how strict the category labels should be.</source>\n            <translation>Kategori etiketlerinin ne kadar katı olacağını seç.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"78\" />\n            <source>More refined</source>\n            <translation>Daha ayrıntılı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"79\" />\n            <source>Favor detailed labels even if similar items vary.</source>\n            <translation>Benzer öğeler değişse bile ayrıntılı etiketleri tercih eder.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"82\" />\n            <source>More consistent</source>\n            <translation>Daha tutarlı</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"83\" />\n            <source>Favor consistent labels across similar items.</source>\n            <translation>Benzer öğelerde tutarlı etiketleri tercih eder.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"86\" />\n            <source>Use a whitelist</source>\n            <translation>Beyaz liste kullan</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"87\" />\n            <source>Restrict categories and subcategories to the selected whitelist.</source>\n            <translation>Kategorileri ve alt kategorileri seçili beyaz listeyle sınırla.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"90\" />\n            <source>Select the whitelist used for this run.</source>\n            <translation>Bu çalışma için kullanılacak beyaz listeyi seç.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"93\" />\n            <source>Categorize files</source>\n            <translation>Dosyaları kategorilendir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"94\" />\n            <source>Include files in the categorization pass.</source>\n            <translation>Dosyaları kategorizasyona dahil et.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"97\" />\n            <source>Categorize folders</source>\n            <translation>Dizinleri kategorilendir</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"98\" />\n            <source>Include directories in the categorization pass.</source>\n            <translation>Dizinleri kategorizasyona dahil et.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"101\" />\n            <source>Scan subfolders</source>\n            <translation>Alt klasörleri tara</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"102\" />\n            <source>Scan files inside subfolders and treat them as part of the main folder.</source>\n            <translation>Alt dizinlerdeki dosyaları tara ve ana dizindeymiş gibi işle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"105\" />\n            <source>Analyze picture files by content (can be slow)</source>\n            <translation>Resim dosyalarını içeriğe göre analiz et (yavaş olabilir)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"106\" />\n            <source>Run the visual LLM on supported picture files.</source>\n            <translation>Görsel LLM'yi desteklenen resim dosyaları üzerinde çalıştır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"109\" />\n            <source>Process picture files only (ignore any other files)</source>\n            <translation>Yalnızca resim dosyalarını işle (diğer tüm dosyaları yok say)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"110\" />\n            <source>Ignore non-picture files in this run.</source>\n            <translation>Bu çalışmada resim olmayan dosyaları yok say.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"113\" />\n            <source>Add image creation date (if available) to category name</source>\n            <translation>Görüntü oluşturma tarihini (varsa) kategori adına ekle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"114\" />\n            <source>Append the image creation date from metadata to the category label.</source>\n            <translation>Görüntü oluşturma tarihini meta verilerden kategori etiketine ekle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"117\" />\n            <source>Add photo date and place to filename (if available)</source>\n            <translation>Fotoğraf tarihini ve yerini dosya adına ekle (varsa)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"118\" />\n            <source>Date comes from photo EXIF metadata. Place names are resolved online from GPS coordinates, so network access is required for place prefixes.</source>\n            <translation>Tarih, fotoğrafın EXIF meta verilerinden alınır. Yer adları GPS koordinatlarından çevrimiçi çözümlenir; bu nedenle yer önekleri için ağ erişimi gerekir.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"121\" />\n            <source>Add audio/video metadata to file name (if available)</source>\n            <translation>Ses/video meta verilerini dosya adına ekle (varsa)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"122\" />\n            <source>Use embedded media tags (for example year, artist, album, title) to build suggested audio/video filenames.</source>\n            <translation>Önerilen ses/video dosya adlarını oluşturmak için gömülü medya etiketlerini (ör. yıl, sanatçı, albüm, başlık) kullan.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"125\" />\n            <source>Offer to rename picture files</source>\n            <translation>Resim dosyalarını yeniden adlandırmayı öner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"126\" />\n            <source>Show suggested filenames for picture files.</source>\n            <translation>Resim dosyaları için önerilen dosya adlarını göster.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"129\" />\n            <source>Do not categorize picture files (only rename)</source>\n            <translation>Resim dosyalarını kategorize etme (yalnızca yeniden adlandır)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"130\" />\n            <source>Skip categorization for picture files and only rename them.</source>\n            <translation>Resim dosyalarını kategorize etme, yalnızca yeniden adlandır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"133\" />\n            <source>Show or hide picture analysis options</source>\n            <translation>Görsel analiz seçeneklerini göster veya gizle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"136\" />\n            <source>Analyze document files by content</source>\n            <translation>Belge dosyalarını içeriğe göre analiz et</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"137\" />\n            <source>Summarize document contents with the selected LLM.</source>\n            <translation>Belge içeriğini seçilen LLM ile özetle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"140\" />\n            <source>Process document files only (ignore any other files)</source>\n            <translation>Yalnızca belge dosyalarını işle (diğer tüm dosyaları yok say)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"141\" />\n            <source>Ignore non-document files in this run.</source>\n            <translation>Bu çalışmada belge olmayan dosyaları yok say.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"144\" />\n            <source>Offer to rename document files</source>\n            <translation>Belge dosyalarını yeniden adlandırmayı öner</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"145\" />\n            <source>Show suggested filenames for document files.</source>\n            <translation>Belge dosyaları için önerilen dosya adlarını göster.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"148\" />\n            <source>Do not categorize document files (only rename)</source>\n            <translation>Belge dosyalarını kategorize etme (yalnızca yeniden adlandır)</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"149\" />\n            <source>Skip categorization for document files and only rename them.</source>\n            <translation>Belge dosyalarını kategorize etme, yalnızca yeniden adlandır.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"152\" />\n            <source>Add document creation date (if available) to category name</source>\n            <translation>Belge oluşturma tarihini (varsa) kategori adına ekle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"153\" />\n            <source>Append the document creation date from metadata to the category label.</source>\n            <translation>Belge oluşturma tarihini meta verilerden kategori etiketine ekle.</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"156\" />\n            <source>Show or hide document analysis options</source>\n            <translation>Belge analiz seçeneklerini göster veya gizle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Stop analyzing</source>\n            <translation>Analizi durdur</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"159\" />\n            <source>Analyze folder</source>\n            <translation>Klasörü analiz et</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"171\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"184\" />\n            <source>File</source>\n            <translation>Dosya</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"172\" />\n            <source>Type</source>\n            <translation>Tür</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"173\" />\n            <source>Category</source>\n            <translation>Kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"174\" />\n            <source>Subcategory</source>\n            <translation>Alt kategori</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"175\" />\n            <source>Status</source>\n            <translation>Durum</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"182\" />\n            <source>Directory</source>\n            <translation>Klasör</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"190\" />\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"294\" />\n            <source>Ready</source>\n            <translation>Hazır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"268\" />\n            <source>&amp;Help</source>\n            <translation>&amp;Yardım</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"276\" />\n            <source>File Explorer</source>\n            <translation>Dosya gezgini</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"289\" />\n            <source>Cancelling analysis…</source>\n            <translation>Analiz iptal ediliyor…</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/UiTranslator.cpp\" line=\"291\" />\n            <source>Analyzing…</source>\n            <translation>Analiz ediliyor…</translation>\n        </message>\n    </context>\n    <context>\n        <name>WhitelistManagerDialog</name>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"87\" />\n            <source>Category whitelists</source>\n            <translation>Kategori izin listeleri</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"94\" />\n            <source>Add</source>\n            <translation>Ekle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"95\" />\n            <source>Edit</source>\n            <translation>Düzenle</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"96\" />\n            <source>Remove</source>\n            <translation>Kaldır</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>Cannot remove</source>\n            <translation>Kaldırılamaz</translation>\n        </message>\n        <message>\n            <location filename=\"../../lib/WhitelistManagerDialog.cpp\" line=\"170\" />\n            <source>The default list cannot be removed.</source>\n            <translation>Varsayılan liste kaldırılamaz.</translation>\n        </message>\n    </context>\n</TS>\n"
  },
  {
    "path": "app/resources/windows/app_icon.rc.in",
    "content": "#include <windows.h>\n\nIDI_APP_ICON ICON \"@APP_ICON_PATH@\"\n"
  },
  {
    "path": "app/resources/windows/version.rc.in",
    "content": "#include <windows.h>\n\n#define VER_COMPANY      \"hyperfield\"\n#define VER_FILEDESC     \"AI File Sorter\"\n#define VER_PRODUCT      \"AI File Sorter\"\n#define VER_FILEVER      @APP_VER_MAJOR@,@APP_VER_MINOR@,@APP_VER_PATCH@,0\n#define VER_FILEVER_STR  \"@APP_VER_MAJOR@.@APP_VER_MINOR@.@APP_VER_PATCH@\\0\"\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION VER_FILEVER\n PRODUCTVERSION VER_FILEVER\n FILEFLAGSMASK 0x3fL\n FILEFLAGS 0x0L\n FILEOS 0x40004L\n FILETYPE 0x1L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\"\n        BEGIN\n            VALUE \"CompanyName\", VER_COMPANY \"\\0\"\n            VALUE \"FileDescription\", VER_FILEDESC \"\\0\"\n            VALUE \"FileVersion\", VER_FILEVER_STR\n            VALUE \"ProductName\", VER_PRODUCT \"\\0\"\n            VALUE \"ProductVersion\", VER_FILEVER_STR\n            VALUE \"OriginalFilename\", \"AIFileSorter.exe\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x0409, 1200\n    END\nEND\n"
  },
  {
    "path": "app/scripts/README.md",
    "content": "# Diagnostic Collection Scripts\n\nThis folder includes cross-platform scripts for collecting AI File Sorter diagnostics,\nautomatically redacting common sensitive data, and creating a zipped bundle to share.\n\n## Scripts\n\n- `collect_macos_diagnostics.sh` (macOS)\n- `collect_linux_diagnostics.sh` (Linux)\n- `collect_windows_diagnostics.ps1` (Windows PowerShell)\n\n## What they do\n\nEach script:\n\n1. Collects relevant app logs and platform crash/system logs.\n2. Redacts common secrets and user-identifying paths from text-based files.\n3. Produces a `*-redacted.zip` bundle for sharing.\n\n## Collection window behavior\n\n- Default: **latest-run mode**\n  - Uses the newest app log file timestamp and collects around that window.\n- Optional: **time-period mode**\n  - You specify a duration such as `30m`, `1h`, `2h30m`, `1d`.\n\nIf no relevant app logs are found, scripts fall back to a recent window (typically 1 hour).\n\n## macOS\n\nRun from repo root:\n\n```bash\n./app/scripts/collect_macos_diagnostics.sh\n./app/scripts/collect_macos_diagnostics.sh --time-period=1h\n./app/scripts/collect_macos_diagnostics.sh --time-period=1h --open-output\n```\n\nOptions:\n\n- `--time-period=<duration>`\n- `--output-dir=<path>`\n- `--keep-raw`\n- `--open-output`\n- `-h`, `--help`\n\nMain sources collected:\n\n- `~/.cache/AIFileSorter/logs` (and `$XDG_CACHE_HOME/AIFileSorter/my_app/logs` if set)\n- `~/Library/Logs/DiagnosticReports/*aifilesorter*`\n- macOS unified logs (`log show`) filtered for AI File Sorter process/messages\n\n## Linux\n\nRun from repo root:\n\n```bash\n./app/scripts/collect_linux_diagnostics.sh\n./app/scripts/collect_linux_diagnostics.sh --time-period=1h\n./app/scripts/collect_linux_diagnostics.sh --time-period=1h --open-output\n```\n\nOptions:\n\n- `--time-period=<duration>`\n- `--output-dir=<path>`\n- `--keep-raw`\n- `--open-output`\n- `-h`, `--help`\n\nMain sources collected:\n\n- `~/.cache/AIFileSorter/logs` (and `$XDG_CACHE_HOME/AIFileSorter/my_app/logs` if set)\n- `/var/crash` entries related to AI File Sorter (when available)\n- `coredumpctl` output for `aifilesorter` (when available)\n- `journalctl` entries for `aifilesorter` / `aifilesorter-bin` (when available)\n\n## Windows (PowerShell)\n\nRun from repo root in PowerShell:\n\n```powershell\n.\\app\\scripts\\collect_windows_diagnostics.ps1\n.\\app\\scripts\\collect_windows_diagnostics.ps1 -TimePeriod 1h\n.\\app\\scripts\\collect_windows_diagnostics.ps1 -TimePeriod 1h -OpenOutput\n```\n\nOptions:\n\n- `-TimePeriod <duration>`\n- `-OutputDir <path>`\n- `-KeepRaw`\n- `-OpenOutput`\n- `-ShowHelp`\n\nMain sources collected:\n\n- `%APPDATA%\\AIFileSorter\\logs`\n- `%LOCALAPPDATA%\\CrashDumps`\n- `%LOCALAPPDATA%\\Microsoft\\Windows\\WER\\ReportArchive` and `ReportQueue`\n- Windows Application/System event entries matching AI File Sorter\n\n## Output structure\n\nScripts write to your output directory (default desktop/home), with names like:\n\n- `aifs-macos-diagnostics-YYYYMMDD_HHMMSS-redacted.zip`\n- `aifs-linux-diagnostics-YYYYMMDD_HHMMSS-redacted.zip`\n- `aifs-windows-diagnostics-YYYYMMDD_HHMMSS-redacted.zip`\n\nInside, the archive contains a `redacted/` folder with sanitized artifacts.\n\n## Redaction notes\n\nRedaction is best-effort and targets common sensitive patterns:\n\n- User home paths and usernames in paths\n- Authorization bearer tokens\n- URL query secrets such as `key`, `api_key`, `token`, etc.\n- Common API key patterns (`sk-...`, `AIza...`)\n\nYou can keep raw files with `--keep-raw` / `-KeepRaw` for local inspection,\nbut only share the redacted zip by default.\n"
  },
  {
    "path": "app/scripts/build_llama_linux.sh",
    "content": "#!/bin/bash\nset -e\n\n# Resolve script directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nLLAMA_DIR=\"$SCRIPT_DIR/../include/external/llama.cpp\"\n\nif [ ! -d \"$LLAMA_DIR\" ]; then\n    echo \"Missing llama.cpp submodule. Please run:\"\n    echo \"  git submodule update --init --recursive\"\n    exit 1\nfi\n\nPRECOMPILED_ROOT_DIR=\"$SCRIPT_DIR/../lib/precompiled\"\nHEADERS_DIR=\"$SCRIPT_DIR/../include/llama\"\n\n# Parse optional arguments (cuda=on/off, vulkan=on/off, blas=on/off/auto)\nCUDASWITCH=\"OFF\"\nVULKANSWITCH=\"OFF\"\nBLASSWITCH=\"AUTO\"\nfor arg in \"$@\"; do\n    case \"${arg,,}\" in\n        cuda=on) CUDASWITCH=\"ON\" ;;\n        cuda=off) CUDASWITCH=\"OFF\" ;;\n        vulkan=on) VULKANSWITCH=\"ON\" ;;\n        vulkan=off) VULKANSWITCH=\"OFF\" ;;\n        blas=on) BLASSWITCH=\"ON\" ;;\n        blas=off) BLASSWITCH=\"OFF\" ;;\n        blas=auto) BLASSWITCH=\"AUTO\" ;;\n    esac\ndone\n\nif [[ \"$CUDASWITCH\" == \"ON\" && \"$VULKANSWITCH\" == \"ON\" ]]; then\n    echo \"Cannot enable both CUDA and Vulkan simultaneously. Choose one backend.\"\n    exit 1\nfi\n\necho \"CUDA support: $CUDASWITCH\"\necho \"VULKAN support: $VULKANSWITCH\"\necho \"BLAS support: $BLASSWITCH (auto prefers OpenBLAS for CPU baseline)\"\n\n# Resolve OpenBLAS availability when BLAS is set to AUTO\nresolve_blas_setting() {\n    local requested=\"$1\"\n    if [[ \"$requested\" == \"ON\" || \"$requested\" == \"OFF\" ]]; then\n        echo \"$requested\"\n        return 0\n    fi\n    if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists openblas; then\n        echo \"ON\"\n        return 0\n    fi\n    for candidate in /usr/lib/libopenblas.so /usr/lib64/libopenblas.so /usr/lib/x86_64-linux-gnu/libopenblas.so /usr/lib/aarch64-linux-gnu/libopenblas.so; do\n        if [ -e \"$candidate\" ]; then\n            echo \"ON\"\n            return 0\n        fi\n    done\n    echo \"OFF\"\n}\n\nbuild_variant() {\n    local variant=\"$1\"\n    local cuda_flag=\"$2\"\n    local vulkan_flag=\"$3\"\n    local blas_flag=\"$4\"\n    local runtime_subdir=\"$5\"\n\n    local build_dir=\"$LLAMA_DIR/build-$variant\"\n    rm -rf \"$build_dir\"\n    mkdir -p \"$build_dir\"\n\n    echo \"Building variant '$variant' (CUDA=$cuda_flag, VULKAN=$vulkan_flag, BLAS=$blas_flag)...\"\n\n    cd \"$LLAMA_DIR\"\n\n    local cmake_args=(\n        -DGGML_CUDA=\"$cuda_flag\"\n        -DGGML_VULKAN=\"$vulkan_flag\"\n        -DGGML_OPENCL=OFF\n        -DGGML_BLAS=\"$blas_flag\"\n        -DBUILD_SHARED_LIBS=ON\n        -DGGML_NATIVE=OFF\n        -DCMAKE_C_FLAGS=\"-mavx2 -mfma\"\n        -DCMAKE_CXX_FLAGS=\"-mavx2 -mfma\"\n        -S .\n        -B \"$build_dir\"\n    )\n\n    if [[ \"$blas_flag\" == \"ON\" ]]; then\n        cmake_args+=( -DGGML_BLAS_VENDOR=OpenBLAS )\n    fi\n    if [[ \"$cuda_flag\" == \"ON\" ]]; then\n        cmake_args+=( -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-10 )\n    fi\n\n    cmake \"${cmake_args[@]}\"\n    cmake --build \"$build_dir\" --config Release -- -j\"$(nproc)\"\n\n    local variant_root=\"$PRECOMPILED_ROOT_DIR/$variant\"\n    local variant_bin=\"$variant_root/bin\"\n    local variant_lib=\"$variant_root/lib\"\n    local ggml_runtime_root=\"$SCRIPT_DIR/../lib/ggml\"\n    local runtime_dir=\"$ggml_runtime_root/$runtime_subdir\"\n\n    rm -rf \"$variant_bin\" \"$variant_lib\" \"$runtime_dir\"\n    mkdir -p \"$variant_bin\" \"$variant_lib\" \"$runtime_dir\"\n\n    shopt -s nullglob\n    for so in \"$build_dir\"/bin/*.so \"$build_dir\"/bin/*.so.*; do\n        cp -P \"$so\" \"$variant_bin/\"\n        cp -P \"$so\" \"$runtime_dir/\"\n    done\n    for lib in \"$build_dir\"/lib/*.a; do\n        cp \"$lib\" \"$variant_lib/\"\n    done\n    for so in \"$build_dir\"/lib/*.so \"$build_dir\"/lib/*.so.*; do\n        cp -P \"$so\" \"$variant_lib/\"\n        cp -P \"$so\" \"$runtime_dir/\"\n    done\n    shopt -u nullglob\n\n    if command -v patchelf >/dev/null 2>&1; then\n        if compgen -G \"$variant_bin/\"'*.so*' >/dev/null; then\n            for lib in \"$variant_bin\"/*.so*; do\n                patchelf --set-rpath '$ORIGIN' \"$lib\" || true\n            done\n        fi\n    else\n        echo \"Warning: patchelf not found; skipping RUNPATH fix for llama libraries.\"\n    fi\n\n    cd \"$SCRIPT_DIR\"\n}\n\n# Determine BLAS setting (AUTO falls back to OFF if OpenBLAS is missing)\nRESOLVED_BLAS=\"$(resolve_blas_setting \"$BLASSWITCH\")\"\nif [[ \"$BLASSWITCH\" == \"ON\" && \"$RESOLVED_BLAS\" == \"OFF\" ]]; then\n    echo \"Requested BLAS=ON but OpenBLAS was not found. Install openblas (or set blas=off) and retry.\" >&2\n    exit 1\nfi\nif [[ \"$RESOLVED_BLAS\" == \"OFF\" && \"$BLASSWITCH\" == \"AUTO\" ]]; then\n    echo \"OpenBLAS not detected; building CPU baseline without BLAS. Install openblas and rerun for BLAS acceleration.\"\nfi\n\n# Always build a CPU baseline (OpenBLAS when available)\nbuild_variant \"cpu\" \"OFF\" \"OFF\" \"$RESOLVED_BLAS\" \"wocuda\"\n\n# Build requested accelerator variant if applicable\nREQUESTED_VARIANT=\"cpu\"\nREQUESTED_RUNTIME=\"wocuda\"\nif [[ \"$CUDASWITCH\" == \"ON\" ]]; then\n    REQUESTED_VARIANT=\"cuda\"\n    REQUESTED_RUNTIME=\"wcuda\"\nelif [[ \"$VULKANSWITCH\" == \"ON\" ]]; then\n    REQUESTED_VARIANT=\"vulkan\"\n    REQUESTED_RUNTIME=\"wvulkan\"\nfi\n\nif [[ \"$REQUESTED_VARIANT\" != \"cpu\" ]]; then\n    build_variant \"$REQUESTED_VARIANT\" \"$CUDASWITCH\" \"$VULKANSWITCH\" \"$RESOLVED_BLAS\" \"$REQUESTED_RUNTIME\"\nfi\n\n# Copy headers once (from the source tree)\nrm -rf \"$HEADERS_DIR\" && mkdir -p \"$HEADERS_DIR\"\ncp \"$LLAMA_DIR/include/llama.h\" \"$HEADERS_DIR\"\ncp \"$LLAMA_DIR\"/ggml/src/*.h \"$HEADERS_DIR\"\ncp \"$LLAMA_DIR\"/ggml/include/*.h \"$HEADERS_DIR\"\n\n# Clean up build directories\nrm -rf \"$LLAMA_DIR\"/build-*\n"
  },
  {
    "path": "app/scripts/build_llama_macos.sh",
    "content": "#!/bin/bash\nset -e\n\n# CLI flags\nusage() {\n    cat <<'USAGE'\nUsage: build_llama_macos.sh [options]\n\nOptions:\n  --arch <arm64|x86_64>   Target macOS architecture\n  --arm64                 Alias for --arch arm64 (Apple Silicon)\n  --x86_64                Alias for --arch x86_64 (Intel)\n  --intel                 Alias for --arch x86_64\n  --m1 | --m2 | --m3      Alias for --arch arm64\n  -h | --help             Show this help\n\nEnvironment overrides:\n  LLAMA_MACOS_ARCH        Target architecture (overridden by CLI)\n  LLAMA_MACOS_ENABLE_METAL=0|1|auto\n  LLAMA_MACOS_MULTI_VARIANT=0|1\nUSAGE\n}\n\nCLI_ARCH=\"\"\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        --arch)\n            if [[ -z \"${2:-}\" ]]; then\n                echo \"Missing value for --arch\" >&2\n                usage\n                exit 1\n            fi\n            CLI_ARCH=\"$2\"\n            shift 2\n            ;;\n        --arm64|--apple-silicon|--m1|--m2|--m3)\n            CLI_ARCH=\"arm64\"\n            shift\n            ;;\n        --x86_64|--intel)\n            CLI_ARCH=\"x86_64\"\n            shift\n            ;;\n        -h|--help)\n            usage\n            exit 0\n            ;;\n        *)\n            echo \"Unknown option: $1\" >&2\n            usage\n            exit 1\n            ;;\n    esac\ndone\n\nif [[ -n \"$CLI_ARCH\" ]]; then\n    case \"$CLI_ARCH\" in\n        arm64|x86_64) ;;\n        *)\n            echo \"Unsupported arch: $CLI_ARCH (use arm64 or x86_64)\" >&2\n            exit 1\n            ;;\n    esac\n    export LLAMA_MACOS_ARCH=\"$CLI_ARCH\"\nfi\n\n# Resolve script directory (cross-shell portable)\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nLLAMA_DIR=\"$SCRIPT_DIR/../include/external/llama.cpp\"\n\nif [ ! -d \"$LLAMA_DIR\" ]; then\n    echo \"Missing llama.cpp submodule. Please run:\"\n    echo \"  git submodule update --init --recursive\"\n    exit 1\nfi\n\nPRECOMPILED_LIBS_DIR=\"${LLAMA_PRECOMPILED_DIR:-$SCRIPT_DIR/../lib/precompiled}\"\nif [[ \"$PRECOMPILED_LIBS_DIR\" != /* ]]; then\n    PRECOMPILED_LIBS_DIR=\"$SCRIPT_DIR/../$PRECOMPILED_LIBS_DIR\"\nfi\nHEADERS_DIR=\"$SCRIPT_DIR/../include/llama\"\nBUILD_DIR=\"$LLAMA_DIR/build\"\nBUILD_BIN_DIR=\"$BUILD_DIR/bin\"\nDYLIB_RPATH=\"@loader_path\"\n\nnormalize_macos_dylib_rpaths() {\n    local dylib_dir=\"$1\"\n    local stale_rpath=\"$2\"\n\n    shopt -s nullglob\n    for dylib in \"$dylib_dir\"/*.dylib; do\n        if ! otool -l \"$dylib\" | grep -Fq \"$DYLIB_RPATH\"; then\n            install_name_tool -add_rpath \"$DYLIB_RPATH\" \"$dylib\"\n        fi\n\n        if otool -l \"$dylib\" | grep -Fq \"$stale_rpath\"; then\n            install_name_tool -delete_rpath \"$stale_rpath\" \"$dylib\"\n        fi\n    done\n    shopt -u nullglob\n}\n\nARCH=$(uname -m)\nTARGET_ARCH=${LLAMA_MACOS_ARCH:-$ARCH}\necho \"Building on architecture: $ARCH (target: $TARGET_ARCH)\"\nCROSS_COMPILE=0\nif [ \"$ARCH\" != \"$TARGET_ARCH\" ]; then\n    CROSS_COMPILE=1\nfi\n\nMACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-11.0}\nexport MACOSX_DEPLOYMENT_TARGET\necho \"Targeting macOS ${MACOSX_DEPLOYMENT_TARGET} for build outputs\"\n\nDEFAULT_BREW_PREFIX=\"/opt/homebrew\"\nif [ \"$TARGET_ARCH\" = \"x86_64\" ]; then\n    DEFAULT_BREW_PREFIX=\"/usr/local\"\nfi\nif [ -n \"${BREW_PREFIX:-}\" ]; then\n    HOMEBREW_PREFIX=\"$BREW_PREFIX\"\nelif [ -x \"${DEFAULT_BREW_PREFIX}/bin/brew\" ]; then\n    HOMEBREW_PREFIX=\"$(${DEFAULT_BREW_PREFIX}/bin/brew --prefix)\"\nelif command -v brew >/dev/null 2>&1; then\n    HOMEBREW_PREFIX=\"$(brew --prefix)\"\nelse\n    HOMEBREW_PREFIX=\"$DEFAULT_BREW_PREFIX\"\nfi\necho \"Using Homebrew prefix: ${HOMEBREW_PREFIX}\"\n\nQT_PREFIX=\"${HOMEBREW_PREFIX}/opt/qt\"\nOPENSSL_PREFIX=\"${HOMEBREW_PREFIX}/opt/openssl@3\"\nPKG_CONFIG_DIRS=(\n    \"${HOMEBREW_PREFIX}/lib/pkgconfig\"\n    \"${HOMEBREW_PREFIX}/share/pkgconfig\"\n    \"${OPENSSL_PREFIX}/lib/pkgconfig\"\n    \"${QT_PREFIX}/lib/pkgconfig\"\n)\nPKG_CONFIG_PATH_VALUE=\"$(IFS=:; echo \"${PKG_CONFIG_DIRS[*]}\")\"\nexport PKG_CONFIG_PATH=\"${PKG_CONFIG_PATH_VALUE}${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}\"\nexport PKG_CONFIG_LIBDIR=\"${PKG_CONFIG_PATH_VALUE}\"\nexport CMAKE_PREFIX_PATH=\"${HOMEBREW_PREFIX}${CMAKE_PREFIX_PATH:+;${CMAKE_PREFIX_PATH}}\"\nif [ \"$TARGET_ARCH\" = \"x86_64\" ]; then\n    export CMAKE_IGNORE_PREFIX_PATH=\"/opt/homebrew${CMAKE_IGNORE_PREFIX_PATH:+;${CMAKE_IGNORE_PREFIX_PATH}}\"\nfi\n\n# Decide whether to enable Metal. Apple Silicon machines benefit from it, but\n# most Intel Macs either lack usable Metal compute queues or expose 0 bytes of\n# GPU memory to ggml, which causes llama.cpp to fail the moment it tries to\n# initialize the backend. On Intel default to a CPU-only build; allow overrides\n# via LLAMA_MACOS_ENABLE_METAL=1.\nENABLE_METAL=${LLAMA_MACOS_ENABLE_METAL:-auto}\nif [ \"$ENABLE_METAL\" = \"auto\" ]; then\n    if [ \"$TARGET_ARCH\" = \"arm64\" ]; then\n        ENABLE_METAL=1\n    else\n        ENABLE_METAL=0\n    fi\nfi\nif [ \"$ENABLE_METAL\" != \"0\" ]; then\n    echo \"Enabling Metal backend\"\n    METAL_FLAG=ON\nelse\n    echo \"Disabling Metal backend (CPU-only build)\"\n    METAL_FLAG=OFF\nfi\n\nMULTI_VARIANT=${LLAMA_MACOS_MULTI_VARIANT:-0}\nCPU_VARIANT_ARGS=\"\"\nif [ \"$MULTI_VARIANT\" = \"1\" ]; then\n    echo \"Enabling multi-variant CPU backend build\"\n    CPU_VARIANT_ARGS=\"-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DGGML_NATIVE=OFF\"\nelif [ \"$CROSS_COMPILE\" = \"1\" ]; then\n    echo \"Cross-compiling CPU backend; disabling native CPU targeting\"\n    CPU_VARIANT_ARGS=\"-DGGML_NATIVE=OFF\"\nfi\n\nARCH_CMAKE_ARG=\"\"\nif [ -n \"$LLAMA_MACOS_ARCH\" ]; then\n    ARCH_CMAKE_ARG=\"-DCMAKE_OSX_ARCHITECTURES=${LLAMA_MACOS_ARCH}\"\nfi\n\n# Ensure SDK paths and libc++ headers are available (especially on Intel Macs).\nif command -v xcrun >/dev/null 2>&1; then\n    SDKROOT=\"$(xcrun --sdk macosx --show-sdk-path 2>/dev/null)\"\n    if [ -n \"$SDKROOT\" ]; then\n        export SDKROOT\n        export CFLAGS=\"${CFLAGS} -isysroot ${SDKROOT}\"\n        export CXXFLAGS=\"${CXXFLAGS} -isysroot ${SDKROOT} -stdlib=libc++ -I${SDKROOT}/usr/include/c++/v1\"\n        export LDFLAGS=\"${LDFLAGS} -isysroot ${SDKROOT}\"\n        CMAKE_SYSROOT_ARG=\"-DCMAKE_OSX_SYSROOT=${SDKROOT}\"\n    fi\nfi\n\n# Enter llama.cpp directory and build\ncd \"$LLAMA_DIR\"\nrm -rf \"$BUILD_DIR\"\nmkdir -p \"$BUILD_DIR\"\nLDFLAGS= cmake -S . -B \"$BUILD_DIR\" \\\n  ${CMAKE_SYSROOT_ARG} \\\n  ${ARCH_CMAKE_ARG} \\\n  -DCMAKE_BUILD_TYPE=Release \\\n  -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \\\n  -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \\\n  -DCMAKE_INSTALL_RPATH=${DYLIB_RPATH} \\\n  -DOPENSSL_ROOT_DIR=${OPENSSL_PREFIX} \\\n  -DBUILD_SHARED_LIBS=ON \\\n  -DCMAKE_EXE_LINKER_FLAGS= \\\n  -DCMAKE_SHARED_LINKER_FLAGS= \\\n  -DCMAKE_MODULE_LINKER_FLAGS= \\\n  ${CPU_VARIANT_ARGS} \\\n  -DGGML_METAL=${METAL_FLAG} \\\n  -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=Accelerate \\\n  -DGGML_CUDA=OFF \\\n  -DGGML_OPENCL=OFF \\\n  -DGGML_VULKAN=OFF \\\n  -DGGML_SYCL=OFF \\\n  -DGGML_HIP=OFF \\\n  -DGGML_KLEIDIAI=OFF \\\n  -DBLAS_LIBRARIES=\"-framework Accelerate\"\n\nLDFLAGS= cmake --build \"$BUILD_DIR\" --config Release -- -j$(sysctl -n hw.logicalcpu)\n\n# Copy the resulting dynamic (.dylib) libraries\nrm -rf \"$PRECOMPILED_LIBS_DIR\"\nmkdir -p \"$PRECOMPILED_LIBS_DIR\"\ncp \"$BUILD_BIN_DIR\"/libllama.dylib \"$PRECOMPILED_LIBS_DIR\"\ncp \"$BUILD_BIN_DIR\"/libggml*.dylib \"$PRECOMPILED_LIBS_DIR\"\ncp \"$BUILD_BIN_DIR\"/libmtmd.dylib \"$PRECOMPILED_LIBS_DIR\"\nnormalize_macos_dylib_rpaths \"$PRECOMPILED_LIBS_DIR\" \"$BUILD_BIN_DIR\"\n# Provide versioned symlinks expected by the app runtime loader\n(\n  cd \"$PRECOMPILED_LIBS_DIR\"\n  ln -sf libllama.dylib libllama.0.dylib\n  ln -sf libmtmd.dylib libmtmd.0.dylib\n)\n\nif [ \"$MULTI_VARIANT\" = \"1\" ]; then\n    shopt -s nullglob\n    for backend_lib in \"$BUILD_BIN_DIR\"/libggml-*.so; do\n        cp \"$backend_lib\" \"$PRECOMPILED_LIBS_DIR\"\n    done\n    shopt -u nullglob\n    for backend_dylib in \"$PRECOMPILED_LIBS_DIR\"/libggml-*.dylib; do\n        base=\"${backend_dylib%.dylib}\"\n        if [ ! -e \"${base}.so\" ]; then\n            ln -sf \"$(basename \"$backend_dylib\")\" \"${base}.so\"\n        fi\n    done\nfi\n\n# Copy headers\nrm -rf \"$HEADERS_DIR\"\nmkdir -p \"$HEADERS_DIR\"\ncp include/llama.h \"$HEADERS_DIR\"\ncp ggml/src/*.h \"$HEADERS_DIR\"\ncp ggml/include/*.h \"$HEADERS_DIR\"\n"
  },
  {
    "path": "app/scripts/build_llama_windows.ps1",
    "content": "$ErrorActionPreference = \"Stop\"\n\n# --- Parse optional arguments ---\n$useCuda = \"OFF\"\n$useVulkan = \"OFF\"\n$useBlas = \"AUTO\" # AUTO = enable BLAS for CPU-only builds by default\n$vcpkgRootArg = $null\n$openBlasRootArg = $null\nforeach ($arg in $args) {\n    if ($arg -match \"^cuda=(on|off)$\") {\n        $useCuda = $Matches[1].ToUpper()\n    } elseif ($arg -match \"^vulkan=(on|off)$\") {\n        $useVulkan = $Matches[1].ToUpper()\n    } elseif ($arg -match \"^blas=(on|off)$\") {\n        $useBlas = $Matches[1].ToUpper()\n    } elseif ($arg -match \"^vcpkgroot=(.+)$\") {\n        $vcpkgRootArg = $Matches[1]\n    } elseif ($arg -match \"^openblasroot=(.+)$\") {\n        $openBlasRootArg = $Matches[1]\n    }\n}\n\nif ($useCuda -eq \"ON\" -and $useVulkan -eq \"ON\") {\n    throw \"Cannot enable both CUDA and Vulkan simultaneously. Choose only one backend.\"\n}\n\nWrite-Output \"`nCUDA Support: $useCuda`n\"\nWrite-Output \"Vulkan Support: $useVulkan`n\"\nWrite-Output \"BLAS Support: $useBlas (AUTO enables for CPU-only builds)`n\"\n\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition\n$llamaDir = Join-Path $scriptDir \"..\\include\\external\\llama.cpp\"\n\nif (-not (Test-Path $llamaDir)) {\n    Write-Output \"Missing llama.cpp submodule. Please run:\"\n    Write-Output \"  git submodule update --init --recursive\"\n    exit 1\n}\n\n$precompiledRootDir = Join-Path $scriptDir \"..\\lib\\precompiled\"\n$headersDir = Join-Path $scriptDir \"..\\include\\llama\"\n$ggmlRuntimeRoot = Join-Path $scriptDir \"..\\lib\\ggml\"\n\n# --- Locate cmake executable ---\nfunction Resolve-CMake {\n    $cmd = Get-Command cmake -ErrorAction SilentlyContinue\n    if ($cmd) {\n        return $cmd.Source\n    }\n    $vsCMake = \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\CMake\\bin\\cmake.exe\"\n    if (Test-Path $vsCMake) {\n        return $vsCMake\n    }\n    throw \"cmake executable not found in PATH. Run this script from a VS Developer PowerShell or install CMake and ensure it is on PATH.\"\n}\n\n$cmakeExe = Resolve-CMake\n\nfunction Resolve-MSVCCompiler {\n    $cmd = Get-Command cl.exe -ErrorAction SilentlyContinue\n    if ($cmd -and (Test-Path $cmd.Source)) {\n        return $cmd.Source\n    }\n\n    $vswherePath = Join-Path ${env:ProgramFiles(x86)} \"Microsoft Visual Studio\\Installer\\vswhere.exe\"\n    if (Test-Path $vswherePath) {\n        $installationPath = & $vswherePath `\n            -latest `\n            -products * `\n            -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `\n            -property installationPath\n\n        if ($installationPath) {\n            $toolRoot = Join-Path $installationPath \"VC\\Tools\\MSVC\"\n            if (Test-Path $toolRoot) {\n                $toolsets = Get-ChildItem -Path $toolRoot -Directory |\n                    Sort-Object Name -Descending\n                foreach ($toolset in $toolsets) {\n                    $candidate = Join-Path $toolset.FullName \"bin\\Hostx64\\x64\\cl.exe\"\n                    if (Test-Path $candidate) {\n                        return $candidate\n                    }\n                }\n            }\n        }\n    }\n\n    throw \"Could not locate MSVC cl.exe. Run this script from a Developer PowerShell or install the Visual Studio C++ toolchain.\"\n}\n\n$msvcCompiler = Resolve-MSVCCompiler\n\n# --- Locate OpenBLAS (required on Windows) ---\nfunction Resolve-VcpkgRoot {\n    param([string]$Explicit)\n\n    if ($Explicit) { return $Explicit }\n\n    $defaultRoot = \"C:\\dev\\vcpkg\"\n    if (Test-Path $defaultRoot) {\n        return $defaultRoot\n    }\n\n    if ($env:VCPKG_ROOT) {\n        if ($env:VCPKG_ROOT -like \"*Program Files*Microsoft Visual Studio*\") {\n            Write-Warning \"Detected Visual Studio's bundled vcpkg at '$($env:VCPKG_ROOT)', which is typically read-only. Please clone vcpkg to a writable location (e.g. $defaultRoot) and pass vcpkgroot=<path>.\"\n            return $null\n        }\n        return $env:VCPKG_ROOT\n    }\n\n    return $null\n}\n\n$cpuOnlyBuild = ($useCuda -eq \"OFF\" -and $useVulkan -eq \"OFF\")\n$enableBlas = ($useBlas -eq \"ON\") -or ($useBlas -eq \"AUTO\" -and $cpuOnlyBuild)\n\nfunction Resolve-OpenBlasRoot {\n    param([string]$Explicit)\n\n    $candidates = @()\n    if ($Explicit) { $candidates += $Explicit }\n    if ($env:OPENBLAS_ROOT) { $candidates += $env:OPENBLAS_ROOT }\n    $candidates += \"C:\\msys64\\mingw64\"\n\n    foreach ($candidate in $candidates) {\n        if ($candidate -and (Test-Path $candidate)) {\n            return (Resolve-Path $candidate).Path\n        }\n    }\n    return $null\n}\n\n$vcpkgRoot = Resolve-VcpkgRoot -Explicit $vcpkgRootArg\nif (-not $vcpkgRoot -or -not (Test-Path $vcpkgRoot)) {\n    throw \"Could not resolve a writable vcpkg root. Pass vcpkgroot=<path> (e.g. C:\\dev\\vcpkg) or set VCPKG_ROOT accordingly.\"\n}\n$env:VCPKG_ROOT = $vcpkgRoot\n\n$triplet = \"x64-windows\"\n\nfunction Invoke-Vcpkg {\n    param(\n        [string]$Subcommand,\n        [string[]]$PackageArgs = @()\n    )\n    $vcpkgExe = Join-Path $vcpkgRoot \"vcpkg.exe\"\n    if (-not (Test-Path $vcpkgExe)) {\n        throw \"Cannot find vcpkg.exe under $vcpkgRoot. Please ensure vcpkg is installed there.\"\n    }\n    Push-Location $vcpkgRoot\n    Write-Output \"Invoking vcpkg with arguments: $Subcommand $($PackageArgs -join ' ') (count=$($PackageArgs.Count))\"\n    if ($PackageArgs.Count -eq 0) {\n        & $vcpkgExe \"--vcpkg-root\" $vcpkgRoot $Subcommand\n    } else {\n        & $vcpkgExe \"--vcpkg-root\" $vcpkgRoot $Subcommand @PackageArgs\n    }\n    $exit = $LASTEXITCODE\n    Pop-Location\n    if ($exit -ne 0) {\n        throw \"vcpkg $Subcommand failed with exit code $exit\"\n    }\n}\n\nfunction Confirm-VcpkgPackage {\n    param(\n        [string]$HeaderCheckPath,\n        [string]$LibraryCheckPath,\n        [string]$PackageName,\n        [string[]]$AdditionalPaths = @()\n    )\n\n    $pathsToCheck = @()\n    if ($HeaderCheckPath) { $pathsToCheck += $HeaderCheckPath }\n    if ($LibraryCheckPath) { $pathsToCheck += $LibraryCheckPath }\n    foreach ($extraPath in $AdditionalPaths) {\n        if ($extraPath) { $pathsToCheck += $extraPath }\n    }\n\n    if ($pathsToCheck.Count -eq 0) {\n        throw \"Confirm-VcpkgPackage was called for $PackageName with no paths to validate.\"\n    }\n\n    $needsInstall = $false\n    foreach ($candidate in $pathsToCheck) {\n        if (-not (Test-Path $candidate)) {\n            $needsInstall = $true\n            break\n        }\n    }\n\n    if ($needsInstall) {\n        Write-Output \"$PackageName not found. Installing via vcpkg ...\"\n        $pkgSpec = \"${PackageName}:$triplet\"\n        Write-Output \"Running: vcpkg install $pkgSpec\"\n        Invoke-Vcpkg -Subcommand \"install\" -PackageArgs @($pkgSpec)\n    }\n\n    foreach ($candidate in $pathsToCheck) {\n        if (-not (Test-Path $candidate)) {\n            throw \"Expected $candidate from package $PackageName but the path is still missing.\"\n        }\n    }\n}\n\n$curlInclude = Join-Path $vcpkgRoot \"installed\\$triplet\\include\"\n$curlLib = Join-Path $vcpkgRoot \"installed\\$triplet\\lib\\libcurl.lib\"\n$curlDll = Join-Path $vcpkgRoot \"installed\\$triplet\\bin\\libcurl.dll\"\nConfirm-VcpkgPackage -HeaderCheckPath (Join-Path $curlInclude \"curl\\curl.h\") -LibraryCheckPath $curlLib -PackageName \"curl\"\n\n$openBlasInclude = $null\n$openBlasLib = $null\n$openBlasDll = $null\nif ($enableBlas) {\n    $openBlasRoot = Resolve-OpenBlasRoot -Explicit $openBlasRootArg\n    if (-not $openBlasRoot) {\n        throw \"BLAS builds require OpenBLAS from MSYS2/MinGW64. Pass openblasroot=<path> or set OPENBLAS_ROOT.\"\n    }\n\n    $openBlasIncludeRoot = Join-Path $openBlasRoot \"include\"\n    $openBlasInclude = Join-Path $openBlasIncludeRoot \"openblas\"\n    $openBlasHeader = Join-Path $openBlasInclude \"cblas.h\"\n    if (-not (Test-Path $openBlasHeader)) {\n        throw \"Missing cblas.h under $openBlasInclude. Install OpenBLAS via MSYS2 (pacman -S mingw-w64-x86_64-openblas) or point openblasroot to a valid tree.\"\n    }\n\n    $openBlasLibCandidates = @(\n        (Join-Path $openBlasRoot \"lib\\openblas.lib\")\n        (Join-Path $openBlasRoot \"lib\\libopenblas.lib\")\n        (Join-Path $openBlasRoot \"lib\\libopenblas.dll.a\")\n        (Join-Path $openBlasRoot \"lib\\libopenblas.a\")\n    )\n    foreach ($candidate in $openBlasLibCandidates) {\n        if (Test-Path $candidate) {\n            $openBlasLib = $candidate\n            break\n        }\n    }\n    if (-not $openBlasLib) {\n        throw \"Could not find an OpenBLAS import library under $openBlasRoot\\lib.\"\n    }\n\n    $openBlasDllCandidates = @(\n        (Join-Path $openBlasRoot \"bin\\libopenblas.dll\")\n        (Join-Path $openBlasRoot \"bin\\openblas.dll\")\n    )\n    foreach ($candidate in $openBlasDllCandidates) {\n        if (Test-Path $candidate) {\n            $openBlasDll = $candidate\n            break\n        }\n    }\n    if (-not $openBlasDll) {\n        throw \"Could not find the OpenBLAS runtime DLL (e.g. libopenblas.dll) under $openBlasRoot\\bin.\"\n    }\n\n    Write-Host \"Using OpenBLAS from $openBlasRoot\"\n}\n\n$vulkanIncludeDir = $null\n$vulkanLibPath = $null\n$vulkanDllPath = $null\n$vulkanGlslcPath = $null\n$vulkanSdkRoot = $null\nif ($useVulkan -eq \"ON\") {\n    $vulkanIncludeDir = Join-Path $vcpkgRoot \"installed\\$triplet\\include\"\n    $vulkanHeaderPath = Join-Path $vulkanIncludeDir \"vulkan\\vulkan.h\"\n    $vulkanLibPath = Join-Path $vcpkgRoot \"installed\\$triplet\\lib\\vulkan-1.lib\"\n    $vulkanDllPath = Join-Path $vcpkgRoot \"installed\\$triplet\\bin\\vulkan-1.dll\"\n    $shadercToolsDir = Join-Path $vcpkgRoot \"installed\\$triplet\\tools\\shaderc\"\n    $vulkanGlslcPath = Join-Path $shadercToolsDir \"glslc.exe\"\n\n    Confirm-VcpkgPackage -HeaderCheckPath $vulkanHeaderPath -LibraryCheckPath $null -PackageName \"vulkan-headers\"\n    Confirm-VcpkgPackage -HeaderCheckPath $null -LibraryCheckPath $vulkanLibPath -PackageName \"vulkan-loader\" -AdditionalPaths @($vulkanDllPath)\n    Confirm-VcpkgPackage -HeaderCheckPath $null -LibraryCheckPath $null -PackageName \"shaderc\" -AdditionalPaths @($vulkanGlslcPath)\n\n    $vulkanSdkRoot = Join-Path $vcpkgRoot \"installed\\$triplet\"\n    $env:VULKAN_SDK = $vulkanSdkRoot\n}\n\n# Write-Host \"Using OpenBLAS include: $openBlasInclude\"\n# Write-Host \"Using OpenBLAS lib: $openBlasLib\"\n\n# --- Build from llama.cpp ---\nPush-Location $llamaDir\n\nif (Test-Path \"build\") {\n    Remove-Item -Recurse -Force \"build\"\n}\nNew-Item -ItemType Directory -Path \"build\" | Out-Null\n\n$cmakeArgs = @(\n    \"-DCMAKE_C_COMPILER=`\"$msvcCompiler`\"\",\n    \"-DCMAKE_CXX_COMPILER=`\"$msvcCompiler`\"\",\n    \"-DCURL_LIBRARY=`\"$curlLib`\"\",\n    \"-DCURL_INCLUDE_DIR=`\"$curlInclude`\"\",\n    \"-DBUILD_SHARED_LIBS=ON\",\n    \"-DGGML_OPENCL=OFF\",\n    \"-DGGML_VULKAN=$useVulkan\",\n    \"-DGGML_SYCL=OFF\",\n    \"-DGGML_HIP=OFF\",\n    \"-DGGML_KLEIDIAI=OFF\",\n    \"-DGGML_NATIVE=OFF\",\n    \"-DCMAKE_C_FLAGS=/arch:AVX2\",\n    \"-DCMAKE_CXX_FLAGS=/arch:AVX2\"\n)\n\nif ($enableBlas) {\n    if (-not $openBlasInclude -or -not $openBlasLib) {\n        throw \"OpenBLAS paths not initialized for the BLAS-enabled build.\"\n    }\n    $cmakeArgs += @(\n        \"-DGGML_BLAS=ON\",\n        \"-DGGML_BLAS_VENDOR=OpenBLAS\",\n        \"-DBLA_VENDOR=OpenBLAS\",\n        \"-DBLAS_INCLUDE_DIRS=`\"$openBlasInclude`\"\",\n        \"-DBLAS_LIBRARIES=`\"$openBlasLib`\"\"\n    )\n} else {\n    $cmakeArgs += \"-DGGML_BLAS=OFF\"\n}\n\nif ($useCuda -eq \"ON\") {\n    $cudaRoot = \"C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.9\"\n    $includeDir = \"$cudaRoot/include\"\n    $libDir = \"$cudaRoot/lib/x64/cudart.lib\"\n\n    $cmakeArgs += @(\n        \"-DGGML_CUDA=ON\",\n        \"-DCUDA_TOOLKIT_ROOT_DIR=`\"$cudaRoot`\"\",\n        \"-DCUDA_INCLUDE_DIRS=`\"$includeDir`\"\",\n        \"-DCUDA_CUDART=`\"$libDir`\"\"\n    )\n} else {\n    $cmakeArgs += \"-DGGML_CUDA=OFF\"\n}\n\nif ($useVulkan -eq \"ON\") {\n    if (-not $vulkanIncludeDir -or -not $vulkanLibPath -or -not $vulkanGlslcPath) {\n        throw \"Vulkan paths were not initialized even though Vulkan support is enabled.\"\n    }\n    $cmakeArgs += @(\n        \"-DVulkan_INCLUDE_DIR=`\"$vulkanIncludeDir`\"\",\n        \"-DVulkan_LIBRARY=`\"$vulkanLibPath`\"\",\n        \"-DVulkan_GLSLC_EXECUTABLE=`\"$vulkanGlslcPath`\"\"\n    )\n    if ($vulkanSdkRoot) {\n        $cmakeArgs += \"-DVULKAN_SDK=`\"$vulkanSdkRoot`\"\"\n    }\n}\n\n& $cmakeExe -S . -B build @cmakeArgs\n& $cmakeExe --build build --config Release -- /m\n\nPop-Location\n\n# --- Clean and repopulate precompiled outputs ---\n$variant = \"cpu\"\n$runtimeSubdir = \"wocuda\"\nif ($useCuda -eq \"ON\") {\n    $variant = \"cuda\"\n    $runtimeSubdir = \"wcuda\"\n} elseif ($useVulkan -eq \"ON\") {\n    if ($enableBlas) {\n        $variant = \"vulkan-blas\"\n        $runtimeSubdir = \"wvulkan-cpu\"\n    } else {\n        $variant = \"vulkan\"\n        $runtimeSubdir = \"wvulkan\"\n    }\n}\n$variantRoot = Join-Path $precompiledRootDir $variant\n$variantBin = Join-Path $variantRoot \"bin\"\n$variantLib = Join-Path $variantRoot \"lib\"\n$runtimeDir = Join-Path $ggmlRuntimeRoot $runtimeSubdir\n\nforeach ($dir in @($variantBin, $variantLib, $runtimeDir)) {\n    if (Test-Path $dir) {\n        Remove-Item -Recurse -Force $dir\n    }\n    New-Item -ItemType Directory -Force -Path $dir | Out-Null\n}\n\n$releaseBin = Join-Path $llamaDir \"build\\bin\\Release\"\n$dllList = @()\nif (Test-Path $releaseBin) {\n    $dllList = Get-ChildItem -Path $releaseBin -Filter \"*.dll\" -File | Select-Object -ExpandProperty Name\n}\nif (-not $dllList -or $dllList.Count -eq 0) {\n    throw \"No DLLs were produced in $releaseBin.\"\n}\n\nforeach ($dll in $dllList) {\n    $src = Join-Path $releaseBin $dll\n    Copy-Item $src -Destination $variantBin -Force\n    if ($dll -ne \"libcurl.dll\") {\n        Copy-Item $src -Destination $runtimeDir -Force\n    }\n}\n\nif ($enableBlas -and $openBlasDll -and (Test-Path $openBlasDll)) {\n    $libOpenBlasName = \"libopenblas.dll\"\n    Copy-Item $openBlasDll -Destination (Join-Path $variantBin $libOpenBlasName) -Force\n    Copy-Item $openBlasDll -Destination (Join-Path $runtimeDir $libOpenBlasName) -Force\n    foreach ($legacy in @((Join-Path $variantBin \"openblas.dll\"), (Join-Path $runtimeDir \"openblas.dll\"))) {\n        if (Test-Path $legacy) {\n            Remove-Item $legacy -Force\n        }\n    }\n}\nif (Test-Path $curlDll) {\n    Copy-Item $curlDll -Destination $variantBin -Force\n    Copy-Item $curlDll -Destination $runtimeDir -Force\n}\n\nif ($useVulkan -eq \"ON\" -and $vulkanDllPath -and (Test-Path $vulkanDllPath)) {\n    Copy-Item $vulkanDllPath -Destination $variantBin -Force\n    Copy-Item $vulkanDllPath -Destination $runtimeDir -Force\n}\n\n$importLibNames = @(\"llama.lib\", \"ggml.lib\", \"ggml-base.lib\", \"ggml-cpu.lib\", \"mtmd.lib\")\n$optionalLibs = @(\"ggml-blas.lib\", \"ggml-openblas.lib\")\nif ($useCuda -eq \"ON\") {\n    $importLibNames += \"ggml-cuda.lib\"\n}\n\nforeach ($libName in $importLibNames) {\n    $libSource = Get-ChildItem (Join-Path $llamaDir \"build\") -Filter $libName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1\n    if (-not $libSource) {\n        throw \"Could not locate $libName within the llama.cpp build directory.\"\n    }\n    Copy-Item $libSource.FullName -Destination (Join-Path $variantLib $libName) -Force\n}\nforeach ($libName in $optionalLibs) {\n    $libSource = Get-ChildItem (Join-Path $llamaDir \"build\") -Filter $libName -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1\n    if ($libSource) {\n        Copy-Item $libSource.FullName -Destination (Join-Path $variantLib $libName) -Force\n    }\n}\n\n# --- Copy headers ---\nNew-Item -ItemType Directory -Force -Path $headersDir | Out-Null\nCopy-Item \"$llamaDir\\include\\llama.h\" -Destination $headersDir\nCopy-Item \"$llamaDir\\ggml\\src\\*.h\" -Destination $headersDir -ErrorAction SilentlyContinue\nCopy-Item \"$llamaDir\\ggml\\include\\*.h\" -Destination $headersDir -ErrorAction SilentlyContinue\n"
  },
  {
    "path": "app/scripts/collect_linux_diagnostics.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n    cat <<'EOF'\nCollect, redact, and zip AI File Sorter diagnostics on Linux.\n\nUsage:\n  ./collect_linux_diagnostics.sh [options]\n\nOptions:\n  --time-period=<duration>   Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d)\n  --output-dir=<path>        Output directory for collected artifacts (default: ~/Desktop or ~)\n  --keep-raw                 Keep unredacted raw logs on disk (default: remove raw logs)\n  --open-output              Open output directory after completion\n  -h, --help                 Show this help\n\nDefault behavior:\n  If --time-period is not supplied, the script attempts \"latest run\" mode:\n  it finds the newest app log mtime and collects logs around that window.\n\nExamples:\n  ./collect_linux_diagnostics.sh\n  ./collect_linux_diagnostics.sh --time-period=1h\n  ./collect_linux_diagnostics.sh --time-period=90m --output-dir=\"$HOME/Desktop\"\nEOF\n}\n\ndie() {\n    echo \"Error: $*\" >&2\n    exit 1\n}\n\nwarn() {\n    echo \"Warning: $*\" >&2\n}\n\nparse_duration_to_seconds() {\n    local input=\"$1\"\n    local value\n    value=\"$(printf '%s' \"$input\" | tr '[:upper:]' '[:lower:]')\"\n    value=\"${value// /}\"\n    [[ -n \"$value\" ]] || die \"Empty duration.\"\n\n    if [[ \"$value\" =~ ^[0-9]+$ ]]; then\n        echo \"$value\"\n        return\n    fi\n\n    local rest=\"$value\"\n    local total=0\n    local chunk number unit multiplier\n\n    while [[ -n \"$rest\" ]]; do\n        if [[ \"$rest\" =~ ^([0-9]+)([smhd])(.*)$ ]]; then\n            number=\"${BASH_REMATCH[1]}\"\n            unit=\"${BASH_REMATCH[2]}\"\n            chunk=\"${BASH_REMATCH[0]}\"\n            rest=\"${BASH_REMATCH[3]}\"\n\n            case \"$unit\" in\n                s) multiplier=1 ;;\n                m) multiplier=60 ;;\n                h) multiplier=3600 ;;\n                d) multiplier=86400 ;;\n                *) die \"Unsupported duration unit in '$chunk'.\" ;;\n            esac\n            total=$((total + number * multiplier))\n        else\n            die \"Invalid duration format: '$input' (examples: 30m, 1h, 2h30m, 1d).\"\n        fi\n    done\n\n    (( total > 0 )) || die \"Duration must be greater than zero.\"\n    echo \"$total\"\n}\n\nis_text_like_file() {\n    local file=\"$1\"\n    case \"$file\" in\n        *.log|*.txt|*.json|*.crash|*.ips|*.ini|*.cfg|*.conf|*.out|*.err)\n            return 0\n            ;;\n    esac\n\n    local mime\n    mime=\"$(file -b --mime-type \"$file\" 2>/dev/null || true)\"\n    case \"$mime\" in\n        text/*|application/json|application/xml|application/x-empty)\n            return 0\n            ;;\n    esac\n    return 1\n}\n\nredact_text_file() {\n    local src=\"$1\"\n    local dst=\"$2\"\n    perl -CS -pe '\n        BEGIN { $home = $ENV{\"HOME\"} // \"\"; }\n        if ($home ne \"\") {\n            s/\\Q$home\\E/<HOME>/g;\n        }\n        s#(/home/)[^/\\s]+#${1}<user>#g;\n        s#(/media/)[^/\\s]+#${1}<media>#g;\n        s#(/mnt/)[^/\\s]+#${1}<mount>#g;\n        s#(/run/user/)[0-9]+#${1}<uid>#g;\n\n        s/(Authorization:\\s*Bearer\\s+)[^\\s\"\\047]+/${1}<REDACTED>/ig;\n        s/([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\\s\"\\047]+/${1}<REDACTED>/ig;\n        s/\\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\\b/sk-<REDACTED>/g;\n        s/\\bAIza[0-9A-Za-z_-]{20,}\\b/AIza<REDACTED>/g;\n    ' \"$src\" > \"$dst\"\n}\n\ncopy_recent_log_files() {\n    local source_dir=\"$1\"\n    local dest_dir=\"$2\"\n    local since_epoch=\"$3\"\n    local copied=0\n    mkdir -p \"$dest_dir\"\n\n    local file mtime\n    for file in \"$source_dir\"/core.log* \"$source_dir\"/db.log* \"$source_dir\"/ui.log*; do\n        [[ -f \"$file\" ]] || continue\n        mtime=\"$(stat -c %Y \"$file\" 2>/dev/null || echo 0)\"\n        if (( mtime >= since_epoch )); then\n            cp \"$file\" \"$dest_dir/\"\n            copied=$((copied + 1))\n        fi\n    done\n\n    echo \"$copied\"\n}\n\nlatest_app_log_epoch() {\n    local latest=0\n    local dir file mtime\n    for dir in \"${APP_LOG_DIRS[@]}\"; do\n        [[ -d \"$dir\" ]] || continue\n        for file in \"$dir\"/core.log* \"$dir\"/db.log* \"$dir\"/ui.log*; do\n            [[ -f \"$file\" ]] || continue\n            mtime=\"$(stat -c %Y \"$file\" 2>/dev/null || echo 0)\"\n            if (( mtime > latest )); then\n                latest=\"$mtime\"\n            fi\n        done\n    done\n    echo \"$latest\"\n}\n\nTIME_PERIOD_RAW=\"\"\nOUTPUT_DIR=\"$HOME/Desktop\"\nKEEP_RAW=0\nOPEN_OUTPUT=0\n\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        --time-period=*)\n            TIME_PERIOD_RAW=\"${1#*=}\"\n            ;;\n        --time-period)\n            [[ -n \"${2:-}\" ]] || die \"Missing value for --time-period\"\n            TIME_PERIOD_RAW=\"$2\"\n            shift\n            ;;\n        --output-dir=*)\n            OUTPUT_DIR=\"${1#*=}\"\n            ;;\n        --output-dir)\n            [[ -n \"${2:-}\" ]] || die \"Missing value for --output-dir\"\n            OUTPUT_DIR=\"$2\"\n            shift\n            ;;\n        --keep-raw)\n            KEEP_RAW=1\n            ;;\n        --open-output)\n            OPEN_OUTPUT=1\n            ;;\n        -h|--help)\n            usage\n            exit 0\n            ;;\n        *)\n            die \"Unknown option: $1\"\n            ;;\n    esac\n    shift\ndone\n\nif [[ \"$(uname -s)\" != \"Linux\" ]]; then\n    die \"This script is for Linux only.\"\nfi\n\ncommand -v perl >/dev/null 2>&1 || die \"perl is required but was not found.\"\ncommand -v zip >/dev/null 2>&1 || die \"zip is required but was not found.\"\ncommand -v stat >/dev/null 2>&1 || die \"stat is required but was not found.\"\n\nif [[ ! -d \"$OUTPUT_DIR\" ]]; then\n    OUTPUT_DIR=\"$HOME\"\nfi\nmkdir -p \"$OUTPUT_DIR\"\nOUTPUT_DIR=\"$(cd \"$OUTPUT_DIR\" && pwd)\"\n\ndeclare -a APP_LOG_DIRS\nAPP_LOG_DIRS=(\"$HOME/.cache/AIFileSorter/logs\")\nif [[ -n \"${XDG_CACHE_HOME:-}\" ]]; then\n    APP_LOG_DIRS+=(\"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\")\nfi\n\nnow_epoch=\"$(date +%s)\"\nsince_epoch=0\nwindow_seconds=0\nwindow_note=\"\"\n\nif [[ -n \"$TIME_PERIOD_RAW\" ]]; then\n    window_seconds=\"$(parse_duration_to_seconds \"$TIME_PERIOD_RAW\")\"\n    since_epoch=$((now_epoch - window_seconds))\n    window_note=\"time-period mode (--time-period=${TIME_PERIOD_RAW})\"\nelse\n    latest_epoch=\"$(latest_app_log_epoch)\"\n    if (( latest_epoch > 0 )); then\n        since_epoch=$((latest_epoch - 300))\n        if (( since_epoch < 0 )); then\n            since_epoch=0\n        fi\n        window_seconds=$((now_epoch - since_epoch))\n        if (( window_seconds < 300 )); then\n            window_seconds=300\n        fi\n        window_note=\"latest-run mode (newest app log mtime: $(date -d \"@${latest_epoch}\" \"+%Y-%m-%d %H:%M:%S\"))\"\n    else\n        window_seconds=3600\n        since_epoch=$((now_epoch - window_seconds))\n        window_note=\"fallback mode (no app logs found, using last 1h)\"\n        warn \"No app logs found. Falling back to last 1h.\"\n    fi\nfi\n\nts=\"$(date \"+%Y%m%d_%H%M%S\")\"\nbase_name=\"aifs-linux-diagnostics-${ts}\"\nwork_dir=\"${OUTPUT_DIR}/${base_name}\"\nraw_dir=\"${work_dir}/raw\"\nredacted_dir=\"${work_dir}/redacted\"\nzip_path=\"${OUTPUT_DIR}/${base_name}-redacted.zip\"\n\nmkdir -p \"$raw_dir\" \"$redacted_dir\"\n\napp_logs_copied=0\n\nif [[ -d \"$HOME/.cache/AIFileSorter/logs\" ]]; then\n    copied=\"$(copy_recent_log_files \"$HOME/.cache/AIFileSorter/logs\" \"$raw_dir/cache-logs\" \"$since_epoch\")\"\n    app_logs_copied=$((app_logs_copied + copied))\nfi\n\nif [[ -n \"${XDG_CACHE_HOME:-}\" ]] && [[ -d \"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\" ]]; then\n    copied=\"$(copy_recent_log_files \"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\" \"$raw_dir/xdg-cache-logs\" \"$since_epoch\")\"\n    app_logs_copied=$((app_logs_copied + copied))\nfi\n\nif (( app_logs_copied == 0 )); then\n    warn \"No recent app log files matched the selected window.\"\nfi\n\nmkdir -p \"$raw_dir/crash\"\ncrash_count=0\n\nif [[ -d \"/var/crash\" ]]; then\n    while IFS= read -r -d '' crash_file; do\n        mtime=\"$(stat -c %Y \"$crash_file\" 2>/dev/null || echo 0)\"\n        if (( mtime >= since_epoch )); then\n            cp \"$crash_file\" \"$raw_dir/crash/\" 2>/dev/null || true\n            crash_count=$((crash_count + 1))\n        fi\n    done < <(find /var/crash -maxdepth 1 -type f \\\n              \\( -iname \"*aifilesorter*\" -o -iname \"*AIFileSorter*\" \\) -print0 2>/dev/null || true)\nfi\n\nif command -v coredumpctl >/dev/null 2>&1; then\n    if ! coredumpctl --since \"@${since_epoch}\" list aifilesorter > \"$raw_dir/crash/coredumpctl_aifilesorter.txt\" 2>&1; then\n        true\n    fi\nfi\n\nmkdir -p \"$raw_dir/journal\"\nif command -v journalctl >/dev/null 2>&1; then\n    journalctl --no-pager --since \"@${since_epoch}\" _COMM=aifilesorter \\\n        > \"$raw_dir/journal/journal_aifilesorter.log\" 2> \"$raw_dir/journal/journal_aifilesorter.stderr\" || true\n    journalctl --no-pager --since \"@${since_epoch}\" _COMM=aifilesorter-bin \\\n        > \"$raw_dir/journal/journal_aifilesorter_bin.log\" 2> \"$raw_dir/journal/journal_aifilesorter_bin.stderr\" || true\n\n    if [[ ! -s \"$raw_dir/journal/journal_aifilesorter.log\" ]] && [[ ! -s \"$raw_dir/journal/journal_aifilesorter_bin.log\" ]]; then\n        journalctl --no-pager --since \"@${since_epoch}\" \\\n            | grep -Ei 'aifilesorter|AIFileSorter' > \"$raw_dir/journal/journal_filtered.log\" 2>/dev/null || true\n    fi\n\n    for err_file in \"$raw_dir/journal/\"*.stderr; do\n        [[ -f \"$err_file\" ]] || continue\n        if [[ ! -s \"$err_file\" ]]; then\n            rm -f \"$err_file\"\n        fi\n    done\nelse\n    warn \"journalctl not found; skipping system journal collection.\"\nfi\n\n{\n    echo \"Collected at: $(date \"+%Y-%m-%d %H:%M:%S %z\")\"\n    echo \"Window note: ${window_note}\"\n    echo \"Window start: $(date -d \"@${since_epoch}\" \"+%Y-%m-%d %H:%M:%S\")\"\n    echo \"Window seconds: ${window_seconds}\"\n    echo \"App logs copied: ${app_logs_copied}\"\n    echo \"Crash artifacts copied: ${crash_count}\"\n    echo\n    echo \"== uname -a ==\"\n    uname -a\n    echo\n    echo \"== /etc/os-release ==\"\n    cat /etc/os-release 2>/dev/null || true\n    echo\n    echo \"== lsb_release -a ==\"\n    lsb_release -a 2>/dev/null || true\n    echo\n    echo \"== glibc ==\"\n    getconf GNU_LIBC_VERSION 2>/dev/null || true\n    echo\n    echo \"== CPU ==\"\n    grep -m1 'model name' /proc/cpuinfo 2>/dev/null || true\n} > \"$raw_dir/system_info.txt\"\n\nwhile IFS= read -r -d '' src; do\n    rel=\"${src#$raw_dir/}\"\n    dst=\"$redacted_dir/$rel\"\n    mkdir -p \"$(dirname \"$dst\")\"\n    if is_text_like_file \"$src\"; then\n        redact_text_file \"$src\" \"$dst\"\n    else\n        cp \"$src\" \"$dst\"\n    fi\ndone < <(find \"$raw_dir\" -type f -print0)\n\n(\n    cd \"$work_dir\"\n    zip -qr \"$zip_path\" \"redacted\"\n)\n\nif (( KEEP_RAW == 0 )); then\n    rm -rf \"$raw_dir\"\nfi\n\necho \"Diagnostics bundle ready:\"\necho \"  $zip_path\"\necho\necho \"Collected with: $window_note\"\necho \"If needed, inspect redacted files at:\"\necho \"  $redacted_dir\"\n\nif (( OPEN_OUTPUT == 1 )); then\n    if command -v xdg-open >/dev/null 2>&1; then\n        xdg-open \"$OUTPUT_DIR\" >/dev/null 2>&1 || true\n    fi\nfi\n"
  },
  {
    "path": "app/scripts/collect_macos_diagnostics.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n    cat <<'EOF'\nCollect, redact, and zip AI File Sorter diagnostics on macOS.\n\nUsage:\n  ./collect_macos_diagnostics.sh [options]\n\nOptions:\n  --time-period=<duration>   Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d)\n  --output-dir=<path>        Output directory for collected artifacts (default: ~/Desktop)\n  --keep-raw                 Keep unredacted raw logs on disk (default: remove raw logs)\n  --open-output              Reveal the resulting zip in Finder\n  -h, --help                 Show this help\n\nDefault behavior:\n  If --time-period is not supplied, the script attempts \"latest run\" mode:\n  it finds the newest app log mtime and collects logs around that window.\n\nExamples:\n  ./collect_macos_diagnostics.sh\n  ./collect_macos_diagnostics.sh --time-period=1h\n  ./collect_macos_diagnostics.sh --time-period=90m --output-dir=\"$HOME/Desktop\"\nEOF\n}\n\ndie() {\n    echo \"Error: $*\" >&2\n    exit 1\n}\n\nwarn() {\n    echo \"Warning: $*\" >&2\n}\n\nparse_duration_to_seconds() {\n    local input=\"$1\"\n    local value\n    value=\"$(printf '%s' \"$input\" | tr '[:upper:]' '[:lower:]')\"\n    value=\"${value// /}\"\n    [[ -n \"$value\" ]] || die \"Empty duration.\"\n\n    if [[ \"$value\" =~ ^[0-9]+$ ]]; then\n        echo \"$value\"\n        return\n    fi\n\n    local rest=\"$value\"\n    local total=0\n    local chunk number unit multiplier\n\n    while [[ -n \"$rest\" ]]; do\n        if [[ \"$rest\" =~ ^([0-9]+)([smhd])(.*)$ ]]; then\n            number=\"${BASH_REMATCH[1]}\"\n            unit=\"${BASH_REMATCH[2]}\"\n            chunk=\"${BASH_REMATCH[0]}\"\n            rest=\"${BASH_REMATCH[3]}\"\n\n            case \"$unit\" in\n                s) multiplier=1 ;;\n                m) multiplier=60 ;;\n                h) multiplier=3600 ;;\n                d) multiplier=86400 ;;\n                *) die \"Unsupported duration unit in '$chunk'.\" ;;\n            esac\n            total=$((total + number * multiplier))\n        else\n            die \"Invalid duration format: '$input' (examples: 30m, 1h, 2h30m, 1d).\"\n        fi\n    done\n\n    (( total > 0 )) || die \"Duration must be greater than zero.\"\n    echo \"$total\"\n}\n\nis_text_like_file() {\n    local file=\"$1\"\n    case \"$file\" in\n        *.log|*.txt|*.json|*.crash|*.ips|*.plist|*.ini|*.cfg|*.conf|*.out|*.err)\n            return 0\n            ;;\n    esac\n\n    local mime\n    mime=\"$(file -b --mime-type \"$file\" 2>/dev/null || true)\"\n    case \"$mime\" in\n        text/*|application/json|application/xml|application/x-plist|application/x-empty)\n            return 0\n            ;;\n    esac\n    return 1\n}\n\nredact_text_file() {\n    local src=\"$1\"\n    local dst=\"$2\"\n    perl -CS -pe '\n        BEGIN { $home = $ENV{\"HOME\"} // \"\"; }\n        if ($home ne \"\") {\n            s/\\Q$home\\E/<HOME>/g;\n        }\n        s#(/Users/)[^/\\s]+#${1}<user>#g;\n        s#(/Volumes/)[^/\\s]+#${1}<volume>#g;\n        s#(/private/var/folders/)[^/\\s]+#${1}<redacted>#g;\n\n        s/(Authorization:\\s*Bearer\\s+)[^\\s\"\\047]+/${1}<REDACTED>/ig;\n        s/([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\\s\"\\047]+/${1}<REDACTED>/ig;\n        s/\\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\\b/sk-<REDACTED>/g;\n        s/\\bAIza[0-9A-Za-z_-]{20,}\\b/AIza<REDACTED>/g;\n    ' \"$src\" > \"$dst\"\n}\n\ncopy_recent_log_files() {\n    local source_dir=\"$1\"\n    local dest_dir=\"$2\"\n    local since_epoch=\"$3\"\n    local copied=0\n    mkdir -p \"$dest_dir\"\n\n    local file mtime\n    for file in \"$source_dir\"/core.log* \"$source_dir\"/db.log* \"$source_dir\"/ui.log*; do\n        [[ -f \"$file\" ]] || continue\n        mtime=\"$(stat -f %m \"$file\" 2>/dev/null || echo 0)\"\n        if (( mtime >= since_epoch )); then\n            cp \"$file\" \"$dest_dir/\"\n            copied=$((copied + 1))\n        fi\n    done\n\n    echo \"$copied\"\n}\n\nlatest_app_log_epoch() {\n    local latest=0\n    local dir file mtime\n    for dir in \"${APP_LOG_DIRS[@]}\"; do\n        [[ -d \"$dir\" ]] || continue\n        for file in \"$dir\"/core.log* \"$dir\"/db.log* \"$dir\"/ui.log*; do\n            [[ -f \"$file\" ]] || continue\n            mtime=\"$(stat -f %m \"$file\" 2>/dev/null || echo 0)\"\n            if (( mtime > latest )); then\n                latest=\"$mtime\"\n            fi\n        done\n    done\n    echo \"$latest\"\n}\n\nTIME_PERIOD_RAW=\"\"\nOUTPUT_DIR=\"$HOME/Desktop\"\nKEEP_RAW=0\nOPEN_OUTPUT=0\n\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        --time-period=*)\n            TIME_PERIOD_RAW=\"${1#*=}\"\n            ;;\n        --time-period)\n            [[ -n \"${2:-}\" ]] || die \"Missing value for --time-period\"\n            TIME_PERIOD_RAW=\"$2\"\n            shift\n            ;;\n        --output-dir=*)\n            OUTPUT_DIR=\"${1#*=}\"\n            ;;\n        --output-dir)\n            [[ -n \"${2:-}\" ]] || die \"Missing value for --output-dir\"\n            OUTPUT_DIR=\"$2\"\n            shift\n            ;;\n        --keep-raw)\n            KEEP_RAW=1\n            ;;\n        --open-output)\n            OPEN_OUTPUT=1\n            ;;\n        -h|--help)\n            usage\n            exit 0\n            ;;\n        *)\n            die \"Unknown option: $1\"\n            ;;\n    esac\n    shift\ndone\n\nif [[ \"$(uname -s)\" != \"Darwin\" ]]; then\n    die \"This script is for macOS only.\"\nfi\n\ncommand -v perl >/dev/null 2>&1 || die \"perl is required but was not found.\"\ncommand -v zip >/dev/null 2>&1 || die \"zip is required but was not found.\"\ncommand -v log >/dev/null 2>&1 || die \"macOS 'log' tool not found.\"\n\nmkdir -p \"$OUTPUT_DIR\"\nOUTPUT_DIR=\"$(cd \"$OUTPUT_DIR\" && pwd)\"\n\ndeclare -a APP_LOG_DIRS\nAPP_LOG_DIRS=(\"$HOME/.cache/AIFileSorter/logs\")\nif [[ -n \"${XDG_CACHE_HOME:-}\" ]]; then\n    APP_LOG_DIRS+=(\"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\")\nfi\n\nnow_epoch=\"$(date +%s)\"\nsince_epoch=0\nwindow_seconds=0\nwindow_note=\"\"\n\nif [[ -n \"$TIME_PERIOD_RAW\" ]]; then\n    window_seconds=\"$(parse_duration_to_seconds \"$TIME_PERIOD_RAW\")\"\n    since_epoch=$((now_epoch - window_seconds))\n    window_note=\"time-period mode (--time-period=${TIME_PERIOD_RAW})\"\nelse\n    latest_epoch=\"$(latest_app_log_epoch)\"\n    if (( latest_epoch > 0 )); then\n        since_epoch=$((latest_epoch - 300))\n        if (( since_epoch < 0 )); then\n            since_epoch=0\n        fi\n        window_seconds=$((now_epoch - since_epoch))\n        if (( window_seconds < 300 )); then\n            window_seconds=300\n        fi\n        window_note=\"latest-run mode (newest app log mtime: $(date -r \"$latest_epoch\" \"+%Y-%m-%d %H:%M:%S\"))\"\n    else\n        window_seconds=3600\n        since_epoch=$((now_epoch - window_seconds))\n        window_note=\"fallback mode (no app logs found, using last 1h)\"\n        warn \"No app logs found. Falling back to last 1h.\"\n    fi\nfi\n\nts=\"$(date \"+%Y%m%d_%H%M%S\")\"\nbase_name=\"aifs-macos-diagnostics-${ts}\"\nwork_dir=\"${OUTPUT_DIR}/${base_name}\"\nraw_dir=\"${work_dir}/raw\"\nredacted_dir=\"${work_dir}/redacted\"\nzip_path=\"${OUTPUT_DIR}/${base_name}-redacted.zip\"\n\nmkdir -p \"$raw_dir\" \"$redacted_dir\"\n\napp_logs_copied=0\n\nif [[ -d \"$HOME/.cache/AIFileSorter/logs\" ]]; then\n    copied=\"$(copy_recent_log_files \"$HOME/.cache/AIFileSorter/logs\" \"$raw_dir/cache-logs\" \"$since_epoch\")\"\n    app_logs_copied=$((app_logs_copied + copied))\nfi\n\nif [[ -n \"${XDG_CACHE_HOME:-}\" ]] && [[ -d \"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\" ]]; then\n    copied=\"$(copy_recent_log_files \"$XDG_CACHE_HOME/AIFileSorter/my_app/logs\" \"$raw_dir/xdg-cache-logs\" \"$since_epoch\")\"\n    app_logs_copied=$((app_logs_copied + copied))\nfi\n\nif (( app_logs_copied == 0 )); then\n    warn \"No recent app log files matched the selected window.\"\nfi\n\nmkdir -p \"$raw_dir/DiagnosticReports\"\ncrash_count=0\nif [[ -d \"$HOME/Library/Logs/DiagnosticReports\" ]]; then\n    while IFS= read -r -d '' crash_file; do\n        mtime=\"$(stat -f %m \"$crash_file\" 2>/dev/null || echo 0)\"\n        if (( mtime >= since_epoch )); then\n            cp \"$crash_file\" \"$raw_dir/DiagnosticReports/\"\n            crash_count=$((crash_count + 1))\n        fi\n    done < <(find \"$HOME/Library/Logs/DiagnosticReports\" -maxdepth 1 -type f \\\n              \\( -iname \"*aifilesorter*\" -o -iname \"*AIFileSorter*\" \\) -print0)\nfi\n\nmkdir -p \"$raw_dir/unified\"\npredicate='process == \"aifilesorter\" OR process == \"AIFileSorter\" OR eventMessage CONTAINS[c] \"AIFileSorter\" OR eventMessage CONTAINS[c] \"aifilesorter\"'\nif ! log show --style compact --last \"${window_seconds}s\" --predicate \"$predicate\" \\\n    > \"$raw_dir/unified/aifs_unified.log\" 2> \"$raw_dir/unified/aifs_unified.stderr\"; then\n    warn \"Failed to read unified logs (see $raw_dir/unified/aifs_unified.stderr).\"\nfi\nif [[ ! -s \"$raw_dir/unified/aifs_unified.stderr\" ]]; then\n    rm -f \"$raw_dir/unified/aifs_unified.stderr\"\nfi\n\n{\n    echo \"Collected at: $(date \"+%Y-%m-%d %H:%M:%S %z\")\"\n    echo \"Window note: ${window_note}\"\n    echo \"Window start: $(date -r \"$since_epoch\" \"+%Y-%m-%d %H:%M:%S\")\"\n    echo \"Window seconds: ${window_seconds}\"\n    echo \"App logs copied: ${app_logs_copied}\"\n    echo \"Crash reports copied: ${crash_count}\"\n    echo\n    echo \"== sw_vers ==\"\n    sw_vers\n    echo\n    echo \"== uname -a ==\"\n    uname -a\n    echo\n    echo \"== CPU ==\"\n    sysctl -n machdep.cpu.brand_string 2>/dev/null || true\n    echo\n    echo \"== hw.model ==\"\n    sysctl -n hw.model 2>/dev/null || true\n} > \"$raw_dir/system_info.txt\"\n\nwhile IFS= read -r -d '' src; do\n    rel=\"${src#$raw_dir/}\"\n    dst=\"$redacted_dir/$rel\"\n    mkdir -p \"$(dirname \"$dst\")\"\n    if is_text_like_file \"$src\"; then\n        redact_text_file \"$src\" \"$dst\"\n    else\n        cp \"$src\" \"$dst\"\n    fi\ndone < <(find \"$raw_dir\" -type f -print0)\n\n(\n    cd \"$work_dir\"\n    zip -qr \"$zip_path\" \"redacted\"\n)\n\nif (( KEEP_RAW == 0 )); then\n    rm -rf \"$raw_dir\"\nfi\n\necho \"Diagnostics bundle ready:\"\necho \"  $zip_path\"\necho\necho \"Collected with: $window_note\"\necho \"If needed, inspect redacted files at:\"\necho \"  $redacted_dir\"\n\nif (( OPEN_OUTPUT == 1 )); then\n    open -R \"$zip_path\" || true\nfi\n"
  },
  {
    "path": "app/scripts/collect_windows_diagnostics.ps1",
    "content": "param(\n    [Alias(\"time-period\")]\n    [string]$TimePeriod,\n    [Alias(\"output-dir\")]\n    [string]$OutputDir = [System.Environment]::GetFolderPath(\"Desktop\"),\n    [Alias(\"keep-raw\")]\n    [switch]$KeepRaw,\n    [Alias(\"open-output\")]\n    [switch]$OpenOutput,\n    [Alias(\"h\", \"help\")]\n    [switch]$ShowHelp\n)\n\n$ErrorActionPreference = \"Stop\"\n\nfunction Show-Usage {\n    @\"\nCollect, redact, and zip AI File Sorter diagnostics on Windows.\n\nUsage:\n  .\\collect_windows_diagnostics.ps1 [options]\n\nOptions:\n  -TimePeriod <duration>  Collect logs from the last duration (e.g. 30m, 1h, 2h30m, 1d)\n  -OutputDir <path>       Output directory for collected artifacts (default: Desktop)\n  -KeepRaw                Keep unredacted raw logs on disk (default: remove raw logs)\n  -OpenOutput             Reveal resulting zip in Explorer\n  -ShowHelp               Show this help\n\nDefault behavior:\n  If -TimePeriod is not supplied, the script attempts \"latest run\" mode:\n  it finds the newest app log mtime and collects logs around that window.\n\nExamples:\n  .\\collect_windows_diagnostics.ps1\n  .\\collect_windows_diagnostics.ps1 -TimePeriod 1h\n  .\\collect_windows_diagnostics.ps1 -TimePeriod 90m -OutputDir \"$env:USERPROFILE\\Desktop\"\n\"@\n}\n\nfunction Convert-TimePeriodToTimeSpan {\n    param([Parameter(Mandatory = $true)][string]$InputValue)\n\n    $value = $InputValue.Trim().ToLowerInvariant() -replace \"\\s+\", \"\"\n    if ([string]::IsNullOrWhiteSpace($value)) {\n        throw \"Empty duration.\"\n    }\n\n    if ($value -match '^\\d+$') {\n        return [TimeSpan]::FromSeconds([int64]$value)\n    }\n\n    $rest = $value\n    $totalSeconds = [int64]0\n\n    while ($rest.Length -gt 0) {\n        $m = [regex]::Match($rest, '^([0-9]+)([smhd])(.*)$')\n        if (-not $m.Success) {\n            throw \"Invalid duration format: '$InputValue' (examples: 30m, 1h, 2h30m, 1d).\"\n        }\n\n        $number = [int64]$m.Groups[1].Value\n        $unit = $m.Groups[2].Value\n        $rest = $m.Groups[3].Value\n\n        switch ($unit) {\n            \"s\" { $totalSeconds += $number }\n            \"m\" { $totalSeconds += $number * 60 }\n            \"h\" { $totalSeconds += $number * 3600 }\n            \"d\" { $totalSeconds += $number * 86400 }\n            default { throw \"Unsupported duration unit in '$InputValue'.\" }\n        }\n    }\n\n    if ($totalSeconds -le 0) {\n        throw \"Duration must be greater than zero.\"\n    }\n\n    return [TimeSpan]::FromSeconds($totalSeconds)\n}\n\nfunction New-DirectoryIfMissing {\n    param([Parameter(Mandatory = $true)][string]$Path)\n    if (-not (Test-Path -LiteralPath $Path)) {\n        New-Item -ItemType Directory -Path $Path -Force | Out-Null\n    }\n}\n\nfunction Copy-RecentAppLogs {\n    param(\n        [Parameter(Mandatory = $true)][string]$SourceDir,\n        [Parameter(Mandatory = $true)][string]$DestinationDir,\n        [Parameter(Mandatory = $true)][datetime]$Since\n    )\n\n    if (-not (Test-Path -LiteralPath $SourceDir)) {\n        return 0\n    }\n\n    New-DirectoryIfMissing -Path $DestinationDir\n    $copied = 0\n    $patterns = @(\"core.log*\", \"db.log*\", \"ui.log*\")\n    foreach ($pattern in $patterns) {\n        $files = Get-ChildItem -Path $SourceDir -Filter $pattern -File -ErrorAction SilentlyContinue\n        foreach ($file in $files) {\n            if ($file.LastWriteTime -ge $Since) {\n                Copy-Item -LiteralPath $file.FullName -Destination $DestinationDir -Force\n                $copied++\n            }\n        }\n    }\n\n    return $copied\n}\n\nfunction Get-LatestAppLogTime {\n    param([Parameter(Mandatory = $true)][string[]]$LogDirs)\n\n    $latest = [datetime]::MinValue\n    foreach ($dir in $LogDirs) {\n        if (-not (Test-Path -LiteralPath $dir)) { continue }\n        $patterns = @(\"core.log*\", \"db.log*\", \"ui.log*\")\n        foreach ($pattern in $patterns) {\n            $files = Get-ChildItem -Path $dir -Filter $pattern -File -ErrorAction SilentlyContinue\n            foreach ($file in $files) {\n                if ($file.LastWriteTime -gt $latest) {\n                    $latest = $file.LastWriteTime\n                }\n            }\n        }\n    }\n    return $latest\n}\n\nfunction Is-TextLikeFile {\n    param([Parameter(Mandatory = $true)][string]$Path)\n    $ext = [IO.Path]::GetExtension($Path).ToLowerInvariant()\n    $textExtensions = @(\n        \".log\", \".txt\", \".json\", \".wer\", \".xml\",\n        \".ini\", \".cfg\", \".conf\", \".out\", \".err\", \".csv\"\n    )\n    return $textExtensions -contains $ext\n}\n\nfunction Redact-TextContent {\n    param([Parameter(Mandatory = $true)][string]$Content)\n\n    $result = $Content\n\n    if ($env:USERPROFILE) {\n        $result = [regex]::Replace($result, [regex]::Escape($env:USERPROFILE), \"<HOME>\", \"IgnoreCase\")\n    }\n    if ($env:HOMEDRIVE -and $env:HOMEPATH) {\n        $homePath = \"$($env:HOMEDRIVE)$($env:HOMEPATH)\"\n        $result = [regex]::Replace($result, [regex]::Escape($homePath), \"<HOME>\", \"IgnoreCase\")\n    }\n\n    $result = [regex]::Replace($result, '(?i)\\b([A-Z]:\\\\Users\\\\)[^\\\\\\s]+', '$1<user>')\n    $result = [regex]::Replace($result, '(?i)\\b([A-Z]:\\\\Documents and Settings\\\\)[^\\\\\\s]+', '$1<user>')\n\n    $result = [regex]::Replace($result, '(?i)(Authorization:\\s*Bearer\\s+)[^\\s\"''`]+', '$1<REDACTED>')\n    $result = [regex]::Replace($result, '(?i)([?&](?:key|api_key|apikey|token|auth|authorization)=)[^&\\s\"''`]+', '$1<REDACTED>')\n    $result = [regex]::Replace($result, '\\bsk-(?:proj-)?[A-Za-z0-9_-]{8,}\\b', 'sk-<REDACTED>')\n    $result = [regex]::Replace($result, '\\bAIza[0-9A-Za-z_-]{20,}\\b', 'AIza<REDACTED>')\n\n    return $result\n}\n\nif ($ShowHelp) {\n    Show-Usage\n    exit 0\n}\n\nif ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {\n    throw \"This script is for Windows only.\"\n}\n\nif (-not (Get-Command Compress-Archive -ErrorAction SilentlyContinue)) {\n    throw \"Compress-Archive cmdlet is unavailable.\"\n}\n\nif ([string]::IsNullOrWhiteSpace($OutputDir) -or -not (Test-Path -LiteralPath $OutputDir)) {\n    $OutputDir = $env:USERPROFILE\n}\nNew-DirectoryIfMissing -Path $OutputDir\n$OutputDir = (Resolve-Path -LiteralPath $OutputDir).Path\n\n$logDirs = @()\nif ($env:APPDATA) {\n    $logDirs += (Join-Path $env:APPDATA \"AIFileSorter\\logs\")\n}\n\n$now = Get-Date\n$since = $null\n$windowNote = \"\"\n\nif (-not [string]::IsNullOrWhiteSpace($TimePeriod)) {\n    $span = Convert-TimePeriodToTimeSpan -InputValue $TimePeriod\n    $since = $now - $span\n    $windowNote = \"time-period mode (-TimePeriod $TimePeriod)\"\n} else {\n    $latest = Get-LatestAppLogTime -LogDirs $logDirs\n    if ($latest -gt [datetime]::MinValue) {\n        $since = $latest.AddMinutes(-5)\n        if ($since -lt [datetime]::UnixEpoch) {\n            $since = [datetime]::UnixEpoch\n        }\n        $windowNote = \"latest-run mode (newest app log mtime: $($latest.ToString(\"yyyy-MM-dd HH:mm:ss\")))\"\n    } else {\n        $since = $now.AddHours(-1)\n        $windowNote = \"fallback mode (no app logs found, using last 1h)\"\n        Write-Warning \"No app logs found. Falling back to last 1h.\"\n    }\n}\n\n$timestamp = Get-Date -Format \"yyyyMMdd_HHmmss\"\n$baseName = \"aifs-windows-diagnostics-$timestamp\"\n$workDir = Join-Path $OutputDir $baseName\n$rawDir = Join-Path $workDir \"raw\"\n$redactedDir = Join-Path $workDir \"redacted\"\n$zipPath = Join-Path $OutputDir \"$baseName-redacted.zip\"\n\nNew-DirectoryIfMissing -Path $rawDir\nNew-DirectoryIfMissing -Path $redactedDir\n\n$appLogsCopied = 0\nif ($env:APPDATA) {\n    $appLogsCopied += Copy-RecentAppLogs -SourceDir (Join-Path $env:APPDATA \"AIFileSorter\\logs\") -DestinationDir (Join-Path $rawDir \"appdata-logs\") -Since $since\n}\n\nif ($appLogsCopied -eq 0) {\n    Write-Warning \"No recent app log files matched the selected window.\"\n}\n\n$crashRoot = Join-Path $rawDir \"crash\"\nNew-DirectoryIfMissing -Path $crashRoot\n$crashCount = 0\n\nif ($env:LOCALAPPDATA) {\n    $crashDumpDir = Join-Path $env:LOCALAPPDATA \"CrashDumps\"\n    if (Test-Path -LiteralPath $crashDumpDir) {\n        $dumpDest = Join-Path $crashRoot \"CrashDumps\"\n        New-DirectoryIfMissing -Path $dumpDest\n        $dumps = Get-ChildItem -Path $crashDumpDir -File -ErrorAction SilentlyContinue |\n            Where-Object {\n                ($_.Name -match '(?i)aifilesorter') -and ($_.LastWriteTime -ge $since)\n            }\n        foreach ($dump in $dumps) {\n            Copy-Item -LiteralPath $dump.FullName -Destination $dumpDest -Force\n            $crashCount++\n        }\n    }\n\n    $werBase = Join-Path $env:LOCALAPPDATA \"Microsoft\\Windows\\WER\"\n    foreach ($sub in @(\"ReportArchive\", \"ReportQueue\")) {\n        $dir = Join-Path $werBase $sub\n        if (-not (Test-Path -LiteralPath $dir)) { continue }\n\n        $dest = Join-Path $crashRoot \"WER\\$sub\"\n        New-DirectoryIfMissing -Path $dest\n\n        $reportDirs = Get-ChildItem -Path $dir -Directory -ErrorAction SilentlyContinue |\n            Where-Object {\n                ($_.Name -match '(?i)aifilesorter') -and ($_.LastWriteTime -ge $since)\n            }\n        foreach ($reportDir in $reportDirs) {\n            Copy-Item -LiteralPath $reportDir.FullName -Destination $dest -Recurse -Force\n            $crashCount++\n        }\n    }\n}\n\n$eventsDir = Join-Path $rawDir \"events\"\nNew-DirectoryIfMissing -Path $eventsDir\n\ntry {\n    $appEvents = Get-WinEvent -FilterHashtable @{ LogName = \"Application\"; StartTime = $since } -ErrorAction Stop |\n        Where-Object { $_.Message -match '(?i)aifilesorter|AIFileSorter' }\n    if ($appEvents) {\n        $appEvents |\n            Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message |\n            Format-List | Out-File -FilePath (Join-Path $eventsDir \"application_events.txt\") -Encoding utf8\n    } else {\n        \"No matching Application events.\" | Out-File -FilePath (Join-Path $eventsDir \"application_events.txt\") -Encoding utf8\n    }\n} catch {\n    \"Failed to collect Application events: $($_.Exception.Message)\" |\n        Out-File -FilePath (Join-Path $eventsDir \"application_events.txt\") -Encoding utf8\n}\n\ntry {\n    $sysEvents = Get-WinEvent -FilterHashtable @{ LogName = \"System\"; StartTime = $since } -ErrorAction Stop |\n        Where-Object { $_.Message -match '(?i)aifilesorter|AIFileSorter' }\n    if ($sysEvents) {\n        $sysEvents |\n            Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message |\n            Format-List | Out-File -FilePath (Join-Path $eventsDir \"system_events.txt\") -Encoding utf8\n    } else {\n        \"No matching System events.\" | Out-File -FilePath (Join-Path $eventsDir \"system_events.txt\") -Encoding utf8\n    }\n} catch {\n    \"Failed to collect System events: $($_.Exception.Message)\" |\n        Out-File -FilePath (Join-Path $eventsDir \"system_events.txt\") -Encoding utf8\n}\n\n$systemInfoFile = Join-Path $rawDir \"system_info.txt\"\n@(\n    \"Collected at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')\"\n    \"Window note: $windowNote\"\n    \"Window start: $($since.ToString('yyyy-MM-dd HH:mm:ss'))\"\n    \"App logs copied: $appLogsCopied\"\n    \"Crash artifacts copied: $crashCount\"\n    \"\"\n    \"== OS ==\"\n    (Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Caption)\n    (Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Version)\n    \"\"\n    \"== CPU ==\"\n    (Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Name)\n    \"\"\n    \"== Computer ==\"\n    $env:COMPUTERNAME\n) | Out-File -FilePath $systemInfoFile -Encoding utf8\n\n$rawFiles = Get-ChildItem -Path $rawDir -Recurse -File -ErrorAction SilentlyContinue\nforeach ($srcFile in $rawFiles) {\n    $relative = $srcFile.FullName.Substring($rawDir.Length).TrimStart('\\')\n    $dst = Join-Path $redactedDir $relative\n    $dstParent = Split-Path -Parent $dst\n    New-DirectoryIfMissing -Path $dstParent\n\n    if (Is-TextLikeFile -Path $srcFile.FullName) {\n        try {\n            $content = Get-Content -LiteralPath $srcFile.FullName -Raw -ErrorAction Stop\n            $redacted = Redact-TextContent -Content $content\n            Set-Content -LiteralPath $dst -Value $redacted -Encoding utf8\n        } catch {\n            Copy-Item -LiteralPath $srcFile.FullName -Destination $dst -Force\n        }\n    } else {\n        Copy-Item -LiteralPath $srcFile.FullName -Destination $dst -Force\n    }\n}\n\nif (Test-Path -LiteralPath $zipPath) {\n    Remove-Item -LiteralPath $zipPath -Force\n}\nCompress-Archive -Path (Join-Path $workDir \"redacted\") -DestinationPath $zipPath -Force\n\nif (-not $KeepRaw) {\n    Remove-Item -LiteralPath $rawDir -Recurse -Force\n}\n\nWrite-Output \"Diagnostics bundle ready:\"\nWrite-Output \"  $zipPath\"\nWrite-Output \"\"\nWrite-Output \"Collected with: $windowNote\"\nWrite-Output \"If needed, inspect redacted files at:\"\nWrite-Output \"  $redactedDir\"\n\nif ($OpenOutput) {\n    Start-Process explorer.exe \"/select,`\"$zipPath`\"\" | Out-Null\n}\n"
  },
  {
    "path": "app/scripts/gen_run_wrapper.py",
    "content": "#!/usr/bin/env python3\nimport argparse\nfrom pathlib import Path\n\nDEV_DECL = \"SCRIPT_DIR=\\\"$(cd \\\"$(dirname \\\"$0\\\")\\\" && pwd)\\\"\\nAPP_DIR=\\\"$(cd \\\"$SCRIPT_DIR/..\\\" && pwd)\\\"\"\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--mode', choices=['dev', 'install'], default='dev')\n    parser.add_argument('--install-app-dir', default='')\n    parser.add_argument('--binary', required=True)\n    parser.add_argument('--template', default='scripts/run_aifilesorter.sh.in')\n    parser.add_argument('--output', required=True)\n    args = parser.parse_args()\n\n    template = Path(args.template).read_text()\n    if args.mode == 'dev':\n        app_decl = DEV_DECL\n    else:\n        app_decl = f'APP_DIR=\"{args.install_app_dir}\"'\n    content = template.replace('@APP_DIR_DECLARATION@', app_decl)\n    content = content.replace('@WRAPPED_BINARY@', args.binary)\n    Path(args.output).write_text(content)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "app/scripts/generate_icon.ps1",
    "content": "param(\n    [Parameter(Mandatory = $true)][string]$BasePng,\n    [Parameter(Mandatory = $true)][string]$Ico\n)\n\n$ErrorActionPreference = \"Stop\"\n\nAdd-Type -AssemblyName System.Drawing\n\n$basePath = Resolve-Path $BasePng\nif (-not $basePath) {\n    throw \"Base PNG '$BasePng' does not exist.\"\n}\n\n$icoFullPath = [System.IO.Path]::GetFullPath($Ico)\n$icoDir = [System.IO.Path]::GetDirectoryName($icoFullPath)\nif ($icoDir -and -not (Test-Path $icoDir)) {\n    New-Item -ItemType Directory -Force -Path $icoDir | Out-Null\n}\n\n$bitmap = [System.Drawing.Bitmap]::FromFile($basePath)\ntry {\n    $width = $bitmap.Width\n    $height = $bitmap.Height\n    $stream = New-Object System.IO.MemoryStream\n    $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png)\n    $bytes = $stream.ToArray()\n    $stream.Dispose()\n}\nfinally {\n    $bitmap.Dispose()\n}\n\n$fs = [System.IO.File]::Open($icoFullPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)\n$bw = New-Object System.IO.BinaryWriter($fs)\n\ntry {\n    $bw.Write([UInt16]0)\n    $bw.Write([UInt16]1)\n    $bw.Write([UInt16]1)\n\n    $widthByte  = if ($width  -ge 256) { 0 } else { [byte]$width }\n    $heightByte = if ($height -ge 256) { 0 } else { [byte]$height }\n    $bw.Write([byte]$widthByte)\n    $bw.Write([byte]$heightByte)\n    $bw.Write([byte]0)\n    $bw.Write([byte]0)\n    $bw.Write([UInt16]1)\n    $bw.Write([UInt16]32)\n    $bw.Write([UInt32]$bytes.Length)\n    $bw.Write([UInt32](6 + 16))\n    $bw.Write($bytes)\n}\nfinally {\n    $bw.Dispose()\n    $fs.Dispose()\n}\n\n"
  },
  {
    "path": "app/scripts/package_deb.sh",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Builds a Debian package for AI File Sorter that bundles only the project-specific\n# llama/ggml libraries and assumes all other runtime libraries are supplied by the system.\n#\n# Usage:\n#   ./package_deb.sh [options] [version]\n# If no version is supplied, the script reads app/include/app_version.hpp.\n# By default the package includes CPU precompiled libs. Add flags for GPU variants.\n\nSCRIPT_DIR=\"$(cd -- \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nREPO_ROOT=\"$(cd -- \"$SCRIPT_DIR/../..\" && pwd)\"\nAPP_DIR=\"$REPO_ROOT/app\"\n\nusage() {\n    cat <<'EOF'\nUsage: ./package_deb.sh [options] [version]\n\nOptions:\n  --include-cuda     Include precompiled CUDA runtime libs (app/lib/precompiled/cuda)\n  --include-vulkan   Include precompiled Vulkan runtime libs (app/lib/precompiled/vulkan)\n  --include-all      Include CPU + CUDA + Vulkan precompiled runtime libs\n  -h, --help         Show this help\n\nNotes:\n  - CPU precompiled libs are included by default.\n  - Root files in app/lib/precompiled (e.g. libpdfium.so) are always included when present.\nEOF\n}\n\nVERSION_FROM_HEADER() {\n    local header=\"$1\"\n    if [[ ! -f \"$header\" ]]; then\n        echo \"0.0.0\"\n        return\n    fi\n    local line\n    line=\"$(grep -m1 'APP_VERSION' \"$header\" || true)\"\n    if [[ -z \"$line\" ]]; then\n        echo \"0.0.0\"\n        return\n    fi\n    if [[ \"$line\" =~ Version\\{[[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\\} ]]; then\n        printf \"%s.%s.%s\\n\" \"${BASH_REMATCH[1]}\" \"${BASH_REMATCH[2]}\" \"${BASH_REMATCH[3]}\"\n    else\n        echo \"0.0.0\"\n    fi\n}\n\nINCLUDE_CPU=1\nINCLUDE_CUDA=0\nINCLUDE_VULKAN=0\nVERSION_ARG=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n    case \"$1\" in\n        --include-cuda)\n            INCLUDE_CUDA=1\n            ;;\n        --include-vulkan)\n            INCLUDE_VULKAN=1\n            ;;\n        --include-all)\n            INCLUDE_CPU=1\n            INCLUDE_CUDA=1\n            INCLUDE_VULKAN=1\n            ;;\n        -h|--help)\n            usage\n            exit 0\n            ;;\n        -*)\n            echo \"Unknown option: $1\" >&2\n            usage >&2\n            exit 1\n            ;;\n        *)\n            if [[ -n \"$VERSION_ARG\" ]]; then\n                echo \"Unexpected extra argument: $1\" >&2\n                usage >&2\n                exit 1\n            fi\n            VERSION_ARG=\"$1\"\n            ;;\n    esac\n    shift\ndone\n\nVERSION=\"${VERSION_ARG:-$(VERSION_FROM_HEADER \"$APP_DIR/include/app_version.hpp\")}\"\n\nif [[ -z \"$VERSION\" ]]; then\n    echo \"Failed to determine package version.\" >&2\n    exit 1\nfi\n\nBIN_PATH=\"$APP_DIR/bin/aifilesorter-bin\"\nif [[ ! -x \"$BIN_PATH\" ]]; then\n    echo \"Binary not found at $BIN_PATH — running make.\" >&2\n    make -C \"$APP_DIR\"\nfi\n\nif [[ ! -x \"$BIN_PATH\" ]]; then\n    echo \"Binary still missing after build attempt.\" >&2\n    exit 1\nfi\n\nget_needed_soname() {\n    local binary=\"$1\"\n    local pattern=\"$2\"\n    if ! command -v readelf >/dev/null 2>&1; then\n        return 0\n    fi\n    readelf -d \"$binary\" 2>/dev/null | awk -v pat=\"$pattern\" '\n        /NEEDED/ {\n            gsub(/\\[|\\]/, \"\", $5);\n            if ($5 ~ pat) { print $5; exit }\n        }'\n}\n\nresolve_fmt_dep() {\n    local soname\n    soname=\"$(get_needed_soname \"$BIN_PATH\" '^libfmt[.]so')\"\n    case \"$soname\" in\n        libfmt.so.10) echo \"libfmt10\" ;;\n        libfmt.so.9) echo \"libfmt9\" ;;\n        libfmt.so.8) echo \"libfmt8\" ;;\n        *) echo \"libfmt10\" ;;\n    esac\n}\n\nresolve_jsoncpp_dep() {\n    local soname\n    soname=\"$(get_needed_soname \"$BIN_PATH\" '^libjsoncpp[.]so')\"\n    case \"$soname\" in\n        libjsoncpp.so.26) echo \"libjsoncpp26\" ;;\n        libjsoncpp.so.25) echo \"libjsoncpp25\" ;;\n        libjsoncpp.so.24) echo \"libjsoncpp24\" ;;\n        *) echo \"libjsoncpp26\" ;;\n    esac\n}\n\nresolve_mediainfo_dep() {\n    local soname\n    soname=\"$(get_needed_soname \"$BIN_PATH\" '^libmediainfo[.]so')\"\n    case \"$soname\" in\n        libmediainfo.so.0) echo \"libmediainfo0v5\" ;;\n        *) echo \"libmediainfo0v5\" ;;\n    esac\n}\n\njoin_by_comma_space() {\n    local first=1\n    local item\n    for item in \"$@\"; do\n        if [[ \"$first\" == \"1\" ]]; then\n            printf '%s' \"$item\"\n            first=0\n        else\n            printf ', %s' \"$item\"\n        fi\n    done\n    printf '\\n'\n}\n\nFMT_DEP=\"$(resolve_fmt_dep)\"\nJSONCPP_DEP=\"$(resolve_jsoncpp_dep)\"\nCURL_DEP=\"libcurl4 | libcurl4t64\"\nMEDIAINFO_DEP=\"$(resolve_mediainfo_dep)\"\nZLIB_DEP=\"zlib1g\"\n\nOUT_DIR=\"$REPO_ROOT/dist/aifilesorter_deb\"\nPKG_NAME=\"aifilesorter_${VERSION}\"\nPKG_ROOT=\"$OUT_DIR/$PKG_NAME\"\n\necho \"Staging package in $PKG_ROOT\"\nrm -rf \"$PKG_ROOT\"\nmkdir -p \\\n    \"$PKG_ROOT/DEBIAN\" \\\n    \"$PKG_ROOT/opt/aifilesorter/bin\" \\\n    \"$PKG_ROOT/opt/aifilesorter/lib\" \\\n    \"$PKG_ROOT/opt/aifilesorter/certs\" \\\n    \"$PKG_ROOT/usr/bin\"\n\ninstall -m 0755 \"$BIN_PATH\" \"$PKG_ROOT/opt/aifilesorter/bin/aifilesorter-bin\"\nln -sf aifilesorter-bin \"$PKG_ROOT/opt/aifilesorter/bin/aifilesorter\"\n\nPRECOMPILED_SRC=\"$APP_DIR/lib/precompiled\"\nPRECOMPILED_DST=\"$PKG_ROOT/opt/aifilesorter/lib/precompiled\"\n\ncopy_variant_dir() {\n    local variant=\"$1\"\n    local enabled=\"$2\"\n    local src_dir=\"$PRECOMPILED_SRC/$variant\"\n    if [[ \"$enabled\" != \"1\" ]]; then\n        return 0\n    fi\n    if [[ ! -d \"$src_dir\" ]]; then\n        echo \"Requested precompiled variant '$variant' but '$src_dir' was not found.\" >&2\n        exit 1\n    fi\n    cp -a \"$src_dir\" \"$PRECOMPILED_DST/\"\n}\n\necho \"Copying llama/ggml libraries\"\nif [[ -d \"$PRECOMPILED_SRC\" ]]; then\n    mkdir -p \"$PRECOMPILED_DST\"\n    # Keep root-level runtime payloads such as libpdfium.so.\n    find \"$PRECOMPILED_SRC\" -mindepth 1 -maxdepth 1 \\( -type f -o -type l \\) \\\n        -exec cp -a {} \"$PRECOMPILED_DST/\" \\;\n    copy_variant_dir cpu \"$INCLUDE_CPU\"\n    copy_variant_dir cuda \"$INCLUDE_CUDA\"\n    copy_variant_dir vulkan \"$INCLUDE_VULKAN\"\nelse\n    echo \"Warning: '$PRECOMPILED_SRC' not found; packaging without bundled llama/ggml runtime libs.\" >&2\nfi\n\nSELECTED_VARIANTS=()\nif [[ \"$INCLUDE_CPU\" == \"1\" ]]; then SELECTED_VARIANTS+=(\"cpu\"); fi\nif [[ \"$INCLUDE_CUDA\" == \"1\" ]]; then SELECTED_VARIANTS+=(\"cuda\"); fi\nif [[ \"$INCLUDE_VULKAN\" == \"1\" ]]; then SELECTED_VARIANTS+=(\"vulkan\"); fi\necho \"Included precompiled variants: ${SELECTED_VARIANTS[*]}\"\n\nPACKAGE_DEPENDS=(\n    \"libc6 (>= 2.31)\"\n    \"libstdc++6 (>= 12)\"\n    \"libgcc-s1 (>= 12)\"\n    \"libqt6widgets6 (>= 6.2)\"\n    \"libqt6gui6 (>= 6.2)\"\n    \"libqt6core6 (>= 6.2)\"\n    \"libqt6dbus6 (>= 6.2)\"\n    \"qt6-wayland\"\n    \"$CURL_DEP\"\n    \"$JSONCPP_DEP\"\n    \"libsqlite3-0\"\n    \"$FMT_DEP\"\n    \"libssl3\"\n    \"libopenblas0-pthread\"\n    \"$MEDIAINFO_DEP\"\n    \"$ZLIB_DEP\"\n)\nif [[ \"$INCLUDE_VULKAN\" == \"1\" ]]; then\n    PACKAGE_DEPENDS+=(\"libvulkan1\")\nfi\nPACKAGE_DEPENDS_STR=\"$(join_by_comma_space \"${PACKAGE_DEPENDS[@]}\")\"\n\nDESCRIPTION_TEXT=\"AI-powered file categorization tool. Requires the listed runtime libraries from the host system.\"\nif [[ \"$INCLUDE_VULKAN\" == \"1\" ]]; then\n    DESCRIPTION_TEXT+=\" Includes the Vulkan backend and requires a working host Vulkan loader/driver stack.\"\nfi\nif [[ \"$INCLUDE_CUDA\" == \"1\" ]]; then\n    DESCRIPTION_TEXT+=\" CUDA-enabled builds require matching NVIDIA runtime libraries installed separately.\"\nfi\n\nif [[ -f \"$APP_DIR/resources/certs/cacert.pem\" ]]; then\n    install -m 0644 \"$APP_DIR/resources/certs/cacert.pem\" \"$PKG_ROOT/opt/aifilesorter/certs/cacert.pem\"\nfi\n\nif [[ -f \"$REPO_ROOT/LICENSE\" ]]; then\n    install -m 0644 \"$REPO_ROOT/LICENSE\" \"$PKG_ROOT/opt/aifilesorter/LICENSE\"\nfi\n\ncat > \"$PKG_ROOT/usr/bin/run_aifilesorter.sh\" <<'EOF'\n#!/bin/sh\nAPP_DIR=\"/opt/aifilesorter\"\nCPU_LIB_DIR=\"$APP_DIR/lib/precompiled/cpu/bin\"\nCUDA_LIB_DIR=\"$APP_DIR/lib/precompiled/cuda/bin\"\nVULKAN_LIB_DIR=\"$APP_DIR/lib/precompiled/vulkan/bin\"\nPRECOMPILED_ROOT_DIR=\"$APP_DIR/lib/precompiled\"\nPLATFORM_CANDIDATES=\"/usr/lib/x86_64-linux-gnu/qt6/plugins /usr/lib/qt6/plugins /lib/x86_64-linux-gnu/qt6/plugins\"\n\nchoose_vulkan_path() {\n    if [ -d \"$VULKAN_LIB_DIR\" ]; then\n        if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libvulkan; then\n            echo \"$VULKAN_LIB_DIR\"\n            return\n        fi\n        for candidate in /usr/lib/x86_64-linux-gnu/libvulkan.so* /usr/lib/libvulkan.so* /lib/x86_64-linux-gnu/libvulkan.so*; do\n            if [ \"$candidate\" = \"/usr/lib/x86_64-linux-gnu/libvulkan.so*\" ]; then\n                break\n            fi\n            if [ -e \"$candidate\" ]; then\n                echo \"$VULKAN_LIB_DIR\"\n                return\n            fi\n        done\n    fi\n    echo \"\"\n}\n\nchoose_cuda_path() {\n    if [ -d \"$CUDA_LIB_DIR\" ]; then\n        if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libcudart; then\n            echo \"$CUDA_LIB_DIR\"\n            return\n        fi\n        for candidate in /usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*; do\n            if [ \"$candidate\" = \"/usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*\" ]; then\n                break\n            fi\n            if [ -e \"$candidate\" ]; then\n                echo \"$CUDA_LIB_DIR\"\n                return\n            fi\n        done\n    fi\n    echo \"\"\n}\n\nSELECTED_VULKAN_DIR=\"$(choose_vulkan_path)\"\nSELECTED_CUDA_DIR=\"$(choose_cuda_path)\"\nPATH_COMPONENTS=\"$CPU_LIB_DIR:$PRECOMPILED_ROOT_DIR\"\nif [ -n \"$SELECTED_VULKAN_DIR\" ] && [ -d \"$SELECTED_VULKAN_DIR\" ] && [ \"$SELECTED_VULKAN_DIR\" != \"$CPU_LIB_DIR\" ]; then\n    PATH_COMPONENTS=\"$SELECTED_VULKAN_DIR:$PATH_COMPONENTS\"\nelif [ -n \"$SELECTED_CUDA_DIR\" ] && [ -d \"$SELECTED_CUDA_DIR\" ] && [ \"$SELECTED_CUDA_DIR\" != \"$CPU_LIB_DIR\" ]; then\n    PATH_COMPONENTS=\"$SELECTED_CUDA_DIR:$PATH_COMPONENTS\"\nfi\nif [ -n \"$LD_LIBRARY_PATH\" ]; then\n    export LD_LIBRARY_PATH=\"$PATH_COMPONENTS:$LD_LIBRARY_PATH\"\nelse\n    export LD_LIBRARY_PATH=\"$PATH_COMPONENTS\"\nfi\n\nif [ -z \"$QT_QPA_PLATFORM_PLUGIN_PATH\" ]; then\n    for candidate in $PLATFORM_CANDIDATES; do\n        if [ -d \"$candidate/platforms\" ]; then\n            export QT_QPA_PLATFORM_PLUGIN_PATH=\"$candidate/platforms\"\n            break\n        fi\n    done\nfi\n\nif [ -n \"$QT_QPA_PLATFORM_PLUGIN_PATH\" ] && [ ! -f \"$QT_QPA_PLATFORM_PLUGIN_PATH/libqxcb.so\" ]; then\n    if [ -n \"$WAYLAND_DISPLAY\" ] || [ \"$XDG_SESSION_TYPE\" = \"wayland\" ]; then\n        export QT_QPA_PLATFORM=\"wayland\"\n    else\n        echo \"Qt xcb platform plugin (libqxcb.so) not found in \\$QT_QPA_PLATFORM_PLUGIN_PATH ($QT_QPA_PLATFORM_PLUGIN_PATH).\" >&2\n        echo \"Install a Qt 6 XCB platform plugin (e.g. from qt.io archives) or run under a Wayland session.\" >&2\n        exit 1\n    fi\nfi\n\nexec \"$APP_DIR/bin/aifilesorter-bin\" \"$@\"\nEOF\nchmod 0755 \"$PKG_ROOT/usr/bin/run_aifilesorter.sh\"\nln -sf run_aifilesorter.sh \"$PKG_ROOT/usr/bin/aifilesorter\"\n\nCONTROL_FILE=\"$PKG_ROOT/DEBIAN/control\"\ncat > \"$CONTROL_FILE\" <<EOF\nPackage: aifilesorter\nVersion: ${VERSION}\nSection: utils\nPriority: optional\nArchitecture: amd64\nMaintainer: AI File Sorter Team <support@example.com>\nInstalled-Size: 0\nDepends: ${PACKAGE_DEPENDS_STR}\nDescription: AI File Sorter desktop application\n ${DESCRIPTION_TEXT}\nEOF\nchmod 0644 \"$CONTROL_FILE\"\n\necho \"Adjusting permissions\"\nfind \"$PKG_ROOT\" -type d -exec chmod 755 {} +\nfind \"$PKG_ROOT/opt/aifilesorter/lib\" -type f -exec chmod 0644 {} +\nchmod 0755 \"$PKG_ROOT/opt/aifilesorter/bin/aifilesorter-bin\"\nchmod 0755 \"$PKG_ROOT/opt/aifilesorter/bin/aifilesorter\"\nchmod 0755 \"$PKG_ROOT/usr/bin/run_aifilesorter.sh\"\nchmod 0755 \"$PKG_ROOT/usr/bin/aifilesorter\"\n\nSIZE_KB=$(du -sk \"$PKG_ROOT\" | cut -f1)\nsed -i \"s/^Installed-Size: .*/Installed-Size: ${SIZE_KB}/\" \"$CONTROL_FILE\"\n\nmkdir -p \"$OUT_DIR\"\nDEB_PATH=\"$OUT_DIR/${PKG_NAME}_amd64.deb\"\nrm -f \"$DEB_PATH\"\n\necho \"Building package $DEB_PATH\"\ndpkg-deb --build --root-owner-group \"$PKG_ROOT\" \"$OUT_DIR\"\n\necho \"Done. Package created at $DEB_PATH\"\n"
  },
  {
    "path": "app/scripts/rebuild_and_test.sh",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nscript_dir=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nrepo_root=\"$(cd \"${script_dir}/../..\" && pwd)\"\nbuild_dir=\"${repo_root}/build-tests\"\n\necho \"[INFO] Configuring tests build directory at ${build_dir}\"\ncmake -S \"${repo_root}/app\" -B \"${build_dir}\" -DAI_FILE_SORTER_BUILD_TESTS=ON\n\necho \"[INFO] Building tests\"\ncmake --build \"${build_dir}\"\n\necho \"[INFO] Running ctest\"\nctest --test-dir \"${build_dir}\"\n"
  },
  {
    "path": "app/scripts/run_aifilesorter.sh.in",
    "content": "#!/bin/sh\n@APP_DIR_DECLARATION@\nCPU_LIB_DIR=\"$APP_DIR/lib/precompiled/cpu/bin\"\nCUDA_LIB_DIR=\"$APP_DIR/lib/precompiled/cuda/bin\"\nVULKAN_LIB_DIR=\"$APP_DIR/lib/precompiled/vulkan/bin\"\nPRECOMPILED_ROOT_DIR=\"$APP_DIR/lib/precompiled\"\nPLATFORM_CANDIDATES=\"/usr/lib/x86_64-linux-gnu/qt6/plugins /usr/lib/qt6/plugins /lib/x86_64-linux-gnu/qt6/plugins\"\n\nselect_cuda_dir() {\n    if [ -d \"$CUDA_LIB_DIR\" ]; then\n        if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libcudart; then\n            echo \"$CUDA_LIB_DIR\"\n            return\n        fi\n        for candidate in /usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*; do\n            [ \"$candidate\" = \"/usr/local/cuda*/targets/x86_64-linux/lib/libcudart.so*\" ] && break\n            if [ -e \"$candidate\" ]; then\n                echo \"$CUDA_LIB_DIR\"\n                return\n            fi\n        done\n    fi\n    echo \"\"\n}\n\nselect_vulkan_dir() {\n    if [ -d \"$VULKAN_LIB_DIR\" ]; then\n        if command -v ldconfig >/dev/null 2>&1 && ldconfig -p 2>/dev/null | grep -q libvulkan; then\n            echo \"$VULKAN_LIB_DIR\"\n            return\n        fi\n        for candidate in /usr/lib/x86_64-linux-gnu/libvulkan.so* /usr/lib/libvulkan.so* /lib/x86_64-linux-gnu/libvulkan.so*; do\n            [ \"$candidate\" = \"/usr/lib/x86_64-linux-gnu/libvulkan.so*\" ] && break\n            if [ -e \"$candidate\" ]; then\n                echo \"$VULKAN_LIB_DIR\"\n                return\n            fi\n        done\n    fi\n    echo \"\"\n}\n\nCUDA_OVERRIDE=\"\"\nVULKAN_OVERRIDE=\"\"\nfor arg in \"$@\"; do\n    case \"$arg\" in\n        --cuda=on|cuda=on) CUDA_OVERRIDE=\"on\" ;;\n        --cuda=off|cuda=off) CUDA_OVERRIDE=\"off\" ;;\n        --vulkan=on|vulkan=on) VULKAN_OVERRIDE=\"on\" ;;\n        --vulkan=off|vulkan=off) VULKAN_OVERRIDE=\"off\" ;;\n    esac\ndone\n\nif [ \"$CUDA_OVERRIDE\" = \"on\" ] && [ \"$VULKAN_OVERRIDE\" = \"on\" ]; then\n    echo \"Cannot force both CUDA and Vulkan simultaneously.\" >&2\n    exit 1\nfi\n\nSELECTED_CUDA_DIR=\"$(select_cuda_dir)\"\nSELECTED_VK_DIR=\"$(select_vulkan_dir)\"\n\nUSE_CUDA=0\nUSE_VULKAN=0\nGPU_BACKEND=\"cpu\"\nGGML_VARIANT=\"wocuda\"\nLLAMA_DEVICE=\"\"\nif [ -n \"$SELECTED_VK_DIR\" ]; then\n    USE_VULKAN=1\nelif [ -n \"$SELECTED_CUDA_DIR\" ]; then\n    USE_CUDA=1\nfi\n\nif [ \"$CUDA_OVERRIDE\" = \"on\" ]; then\n    if [ -n \"$SELECTED_CUDA_DIR\" ]; then\n        USE_CUDA=1\n        USE_VULKAN=0\n    else\n        echo \"Warning: CUDA forced but not detected; falling back.\" >&2\n        USE_CUDA=0\n    fi\nelif [ \"$CUDA_OVERRIDE\" = \"off\" ]; then\n    USE_CUDA=0\nfi\n\nif [ \"$VULKAN_OVERRIDE\" = \"on\" ]; then\n    if [ -n \"$SELECTED_VK_DIR\" ]; then\n        USE_VULKAN=1\n        if [ \"$CUDA_OVERRIDE\" != \"off\" ]; then\n            USE_CUDA=0\n        fi\n    else\n        echo \"Warning: Vulkan forced but not detected; falling back.\" >&2\n        USE_VULKAN=0\n    fi\nelif [ \"$VULKAN_OVERRIDE\" = \"off\" ]; then\n    USE_VULKAN=0\nfi\n\nif [ $USE_CUDA -eq 0 ] && [ $USE_VULKAN -eq 0 ]; then\n    if [ \"$VULKAN_OVERRIDE\" != \"off\" ] && [ -n \"$SELECTED_VK_DIR\" ]; then\n        USE_VULKAN=1\n    elif [ \"$CUDA_OVERRIDE\" != \"off\" ] && [ -n \"$SELECTED_CUDA_DIR\" ]; then\n        USE_CUDA=1\n    fi\nfi\n\nif [ $USE_CUDA -eq 1 ]; then\n    echo \"Using CUDA backend.\" >&2\n    unset GGML_DISABLE_CUDA\n    GPU_BACKEND=\"cuda\"\n    GGML_VARIANT=\"wcuda\"\n    LLAMA_DEVICE=\"cuda\"\nelif [ $USE_VULKAN -eq 1 ]; then\n    echo \"Using Vulkan backend.\" >&2\n    export GGML_DISABLE_CUDA=1\n    GPU_BACKEND=\"vulkan\"\n    GGML_VARIANT=\"wvulkan\"\n    LLAMA_DEVICE=\"vulkan\"\nelse\n    echo \"Using CPU backend.\" >&2\n    export GGML_DISABLE_CUDA=1\n    GPU_BACKEND=\"cpu\"\n    GGML_VARIANT=\"wocuda\"\n    LLAMA_DEVICE=\"\"\nfi\n\nexport AI_FILE_SORTER_GPU_BACKEND=\"$GPU_BACKEND\"\nexport AI_FILE_SORTER_GGML_DIR=\"$APP_DIR/lib/ggml/$GGML_VARIANT\"\nif [ -n \"$LLAMA_DEVICE\" ]; then\n    export LLAMA_ARG_DEVICE=\"$LLAMA_DEVICE\"\nelse\n    unset LLAMA_ARG_DEVICE\nfi\n\nLIB_PATH=\"$CPU_LIB_DIR:$PRECOMPILED_ROOT_DIR\"\nif [ $USE_CUDA -eq 1 ] && [ -n \"$SELECTED_CUDA_DIR\" ]; then\n    LIB_PATH=\"$SELECTED_CUDA_DIR:$LIB_PATH\"\nelif [ $USE_VULKAN -eq 1 ] && [ -n \"$SELECTED_VK_DIR\" ]; then\n    LIB_PATH=\"$SELECTED_VK_DIR:$LIB_PATH\"\nfi\nif [ -n \"$LD_LIBRARY_PATH\" ]; then\n    export LD_LIBRARY_PATH=\"$LIB_PATH:$LD_LIBRARY_PATH\"\nelse\n    export LD_LIBRARY_PATH=\"$LIB_PATH\"\nfi\n\nif [ -z \"$QT_QPA_PLATFORM_PLUGIN_PATH\" ]; then\n    for candidate in $PLATFORM_CANDIDATES; do\n        if [ -d \"$candidate/platforms\" ]; then\n            export QT_QPA_PLATFORM_PLUGIN_PATH=\"$candidate/platforms\"\n            break\n        fi\n    done\nfi\nif [ -n \"$QT_QPA_PLATFORM_PLUGIN_PATH\" ] && [ ! -f \"$QT_QPA_PLATFORM_PLUGIN_PATH/libqxcb.so\" ]; then\n    if [ -n \"$WAYLAND_DISPLAY\" ] || [ \"$XDG_SESSION_TYPE\" = \"wayland\" ]; then\n        export QT_QPA_PLATFORM=\"wayland\"\n    else\n        echo \"Qt xcb platform plugin (libqxcb.so) not found in $QT_QPA_PLATFORM_PLUGIN_PATH ($QT_QPA_PLATFORM_PLUGIN_PATH).\" >&2\n        echo \"Install a Qt 6 XCB platform plugin or run under a Wayland session.\" >&2\n        exit 1\n    fi\nfi\n\nexec \"$APP_DIR/bin/@WRAPPED_BINARY@\" \"$@\"\n"
  },
  {
    "path": "app/scripts/vendor_doc_deps.ps1",
    "content": "param(\n    [string]$LibzipVersion = \"1.11.4\",\n    [string]$PugixmlVersion = \"1.15\",\n    [string]$PdfiumRelease = \"latest\",\n    [string]$PdfiumMacX64Archive = \"pdfium-mac-x64.tgz\"\n)\n\n$ErrorActionPreference = \"Stop\"\n\n$rootDir = Resolve-Path (Join-Path $PSScriptRoot \"..\\..\")\n$externalDir = Join-Path $rootDir \"external\"\n$libzipDir = Join-Path $externalDir \"libzip\"\n$pugixmlDir = Join-Path $externalDir \"pugixml\"\n$pdfiumDir = Join-Path $externalDir \"pdfium\"\n$licenseDir = Join-Path $externalDir \"THIRD_PARTY_LICENSES\"\n\nfunction Ensure-Dir([string]$Path) {\n    if (-not (Test-Path $Path)) {\n        New-Item -ItemType Directory -Path $Path -Force | Out-Null\n    }\n}\n\nfunction Require-Tool([string]$Name) {\n    $tool = Get-Command $Name -ErrorAction SilentlyContinue\n    if (-not $tool) {\n        throw \"$Name not found. Install it or ensure it is available in PATH.\"\n    }\n}\n\nfunction Download-File([string]$Url, [string]$Destination) {\n    Write-Output \"Downloading $Url\"\n    Invoke-WebRequest -Uri $Url -OutFile $Destination\n}\n\nRequire-Tool \"tar\"\n\nEnsure-Dir $externalDir\nEnsure-Dir $libzipDir\nEnsure-Dir $pugixmlDir\nEnsure-Dir $licenseDir\nEnsure-Dir (Join-Path $pdfiumDir \"linux-x64\")\nEnsure-Dir (Join-Path $pdfiumDir \"windows-x64\")\nEnsure-Dir (Join-Path $pdfiumDir \"macos-arm64\")\nEnsure-Dir (Join-Path $pdfiumDir \"macos-x64\")\n\n$tempDir = Join-Path $env:TEMP \"aifilesorter-docdeps\"\nEnsure-Dir $tempDir\n\n$libzipArchive = Join-Path $tempDir \"libzip-$LibzipVersion.tar.xz\"\nDownload-File \"https://libzip.org/download/libzip-$LibzipVersion.tar.xz\" $libzipArchive\n& tar -xf $libzipArchive -C $libzipDir --strip-components=1\nif (Test-Path (Join-Path $libzipDir \"LICENSE\")) {\n    Copy-Item (Join-Path $libzipDir \"LICENSE\") (Join-Path $licenseDir \"libzip-LICENSE\") -Force\n}\n\n$pugixmlArchive = Join-Path $tempDir \"pugixml-$PugixmlVersion.tar.gz\"\nDownload-File \"https://github.com/zeux/pugixml/releases/download/v$PugixmlVersion/pugixml-$PugixmlVersion.tar.gz\" $pugixmlArchive\n& tar -xf $pugixmlArchive -C $pugixmlDir --strip-components=1\nif (Test-Path (Join-Path $pugixmlDir \"LICENSE.md\")) {\n    Copy-Item (Join-Path $pugixmlDir \"LICENSE.md\") (Join-Path $licenseDir \"pugixml-LICENSE.md\") -Force\n} elseif (Test-Path (Join-Path $pugixmlDir \"LICENSE\")) {\n    Copy-Item (Join-Path $pugixmlDir \"LICENSE\") (Join-Path $licenseDir \"pugixml-LICENSE\") -Force\n}\n\n$pdfiumLinuxArchive = Join-Path $tempDir \"pdfium-linux-x64.tgz\"\nDownload-File \"https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-linux-x64.tgz\" $pdfiumLinuxArchive\n& tar -xf $pdfiumLinuxArchive -C (Join-Path $pdfiumDir \"linux-x64\")\n\n$pdfiumWinArchive = Join-Path $tempDir \"pdfium-win-x64.tgz\"\nDownload-File \"https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-win-x64.tgz\" $pdfiumWinArchive\n& tar -xf $pdfiumWinArchive -C (Join-Path $pdfiumDir \"windows-x64\")\n\n$pdfiumMacArchive = Join-Path $tempDir \"pdfium-mac-arm64.tgz\"\nDownload-File \"https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/pdfium-mac-arm64.tgz\" $pdfiumMacArchive\n& tar -xf $pdfiumMacArchive -C (Join-Path $pdfiumDir \"macos-arm64\")\n\n$pdfiumMacX64Archive = Join-Path $tempDir $PdfiumMacX64Archive\nDownload-File \"https://github.com/bblanchon/pdfium-binaries/releases/$PdfiumRelease/download/$PdfiumMacX64Archive\" $pdfiumMacX64Archive\n& tar -xf $pdfiumMacX64Archive -C (Join-Path $pdfiumDir \"macos-x64\")\n\nif (Test-Path (Join-Path $pdfiumDir \"linux-x64\\LICENSE\")) {\n    Copy-Item (Join-Path $pdfiumDir \"linux-x64\\LICENSE\") (Join-Path $licenseDir \"pdfium-LICENSE\") -Force\n} elseif (Test-Path (Join-Path $pdfiumDir \"linux-x64\\LICENSE.txt\")) {\n    Copy-Item (Join-Path $pdfiumDir \"linux-x64\\LICENSE.txt\") (Join-Path $licenseDir \"pdfium-LICENSE.txt\") -Force\n}\n\n$pdfiumReadme = @\"\n# PDFium prebuilts\n\nThis folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`.\nExpected layout:\n\n- linux-x64/\n- windows-x64/\n- macos-arm64/\n- macos-x64/\n\nEach folder should contain `include/` and the platform PDFium library under `lib/`:\n\n- Linux: `lib/libpdfium.so`\n- Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib`\n- macOS: `lib/libpdfium.dylib` (arm64 or x64)\n\"@\nSet-Content -Path (Join-Path $pdfiumDir \"README.md\") -Value $pdfiumReadme\n\nWrite-Output \"Done. You can now commit external/libzip, external/pugixml, and external/pdfium.\"\n"
  },
  {
    "path": "app/scripts/vendor_doc_deps.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nLIBZIP_VERSION=\"1.11.4\"\nPUGIXML_VERSION=\"1.15\"\nPDFIUM_RELEASE=\"latest\"\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/../..\" && pwd)\"\nLIBZIP_DIR=\"$ROOT_DIR/external/libzip\"\nPUGIXML_DIR=\"$ROOT_DIR/external/pugixml\"\nPDFIUM_DIR=\"$ROOT_DIR/external/pdfium\"\nLICENSE_DIR=\"$ROOT_DIR/external/THIRD_PARTY_LICENSES\"\n\nmkdir -p \"$LIBZIP_DIR\" \"$PUGIXML_DIR\" \"$LICENSE_DIR\" \\\n  \"$PDFIUM_DIR/linux-x64\" \"$PDFIUM_DIR/windows-x64\" \"$PDFIUM_DIR/macos-arm64\" \"$PDFIUM_DIR/macos-x64\"\n\ncurl -L --fail \"https://libzip.org/download/libzip-${LIBZIP_VERSION}.tar.xz\" \\\n  -o \"/tmp/libzip-${LIBZIP_VERSION}.tar.xz\"\ntar -xf \"/tmp/libzip-${LIBZIP_VERSION}.tar.xz\" --strip-components=1 -C \"$LIBZIP_DIR\"\nif [ -f \"$LIBZIP_DIR/LICENSE\" ]; then\n  cp \"$LIBZIP_DIR/LICENSE\" \"$LICENSE_DIR/libzip-LICENSE\"\nfi\n\ncurl -L --fail \"https://github.com/zeux/pugixml/releases/download/v${PUGIXML_VERSION}/pugixml-${PUGIXML_VERSION}.tar.gz\" \\\n  -o \"/tmp/pugixml-${PUGIXML_VERSION}.tar.gz\"\ntar -xf \"/tmp/pugixml-${PUGIXML_VERSION}.tar.gz\" --strip-components=1 -C \"$PUGIXML_DIR\"\nif [ -f \"$PUGIXML_DIR/LICENSE.md\" ]; then\n  cp \"$PUGIXML_DIR/LICENSE.md\" \"$LICENSE_DIR/pugixml-LICENSE.md\"\nelif [ -f \"$PUGIXML_DIR/LICENSE\" ]; then\n  cp \"$PUGIXML_DIR/LICENSE\" \"$LICENSE_DIR/pugixml-LICENSE\"\nfi\n\ncurl -L --fail \"https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-linux-x64.tgz\" \\\n  -o \"/tmp/pdfium-linux-x64.tgz\"\ntar -xf \"/tmp/pdfium-linux-x64.tgz\" -C \"$PDFIUM_DIR/linux-x64\"\nif [ -f \"$PDFIUM_DIR/linux-x64/LICENSE\" ]; then\n  cp \"$PDFIUM_DIR/linux-x64/LICENSE\" \"$LICENSE_DIR/pdfium-LICENSE\"\nelif [ -f \"$PDFIUM_DIR/linux-x64/LICENSE.txt\" ]; then\n  cp \"$PDFIUM_DIR/linux-x64/LICENSE.txt\" \"$LICENSE_DIR/pdfium-LICENSE.txt\"\nfi\n\ncurl -L --fail \"https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-win-x64.tgz\" \\\n  -o \"/tmp/pdfium-win-x64.tgz\"\ntar -xf \"/tmp/pdfium-win-x64.tgz\" -C \"$PDFIUM_DIR/windows-x64\"\n\ncurl -L --fail \"https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/pdfium-mac-arm64.tgz\" \\\n  -o \"/tmp/pdfium-mac-arm64.tgz\"\ntar -xf \"/tmp/pdfium-mac-arm64.tgz\" -C \"$PDFIUM_DIR/macos-arm64\"\n\nPDFIUM_MAC_X64_TGZ=\"${PDFIUM_MAC_X64_TGZ:-pdfium-mac-x64.tgz}\"\ncurl -L --fail \"https://github.com/bblanchon/pdfium-binaries/releases/${PDFIUM_RELEASE}/download/${PDFIUM_MAC_X64_TGZ}\" \\\n  -o \"/tmp/${PDFIUM_MAC_X64_TGZ}\"\ntar -xf \"/tmp/${PDFIUM_MAC_X64_TGZ}\" -C \"$PDFIUM_DIR/macos-x64\"\n\ncat > \"$PDFIUM_DIR/README.md\" <<'DOC'\n# PDFium prebuilts\n\nThis folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`.\nExpected layout:\n\n- linux-x64/\n- windows-x64/\n- macos-arm64/\n- macos-x64/\n\nEach folder should contain `include/` and the platform PDFium library under `lib/`:\n\n- Linux: `lib/libpdfium.so`\n- Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib`\n- macOS: `lib/libpdfium.dylib` (arm64 or x64)\nDOC\n\nprintf \"Done. You can now commit external/libzip, external/pugixml, and external/pdfium.\\n\"\n"
  },
  {
    "path": "app/startapp_linux.cpp",
    "content": "#include <iostream>\n#include <cstdio>\n#include <cstdlib>\n#include <unistd.h>\n#include <limits.h>\n#include <string>\n#include <sys/stat.h>\n#include <vector>\n#include <optional>\n#include <dlfcn.h>\n\nenum class BackendSelection {\n    Cpu,\n    Cuda,\n    Vulkan\n};\n\nstd::string getExecutableDirectory() {\n    char result[PATH_MAX];\n    ssize_t count = readlink(\"/proc/self/exe\", result, PATH_MAX);\n    std::string path(result, (count > 0) ? count : 0);\n    size_t pos = path.find_last_of(\"/\\\\\");\n    return path.substr(0, pos);\n}\n\n\nbool fileExists(const std::string& path) {\n    struct stat buffer;\n    return (stat(path.c_str(), &buffer) == 0);\n}\n\n\nvoid addToLdLibraryPath(const std::string& dir) {\n    const char* oldPath = getenv(\"LD_LIBRARY_PATH\");\n    std::string newPath = dir;\n    if (oldPath) {\n        newPath = std::string(oldPath) + \":\" + dir;\n    }\n    setenv(\"LD_LIBRARY_PATH\", newPath.c_str(), 1);\n}\n\n\nbool isCudaInstalled() {\n    return system(\"ldconfig -p | grep -q libcudart\") == 0;\n}\n\nbool isVulkanAvailable() {\n    void* handle = dlopen(\"libvulkan.so.1\", RTLD_NOW | RTLD_LOCAL);\n    if (!handle) {\n        handle = dlopen(\"libvulkan.so\", RTLD_NOW | RTLD_LOCAL);\n    }\n    if (!handle) {\n        return false;\n    }\n    dlclose(handle);\n    return true;\n}\n\n\nextern char **environ;\n\nstd::vector<std::string> collect_environment_variables()\n{\n    std::vector<std::string> envVars;\n    for (char **env = environ; *env != nullptr; ++env) {\n        envVars.emplace_back(*env);\n    }\n    return envVars;\n}\n\nvoid ensure_executable(const std::string& exePath)\n{\n    if (access(exePath.c_str(), X_OK) != 0) {\n        std::fprintf(stderr, \"App is not executable: %s\\n\", exePath.c_str());\n        perror(\"access\");\n        exit(EXIT_FAILURE);\n    }\n}\n\nvoid set_or_append_env(std::vector<std::string>& envVars,\n                       const std::string& prefix,\n                       const std::string& value)\n{\n    for (auto& env : envVars) {\n        if (env.rfind(prefix, 0) == 0) {\n            env = prefix + value;\n            return;\n        }\n    }\n    envVars.push_back(prefix + value);\n}\n\nstd::vector<char*> build_envp(std::vector<std::string>& envVars)\n{\n    std::vector<char*> envp;\n    envp.reserve(envVars.size() + 1);\n    for (auto &s : envVars) {\n        envp.push_back(s.data());\n    }\n    envp.push_back(nullptr);\n    return envp;\n}\n\nstd::vector<char*> build_argv(const std::string& exePath, int argc, char** argv)\n{\n    std::vector<std::string> arg_storage;\n    arg_storage.push_back(exePath);\n    for (int i = 1; i < argc; ++i) {\n        if (argv[i]) {\n            arg_storage.emplace_back(argv[i]);\n        }\n    }\n\n    std::vector<char*> argv_ptrs;\n    argv_ptrs.reserve(arg_storage.size() + 1);\n    for (auto& arg : arg_storage) {\n        argv_ptrs.push_back(arg.data());\n    }\n    argv_ptrs.push_back(nullptr);\n    return argv_ptrs;\n}\n\nvoid launch_with_env(const std::string& exePath,\n                     std::vector<char*>& argv_ptrs,\n                     std::vector<char*>& envp)\n{\n    execve(exePath.c_str(), argv_ptrs.data(), envp.data());\n    std::fprintf(stderr, \"execve failed\\n\");\n    perror(\"execve failed\");\n    exit(EXIT_FAILURE);\n}\n\nvoid launchMainApp(const std::string& exeDir,\n                   const std::string& libPath,\n                   int argc,\n                   char** argv,\n                   bool disable_cuda,\n                   const std::string& backend_tag,\n                   const std::string& ggml_dir,\n                   const std::string& llama_device) {\n    const std::string exePath = exeDir + \"/bin/aifilesorter\";\n    ensure_executable(exePath);\n\n    std::vector<std::string> envVars = collect_environment_variables();\n    set_or_append_env(envVars, \"LD_LIBRARY_PATH=\", libPath);\n    set_or_append_env(envVars, \"GGML_DISABLE_CUDA=\", disable_cuda ? \"1\" : \"0\");\n    set_or_append_env(envVars, \"AI_FILE_SORTER_GPU_BACKEND=\", backend_tag);\n    set_or_append_env(envVars, \"AI_FILE_SORTER_GGML_DIR=\", ggml_dir);\n    set_or_append_env(envVars, \"LLAMA_ARG_DEVICE=\", llama_device);\n\n    std::vector<char*> envp = build_envp(envVars);\n    std::vector<char*> argv_ptrs = build_argv(exePath, argc, argv);\n    launch_with_env(exePath, argv_ptrs, envp);\n}\n\nvoid launchMainApp(const std::string& exeDir,\n                   const std::string& libPath,\n                   int argc,\n                   char** argv,\n                   bool disable_cuda,\n                   const std::string& backend_tag,\n                   const std::string& ggml_dir,\n                   const std::string& llama_device);\n\n\nstruct BackendOverrideFlags {\n    std::optional<bool> cuda;\n    std::optional<bool> vulkan;\n};\n\nBackendOverrideFlags parse_backend_overrides(int argc, char* argv[])\n{\n    BackendOverrideFlags overrides;\n    for (int i = 1; i < argc; ++i) {\n        const std::string arg = argv[i] ? argv[i] : \"\";\n        if (arg.rfind(\"--cuda=\", 0) == 0) {\n            overrides.cuda = (arg.substr(7) == \"on\");\n        } else if (arg.rfind(\"--vulkan=\", 0) == 0) {\n            overrides.vulkan = (arg.substr(9) == \"on\");\n        }\n    }\n    return overrides;\n}\n\nbool validate_overrides(const BackendOverrideFlags& overrides)\n{\n    if (overrides.cuda.has_value() && overrides.vulkan.has_value() &&\n        overrides.cuda.value() && overrides.vulkan.value()) {\n        std::cerr << \"Cannot force both CUDA and Vulkan simultaneously.\" << std::endl;\n        return false;\n    }\n    return true;\n}\n\nstruct BackendState {\n    bool cuda_available{false};\n    bool vulkan_available{false};\n    BackendSelection selection{BackendSelection::Cpu};\n    std::string ggml_subdir;\n    std::string backend_tag{\"cpu\"};\n    std::string llama_device;\n};\n\nBackendState decide_backend(const BackendOverrideFlags& overrides,\n                            const std::string& baseLibDir)\n{\n    BackendState state;\n    state.cuda_available = isCudaInstalled();\n    state.vulkan_available = isVulkanAvailable();\n\n    bool useCuda = state.cuda_available;\n    bool useVulkan = !useCuda && state.vulkan_available;\n\n    if (overrides.cuda.has_value()) {\n        useCuda = overrides.cuda.value();\n        if (useCuda && !state.cuda_available) {\n            std::cerr << \"Warning: CUDA forced but not detected; falling back.\" << std::endl;\n            useCuda = false;\n        }\n    }\n    if (overrides.vulkan.has_value()) {\n        useVulkan = overrides.vulkan.value();\n        if (useVulkan && !state.vulkan_available) {\n            std::cerr << \"Warning: Vulkan forced but not detected; falling back.\" << std::endl;\n            useVulkan = false;\n        }\n    }\n    if (useCuda && useVulkan) {\n        useVulkan = false; // CUDA has priority\n    }\n\n    if (useCuda) {\n        state.selection = BackendSelection::Cuda;\n        state.ggml_subdir = baseLibDir + \"/ggml/wcuda\";\n        state.backend_tag = \"cuda\";\n        state.llama_device = \"cuda\";\n        std::cout << \"Using CUDA backend.\" << std::endl;\n    } else if (useVulkan) {\n        state.selection = BackendSelection::Vulkan;\n        state.ggml_subdir = baseLibDir + \"/ggml/wvulkan\";\n        state.backend_tag = \"vulkan\";\n        state.llama_device = \"vulkan\";\n        std::cout << \"Using Vulkan backend.\" << std::endl;\n    } else {\n        state.selection = BackendSelection::Cpu;\n        state.ggml_subdir = baseLibDir + \"/ggml/wocuda\";\n        state.backend_tag = \"cpu\";\n        state.llama_device.clear();\n        std::cout << \"Using CPU backend.\" << std::endl;\n    }\n\n    return state;\n}\n\nint main(int argc, char* argv[]) {\n    const std::string exeDir = getExecutableDirectory();\n    const std::string baseLibDir = exeDir + \"/lib\";\n\n    BackendOverrideFlags overrides = parse_backend_overrides(argc, argv);\n    if (!validate_overrides(overrides)) {\n        return EXIT_FAILURE;\n    }\n\n    BackendState backend = decide_backend(overrides, baseLibDir);\n\n    const std::string fullLdPath = backend.ggml_subdir + \":\" + baseLibDir;\n    const bool disableCudaEnv = (backend.selection != BackendSelection::Cuda);\n    launchMainApp(exeDir,\n                  fullLdPath,\n                  argc,\n                  argv,\n                  disableCudaEnv,\n                  QString::fromStdString(backend.backend_tag),\n                  QString::fromStdString(backend.ggml_subdir),\n                  QString::fromStdString(backend.llama_device));\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "app/startapp_windows.cpp",
    "content": "#include <QApplication>\n#include <QCoreApplication>\n#include <QDir>\n#include <QFileInfo>\n#include <QDebug>\n#include <QMessageBox>\n#include <QProcess>\n#include <QProcessEnvironment>\n#include <QLibrary>\n#include <QDesktopServices>\n#include <QUrl>\n#include <QByteArray>\n#include <QObject>\n#include <QStringList>\n\n#include \"UpdaterLaunchOptions.hpp\"\n\n#include <cstdlib>\n\n#include <windows.h>\n#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2\n#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)\n#endif\nusing SetProcessDpiAwarenessContextFn = BOOL (WINAPI *)(HANDLE);\nusing SetProcessDpiAwarenessFn = HRESULT (WINAPI *)(int); // 2 = PROCESS_PER_MONITOR_DPI_AWARE\n\nnamespace {\n\nenum class BackendOverride {\n    None,\n    ForceOn,\n    ForceOff\n};\n\nenum class BackendSelection {\n    Cpu,\n    Cuda,\n    Vulkan\n};\n\nBackendOverride parseBackendOverride(QString value) {\n    value = value.trimmed().toLower();\n    if (value == QLatin1String(\"on\")) {\n        return BackendOverride::ForceOn;\n    }\n    if (value == QLatin1String(\"off\")) {\n        return BackendOverride::ForceOff;\n    }\n    return BackendOverride::None;\n}\n\nbool enableSecureDllSearch()\n{\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602\n    return SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) != 0;\n#else\n    // Only available on Windows 7+ with KB2533623. Try to enable if present.\n    typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunc)(DWORD);\n    if (const HMODULE kernel32 = GetModuleHandleW(L\"kernel32.dll\")) {\n        if (const auto fn = reinterpret_cast<SetDefaultDllDirectoriesFunc>(\n                GetProcAddress(kernel32, \"SetDefaultDllDirectories\"))) {\n            return fn(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) != 0;\n        }\n    }\n    return false;\n#endif\n}\n\nvoid addDllDirectoryChecked(const QString& directory)\n{\n    if (directory.isEmpty()) {\n        return;\n    }\n    const std::wstring wideDir = QDir::toNativeSeparators(directory).toStdWString();\n    if (AddDllDirectory(wideDir.c_str()) == nullptr) {\n        qWarning().noquote()\n            << \"AddDllDirectory failed for\"\n            << QDir::toNativeSeparators(directory)\n            << \"- error\" << GetLastError();\n    } else {\n        qInfo().noquote()\n            << \"Registered DLL directory\"\n            << QDir::toNativeSeparators(directory);\n    }\n}\n\nbool tryLoadLibrary(const QString& name) {\n    QLibrary lib(name);\n    const bool loaded = lib.load();\n    if (loaded) {\n        lib.unload();\n    }\n    return loaded;\n}\n\nQStringList candidateGgmlDirectories(const QString& exeDir, const QString& variant)\n{\n    QStringList candidates;\n    candidates << QDir(exeDir).filePath(QStringLiteral(\"lib/ggml/%1\").arg(variant));\n    candidates << QDir(exeDir).filePath(QStringLiteral(\"ggml/%1\").arg(variant));\n    return candidates;\n}\n\nconst QList<int>& knownCudaRuntimeVersions()\n{\n    static const QList<int> versions = {\n        75, 80, 90, 91, 92,      // CUDA 7.5–9.2\n        100, 101, 102,           // CUDA 10.x\n        110, 111, 112, 113, 114, 115, 116, 117, 118, // CUDA 11.x variants\n        120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130 // CUDA 12.x variants\n    };\n    return versions;\n}\n\nconst QList<int>& requiredCudaRuntimeVersions()\n{\n    static const QList<int> versions = { 120 }; // keep in sync with build script (CUDA 12.x)\n    return versions;\n}\n\nbool isCudaRuntimePresent(const QList<int>& versions, QString *loadedRuntime = nullptr)\n{\n    for (int version : versions) {\n        const QString runtime = QStringLiteral(\"cudart64_%1\").arg(version);\n        if (tryLoadLibrary(runtime)) {\n            if (loadedRuntime) {\n                *loadedRuntime = runtime;\n            }\n            return true;\n        }\n    }\n    return false;\n}\n\nbool isCudaAvailable(QString *loadedRuntime = nullptr) {\n    return isCudaRuntimePresent(knownCudaRuntimeVersions(), loadedRuntime);\n}\n\nbool isRequiredCudaRuntimePresent(QString *loadedRuntime = nullptr) {\n    return isCudaRuntimePresent(requiredCudaRuntimeVersions(), loadedRuntime);\n}\n\nbool loadVulkanLibrary(const QString& path) {\n    const std::wstring native = QDir::toNativeSeparators(path).toStdWString();\n    HMODULE module = LoadLibraryW(native.c_str());\n    if (!module) {\n        return false;\n    }\n    FreeLibrary(module);\n    return true;\n}\n\nbool isVulkanRuntimeAvailable(const QString& exeDir) {\n    if (loadVulkanLibrary(QStringLiteral(\"vulkan-1.dll\"))) {\n        qInfo().noquote() << \"Detected system Vulkan runtime via PATH.\";\n        return true;\n    }\n\n    const QStringList bundledCandidates = {\n        QDir(exeDir).filePath(QStringLiteral(\"lib/precompiled/vulkan/bin/vulkan-1.dll\")),\n    };\n\n    QStringList ggmlCandidates = candidateGgmlDirectories(exeDir, QStringLiteral(\"wvulkan\"));\n    for (QString& root : ggmlCandidates) {\n        root = QDir(root).filePath(QStringLiteral(\"vulkan-1.dll\"));\n    }\n\n    for (const QString& candidate : bundledCandidates + ggmlCandidates) {\n        if (QFileInfo::exists(candidate)) {\n            qInfo().noquote()\n                << \"Detected bundled Vulkan runtime at\"\n                << QDir::toNativeSeparators(candidate);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool isNvidiaDriverAvailable() {\n    static const QStringList driverCandidates = {\n        QStringLiteral(\"nvml\"),\n        QStringLiteral(\"nvcuda\"),\n        QStringLiteral(\"nvapi64\")\n    };\n\n    for (const QString& dll : driverCandidates) {\n        if (tryLoadLibrary(dll)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nvoid appendToProcessPath(const QString& directory) {\n    if (directory.isEmpty()) {\n        return;\n    }\n\n    QByteArray path = qgetenv(\"PATH\");\n    if (!path.isEmpty()) {\n        path.append(';');\n    }\n    path.append(QDir::toNativeSeparators(directory).toUtf8());\n    qputenv(\"PATH\", path);\n    qInfo().noquote() << \"Added to PATH:\" << QDir::toNativeSeparators(directory);\n    qInfo().noquote() << \"Current PATH:\" << QString::fromUtf8(qgetenv(\"PATH\"));\n}\n\nbool promptCudaDownload() {\n    const auto response = QMessageBox::warning(\n        nullptr,\n        QObject::tr(\"CUDA Toolkit Missing\"),\n        QObject::tr(\"A compatible NVIDIA GPU was detected, but the CUDA Toolkit is missing.\\n\\n\"\n                    \"CUDA is required for GPU acceleration in this application.\\n\\n\"\n                    \"Would you like to download and install it now?\"),\n        QMessageBox::Ok | QMessageBox::Cancel,\n        QMessageBox::Ok);\n\n    if (response == QMessageBox::Ok) {\n        QDesktopServices::openUrl(QUrl(QStringLiteral(\"https://developer.nvidia.com/cuda-downloads\")));\n        return true;\n    }\n    return false;\n}\n\nbool launchMainExecutable(const QString& executablePath,\n                          const QStringList& arguments,\n                          bool disableCuda,\n                          const QString& backendTag,\n                          const QString& ggmlDir,\n                          const QString& llamaDevice,\n                          const QProcessEnvironment& extraEnvironment) {\n    QFileInfo exeInfo(executablePath);\n    if (!exeInfo.exists()) {\n        return false;\n    }\n\n    QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();\n    environment.insert(QStringLiteral(\"PATH\"), QString::fromUtf8(qgetenv(\"PATH\")));\n    environment.insert(QStringLiteral(\"GGML_DISABLE_CUDA\"), disableCuda ? QStringLiteral(\"1\") : QStringLiteral(\"0\"));\n    environment.insert(QStringLiteral(\"AI_FILE_SORTER_GPU_BACKEND\"), backendTag);\n    environment.insert(QStringLiteral(\"AI_FILE_SORTER_GGML_DIR\"), ggmlDir);\n    environment.insert(QStringLiteral(\"LLAMA_ARG_DEVICE\"), llamaDevice);\n    for (const QString& key : extraEnvironment.keys()) {\n        environment.insert(key, extraEnvironment.value(key));\n    }\n\n    QProcess process;\n    process.setProcessEnvironment(environment);\n    process.setProgram(executablePath);\n    process.setArguments(arguments);\n    process.setWorkingDirectory(exeInfo.absolutePath());\n\n    return process.startDetached();\n}\n\nQString resolveExecutableName(const QString& baseDir) {\n    const QStringList candidates = {\n        QStringLiteral(\"aifilesorter.exe\"),\n        QStringLiteral(\"AI File Sorter.exe\")\n    };\n\n    for (const QString& candidate : candidates) {\n        const QString fullPath = QDir(baseDir).filePath(candidate);\n        if (QFileInfo::exists(fullPath)) {\n            return fullPath;\n        }\n    }\n\n    return QDir(baseDir).filePath(candidates.front());\n}\n\nstruct BackendOverrides {\n    BackendOverride cuda{BackendOverride::None};\n    BackendOverride vulkan{BackendOverride::None};\n    QStringList observedArgs;\n};\n\nstruct UpdaterLiveTestArgs {\n    bool enabled{false};\n    QString installerUrl;\n    QString installerSha256;\n    QString currentVersion;\n    QString minVersion;\n};\n\nstruct BackendAvailability {\n    bool hasNvidiaDriver{false};\n    bool cudaRuntimeDetected{false};\n    bool runtimeCompatible{false};\n    bool cudaAvailable{false};\n    bool vulkanAvailable{false};\n    bool cudaInitiallyAvailable{false};\n    bool vulkanInitiallyAvailable{false};\n    QString detectedCudaRuntime;\n};\n\nBackendOverrides parse_backend_overrides(int argc, char* argv[])\n{\n    BackendOverrides overrides;\n    for (int i = 1; i < argc; ++i) {\n        const QString arg = QString::fromLocal8Bit(argv[i]);\n        overrides.observedArgs << arg;\n        if (arg.startsWith(QStringLiteral(\"--cuda=\"))) {\n            overrides.cuda = parseBackendOverride(arg.mid(7));\n        } else if (arg.startsWith(QStringLiteral(\"--vulkan=\"))) {\n            overrides.vulkan = parseBackendOverride(arg.mid(9));\n        }\n    }\n    return overrides;\n}\n\nbool consume_flag_value(const QString& argument, const char* prefix, QString& target)\n{\n    const QString prefix_text = QString::fromLatin1(prefix);\n    if (!argument.startsWith(prefix_text)) {\n        return false;\n    }\n    target = argument.mid(prefix_text.size());\n    return true;\n}\n\nUpdaterLiveTestArgs parse_updater_live_test_args(int argc, char* argv[])\n{\n    UpdaterLiveTestArgs args;\n    for (int i = 1; i < argc; ++i) {\n        const QString argument = QString::fromLocal8Bit(argv[i]);\n        if (argument == QLatin1String(UpdaterLaunchOptions::kLiveTestFlag)) {\n            args.enabled = true;\n            continue;\n        }\n        if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestUrlFlag, args.installerUrl)) {\n            continue;\n        }\n        if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestSha256Flag, args.installerSha256)) {\n            continue;\n        }\n        if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestVersionFlag, args.currentVersion)) {\n            continue;\n        }\n        if (consume_flag_value(argument, UpdaterLaunchOptions::kLiveTestMinVersionFlag, args.minVersion)) {\n            continue;\n        }\n    }\n    return args;\n}\n\nQProcessEnvironment build_updater_live_test_environment(const UpdaterLiveTestArgs& args)\n{\n    QProcessEnvironment environment;\n    if (!args.enabled) {\n        return environment;\n    }\n\n    environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestModeEnv), QStringLiteral(\"1\"));\n    if (!args.installerUrl.isEmpty()) {\n        environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestUrlEnv), args.installerUrl);\n    }\n    if (!args.installerSha256.isEmpty()) {\n        environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestSha256Env), args.installerSha256);\n    }\n    if (!args.currentVersion.isEmpty()) {\n        environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestVersionEnv), args.currentVersion);\n    }\n    if (!args.minVersion.isEmpty()) {\n        environment.insert(QString::fromLatin1(UpdaterLaunchOptions::kLiveTestMinVersionEnv), args.minVersion);\n    }\n    return environment;\n}\n\nvoid log_observed_arguments(const QStringList& args)\n{\n    if (args.isEmpty()) {\n        return;\n    }\n    qInfo().noquote() << \"Starter arguments:\" << args.join(QLatin1Char(' '));\n}\n\nbool maybe_prompt_cuda_download(const BackendOverrides& overrides,\n                                const BackendAvailability& availability)\n{\n    if (!availability.hasNvidiaDriver) {\n        return false;\n    }\n\n    const bool runtimeMissing = !availability.cudaRuntimeDetected;\n    const bool runtimeIncompatible = availability.cudaRuntimeDetected && !availability.runtimeCompatible;\n    if (!runtimeMissing && !runtimeIncompatible) {\n        return false;\n    }\n    if (overrides.cuda == BackendOverride::ForceOff) {\n        return false;\n    }\n\n    const bool cudaRequested = overrides.cuda == BackendOverride::ForceOn;\n    const bool vulkanUnavailable = !availability.vulkanAvailable;\n    if (!cudaRequested && !vulkanUnavailable) {\n        return false;\n    }\n\n    return promptCudaDownload();\n}\n\nbool validate_override_conflict(const BackendOverrides& overrides)\n{\n    if (overrides.cuda == BackendOverride::ForceOn &&\n        overrides.vulkan == BackendOverride::ForceOn) {\n        QMessageBox::critical(nullptr,\n                              QObject::tr(\"Launch Error\"),\n                              QObject::tr(\"Cannot enable both CUDA and Vulkan simultaneously.\"));\n        return false;\n    }\n    return true;\n}\n\nBackendAvailability detect_backend_availability(const QString& exeDir,\n                                                bool hasNvidiaDriver,\n                                                bool cudaRuntimeDetected,\n                                                const QString& detectedRuntimeName)\n{\n    BackendAvailability availability;\n    availability.hasNvidiaDriver = hasNvidiaDriver;\n    availability.cudaRuntimeDetected = cudaRuntimeDetected;\n    QString compatibleRuntime;\n    availability.runtimeCompatible = isRequiredCudaRuntimePresent(&compatibleRuntime);\n    availability.detectedCudaRuntime = availability.runtimeCompatible ? compatibleRuntime : detectedRuntimeName;\n    availability.cudaAvailable = availability.runtimeCompatible && hasNvidiaDriver;\n    availability.vulkanAvailable = isVulkanRuntimeAvailable(exeDir);\n    availability.cudaInitiallyAvailable = availability.cudaAvailable;\n    availability.vulkanInitiallyAvailable = availability.vulkanAvailable;\n    if (hasNvidiaDriver && cudaRuntimeDetected && !availability.runtimeCompatible) {\n        const QString requiredRuntime = QStringLiteral(\"cudart64_%1.dll\").arg(requiredCudaRuntimeVersions().constFirst());\n        qWarning().noquote()\n            << \"Detected CUDA runtime\"\n            << (availability.detectedCudaRuntime.isEmpty() ? QStringLiteral(\"<unknown>\") : availability.detectedCudaRuntime)\n            << \"but the bundled GGML build requires\"\n            << requiredRuntime << \".\"\n            << \"Falling back to alternate backend.\";\n    }\n    return availability;\n}\n\nvoid apply_override_flags(const BackendOverrides& overrides,\n                          BackendAvailability& availability)\n{\n    if (overrides.cuda == BackendOverride::ForceOff) {\n        availability.cudaAvailable = false;\n        qInfo().noquote() << \"CUDA manually disabled via --cuda=off.\";\n    }\n    if (overrides.vulkan == BackendOverride::ForceOff) {\n        availability.vulkanAvailable = false;\n        qInfo().noquote() << \"Vulkan manually disabled via --vulkan=off.\";\n    }\n}\n\nBackendSelection resolve_backend_selection(const BackendOverrides& overrides,\n                                           const BackendAvailability& availability)\n{\n    BackendSelection selection = BackendSelection::Cpu;\n    if (overrides.vulkan == BackendOverride::ForceOn) {\n        if (availability.vulkanAvailable) {\n            return BackendSelection::Vulkan;\n        }\n        qWarning().noquote() << \"Vulkan forced but not detected; ignoring request.\";\n    }\n    if (overrides.cuda == BackendOverride::ForceOn) {\n        if (availability.cudaAvailable) {\n            return BackendSelection::Cuda;\n        }\n        qWarning().noquote() << \"CUDA forced but not detected; ignoring request.\";\n    }\n    if (availability.vulkanAvailable) {\n        return BackendSelection::Vulkan;\n    }\n    if (availability.cudaAvailable) {\n        return BackendSelection::Cuda;\n    }\n    return selection;\n}\n\nQString incompatible_runtime_message(const BackendAvailability& availability)\n{\n    if (availability.cudaRuntimeDetected && !availability.runtimeCompatible) {\n        return QStringLiteral(\"CUDA runtime ignored due to incompatibility; using CPU backend.\");\n    }\n    return QStringLiteral(\"No GPU runtime detected; using CPU backend.\");\n}\n\nQString cpu_backend_message(const BackendAvailability& availability)\n{\n    if (!availability.cudaAvailable && !availability.vulkanAvailable) {\n        return incompatible_runtime_message(availability);\n    }\n    if (availability.cudaInitiallyAvailable && !availability.cudaAvailable) {\n        return QStringLiteral(\"CUDA runtime ignored due to override; using CPU backend.\");\n    }\n    if (availability.vulkanInitiallyAvailable && !availability.vulkanAvailable) {\n        return QStringLiteral(\"Vulkan runtime ignored due to override; using CPU backend.\");\n    }\n    return QStringLiteral(\"CUDA and Vulkan explicitly disabled; using CPU backend.\");\n}\n\nvoid enable_per_monitor_dpi_awareness()\n{\n    HMODULE user32 = GetModuleHandleW(L\"user32.dll\");\n    if (user32) {\n        const auto set_ctx = reinterpret_cast<SetProcessDpiAwarenessContextFn>(\n            GetProcAddress(user32, \"SetProcessDpiAwarenessContext\"));\n        if (set_ctx && set_ctx(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {\n            return;\n        }\n    }\n    HMODULE shcore = LoadLibraryW(L\"Shcore.dll\");\n    if (shcore) {\n        const auto set_awareness = reinterpret_cast<SetProcessDpiAwarenessFn>(\n            GetProcAddress(shcore, \"SetProcessDpiAwareness\"));\n        if (set_awareness) {\n            set_awareness(2); // PROCESS_PER_MONITOR_DPI_AWARE\n        }\n        FreeLibrary(shcore);\n    }\n}\n\nvoid log_runtime_availability(const BackendAvailability& availability,\n                              BackendSelection selection)\n{\n    const QString availabilityLine =\n        QStringLiteral(\"Runtime availability: CUDA=%1 Vulkan=%2\")\n            .arg(availability.cudaInitiallyAvailable ? QStringLiteral(\"yes\") : QStringLiteral(\"no\"))\n            .arg(availability.vulkanInitiallyAvailable ? QStringLiteral(\"yes\") : QStringLiteral(\"no\"));\n    qInfo().noquote() << availabilityLine;\n\n    switch (selection) {\n        case BackendSelection::Vulkan:\n            qInfo().noquote() << \"Backend selection: Vulkan (priority order Vulkan → CUDA → CPU).\";\n            break;\n        case BackendSelection::Cuda:\n            qInfo().noquote() << \"Backend selection: CUDA (Vulkan unavailable).\";\n            break;\n        case BackendSelection::Cpu:\n        default:\n            qInfo().noquote() << cpu_backend_message(availability);\n            break;\n    }\n}\n\nQString ggml_variant_for_selection(BackendSelection selection)\n{\n    switch (selection) {\n        case BackendSelection::Cuda:\n            return QStringLiteral(\"wcuda\");\n        case BackendSelection::Vulkan:\n            return QStringLiteral(\"wvulkan\");\n        case BackendSelection::Cpu:\n        default:\n            return QStringLiteral(\"wocuda\");\n    }\n}\n\nQString resolve_ggml_directory(const QString& exeDir,\n                               const QString& variant,\n                               bool showError = true)\n{\n    const QStringList candidates = candidateGgmlDirectories(exeDir, variant);\n    for (const QString& candidate : candidates) {\n        if (QDir(candidate).exists()) {\n            if (candidate != candidates.front()) {\n                qInfo().noquote() << \"Primary GGML directory missing; using fallback\"\n                                  << QDir::toNativeSeparators(candidate);\n            }\n            return candidate;\n        }\n    }\n\n    if (showError) {\n        QMessageBox::critical(\n            nullptr,\n            QObject::tr(\"Missing GGML Runtime\"),\n            QObject::tr(\"Could not locate the backend runtime DLLs.\\nTried:\\n%1\\n%2\")\n                .arg(QDir::toNativeSeparators(candidates.value(0)),\n                     QDir::toNativeSeparators(candidates.value(1))));\n    }\n    return QString();\n}\n\nvoid configure_runtime_paths(const QString& exeDir,\n                             const QString& ggmlPath,\n                             bool secureSearchEnabled,\n                             bool useCuda,\n                             bool useVulkan)\n{\n    appendToProcessPath(ggmlPath);\n    if (secureSearchEnabled) {\n        addDllDirectoryChecked(ggmlPath);\n    }\n\n    QStringList additionalDllRoots;\n    additionalDllRoots << QDir(exeDir).filePath(QStringLiteral(\"lib/precompiled/cpu/bin\"));\n    if (useCuda) {\n        additionalDllRoots << QDir(exeDir).filePath(QStringLiteral(\"lib/precompiled/cuda/bin\"));\n    }\n    if (useVulkan) {\n        additionalDllRoots << QDir(exeDir).filePath(QStringLiteral(\"lib/precompiled/vulkan/bin\"));\n    }\n    additionalDllRoots << QDir(exeDir).filePath(QStringLiteral(\"bin\"));\n    additionalDllRoots << exeDir;\n    for (const QString& dir : additionalDllRoots) {\n        if (!QDir(dir).exists()) {\n            continue;\n        }\n        appendToProcessPath(dir);\n        if (secureSearchEnabled) {\n            addDllDirectoryChecked(dir);\n        }\n    }\n}\n\nQStringList build_forwarded_args(int argc, char* argv[], bool &console_log_flag)\n{\n    QStringList forwardedArgs;\n    console_log_flag = false;\n    for (int i = 1; i < argc; ++i) {\n        const QString arg = QString::fromLocal8Bit(argv[i]);\n        if (arg == QStringLiteral(\"--console-log\")) {\n            console_log_flag = true;\n        }\n        forwardedArgs.append(arg);\n    }\n    forwardedArgs.prepend(QStringLiteral(\"--allow-direct-launch\"));\n    if (console_log_flag && !forwardedArgs.contains(QStringLiteral(\"--console-log\"))) {\n        forwardedArgs.append(QStringLiteral(\"--console-log\"));\n    }\n    return forwardedArgs;\n}\n\nQString backend_tag_for_selection(BackendSelection selection)\n{\n    switch (selection) {\n        case BackendSelection::Cuda: return QStringLiteral(\"cuda\");\n        case BackendSelection::Vulkan: return QStringLiteral(\"vulkan\");\n        case BackendSelection::Cpu:\n        default: return QStringLiteral(\"cpu\");\n    }\n}\n\nQString llama_device_for_selection(BackendSelection selection)\n{\n    switch (selection) {\n        case BackendSelection::Cuda: return QStringLiteral(\"cuda\");\n        case BackendSelection::Vulkan: return QStringLiteral(\"vulkan\");\n        case BackendSelection::Cpu:\n        default: return QString();\n    }\n}\n\nbool launch_main_process(const QString& mainExecutable,\n                         const QStringList& forwardedArgs,\n                         BackendSelection selection,\n                         const QString& ggmlPath,\n                         const UpdaterLiveTestArgs& updaterLiveTest)\n{\n    const bool disableCudaEnv = (selection != BackendSelection::Cuda);\n    const QString backendTag = backend_tag_for_selection(selection);\n    const QString llamaDevice = llama_device_for_selection(selection);\n    if (!launchMainExecutable(mainExecutable,\n                              forwardedArgs,\n                              disableCudaEnv,\n                              backendTag,\n                              ggmlPath,\n                              llamaDevice,\n                              build_updater_live_test_environment(updaterLiveTest))) {\n        QMessageBox::critical(nullptr,\n            QObject::tr(\"Launch Failed\"),\n            QObject::tr(\"Failed to launch the main application executable:\\n%1\").arg(mainExecutable));\n        return false;\n    }\n    return true;\n}\n\n} // namespace\n\nint main(int argc, char* argv[]) {\n    enable_per_monitor_dpi_awareness();\n    QApplication app(argc, argv);\n    app.setQuitOnLastWindowClosed(false);\n\n    const QString exeDir = QCoreApplication::applicationDirPath();\n    QDir::setCurrent(exeDir);\n\n    QString detectedCudaRuntime;\n    const bool cudaRuntimeDetected = isCudaAvailable(&detectedCudaRuntime);\n    const bool hasNvidiaDriver = isNvidiaDriverAvailable();\n\n    const bool secureSearchEnabled = enableSecureDllSearch();\n    if (!secureSearchEnabled) {\n        qWarning() << \"SetDefaultDllDirectories unavailable; relying on PATH order for DLL resolution.\";\n    }\n\n    BackendOverrides overrides = parse_backend_overrides(argc, argv);\n    const UpdaterLiveTestArgs updaterLiveTest = parse_updater_live_test_args(argc, argv);\n    log_observed_arguments(overrides.observedArgs);\n    if (!validate_override_conflict(overrides)) {\n        return EXIT_FAILURE;\n    }\n\n    BackendAvailability availability = detect_backend_availability(exeDir,\n                                                                   hasNvidiaDriver,\n                                                                   cudaRuntimeDetected,\n                                                                   detectedCudaRuntime);\n    apply_override_flags(overrides, availability);\n    if (maybe_prompt_cuda_download(overrides, availability)) {\n        return EXIT_SUCCESS;\n    }\n    BackendSelection selection = resolve_backend_selection(overrides, availability);\n\n    QString ggmlVariant = ggml_variant_for_selection(selection);\n    QString ggmlPath = resolve_ggml_directory(exeDir, ggmlVariant, /*showError=*/false);\n    if (ggmlPath.isEmpty()) {\n        qWarning().noquote()\n            << \"Backend runtime directory missing for selection\" << ggmlVariant\n            << \"- attempting fallback.\";\n\n        BackendSelection fallbackSelection = BackendSelection::Cpu;\n        if (selection == BackendSelection::Vulkan && availability.cudaAvailable) {\n            fallbackSelection = BackendSelection::Cuda;\n        } else if (selection == BackendSelection::Cuda && availability.vulkanAvailable) {\n            fallbackSelection = BackendSelection::Vulkan;\n        }\n\n        if (fallbackSelection != selection) {\n            qInfo().noquote()\n                << \"Falling back to backend\"\n                << backend_tag_for_selection(fallbackSelection)\n                << \"due to missing runtime directory.\";\n            selection = fallbackSelection;\n            ggmlVariant = ggml_variant_for_selection(selection);\n        } else {\n            qInfo().noquote() << \"Falling back to CPU backend.\";\n            selection = BackendSelection::Cpu;\n            ggmlVariant = ggml_variant_for_selection(selection);\n        }\n\n        ggmlPath = resolve_ggml_directory(exeDir, ggmlVariant, /*showError=*/true);\n        if (ggmlPath.isEmpty()) {\n            return EXIT_FAILURE;\n        }\n    }\n\n    log_runtime_availability(availability, selection);\n\n    const bool useCuda = (selection == BackendSelection::Cuda);\n    const bool useVulkan = (selection == BackendSelection::Vulkan);\n    configure_runtime_paths(exeDir, ggmlPath, secureSearchEnabled, useCuda, useVulkan);\n\n    bool console_log_flag = false;\n    QStringList forwardedArgs = build_forwarded_args(argc, argv, console_log_flag);\n    if (console_log_flag) {\n        AttachConsole(ATTACH_PARENT_PROCESS);\n        FILE* f = nullptr;\n        freopen_s(&f, \"CONOUT$\", \"w\", stdout);\n        freopen_s(&f, \"CONOUT$\", \"w\", stderr);\n        freopen_s(&f, \"CONIN$\", \"r\", stdin);\n    }\n\n    const QString mainExecutable = resolveExecutableName(exeDir);\n    if (!launch_main_process(mainExecutable, forwardedArgs, selection, ggmlPath, updaterLiveTest)) {\n        return EXIT_FAILURE;\n    }\n\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "app/vcpkg.json",
    "content": "{\n  \"name\": \"ai-file-sorter\",\n  \"version-string\": \"0.1.0\",\n  \"description\": \"AI File Sorter (Qt6) - Windows build dependencies\",\n  \"builtin-baseline\": \"3b9d086009cc1c2256e9c28ad44a00036fbd9b26\",\n  \"dependencies\": [\n    \"qtbase\",\n    \"qttools\",\n    \"curl\",\n    \"jsoncpp\",\n    \"sqlite3\",\n    \"openssl\",\n    \"zlib\",\n    \"fmt\",\n    \"spdlog\",\n    \"gettext\",\n    \"libmediainfo\"\n  ]\n}\n"
  },
  {
    "path": "external/README-doc-deps.md",
    "content": "# Vendored document-analysis dependencies\n\nThis repo vendors the following dependencies for embedded document extraction:\n\n- libzip (ZIP container access)\n- pugixml (XML parsing)\n- PDFium (PDF text extraction)\n\nUse `app/scripts/vendor_doc_deps.sh` (or `app/scripts/vendor_doc_deps.ps1` on Windows) to download and populate `external/`.\nThe script also stages third-party license files under `external/THIRD_PARTY_LICENSES`.\n\nCommit the populated directories for release builds (Linux/Windows/macOS ARM).\n"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/libzip-LICENSE",
    "content": "Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner\n\nThe authors can be contacted at <info@libzip.org>\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n\n3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\nOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\nGOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\nIN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\nIF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/pdfium-LICENSE",
    "content": "Copyright 2014-2025 Benoit Blanchon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nThis package also includes third-party software. See the licenses/ directory for their respective licenses.\n"
  },
  {
    "path": "external/THIRD_PARTY_LICENSES/pugixml-LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/libzip/.clang-format",
    "content": "BasedOnStyle: LLVM\nIndentWidth: 4\nColumnLimit: 2000\nAlwaysBreakAfterReturnType: TopLevelDefinitions\nKeepEmptyLinesAtTheStartOfBlocks: false\nMaxEmptyLinesToKeep: 2\nBreakBeforeBraces: Custom\nBraceWrapping:\n  BeforeElse: true\nAlignEscapedNewlines: Left\nUseTab: Never\n#PPDirectiveIndentStyle: AfterHash\n"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: Bug Report\nabout: Report where libzip didn't behave like you expected.\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the Bug**\nA clear and concise description of what the bug is.\n\n**Expected Behavior**\nA clear and concise description of what you expected to happen.\n\n**Observed Behavior**\nA clear and concise description of what actually happened.\n\n**To Reproduce**\nShort program or code snippet that reproduces the problem.\n\n**libzip Version**\nVersion of libzip or revision repository used.\n\n**Operating System**\nOperating system and version, used compiler.\n\n**Test Files**\nIf applicable, attach and describe zip archives that trigger the problem.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/compile-error.md",
    "content": "---\nname: Compile Error\nabout: Report when libzip does not compile.\ntitle: ''\nlabels: compile\nassignees: ''\n\n---\n\n**Compiler Error**\nOutput from the compiler, including exact and complete error message, file name and line number.\n\n**libzip Version**\nVersion of libzip or revision repository used.\n\n**Operating System and Compiler**\nThe operating system and compiler used, including version number.\n\nAlso, any flags passed to `cmake`.\n\n**Autodetected Configuration**\nAttach `CmakeCache.txt` from your build directory. This list everything `cmake` detected on your system.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/feature-request.md",
    "content": "---\nname: Feature Request\nabout: Suggest an idea for this project.\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Description**\nA clear and concise description of what you want to achieve, why the current features are insufficient, and why you think it is generally useful.\n\nAlso, have you checked whether the feature is already mentioned in TODO.md? If so, only submit a new issue if you expand on it.\n\n**Solution**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context about the feature request here.\n"
  },
  {
    "path": "external/libzip/.github/ISSUE_TEMPLATE/other.md",
    "content": "---\nname: Other\nabout: If you have a question about libzip , consider using Discussions instead.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": "external/libzip/.github/workflows/CIFuzz.yml",
    "content": "name: CIFuzz\non: [pull_request]\npermissions:\n  contents: read\njobs:\n  Fuzzing:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Build Fuzzers\n      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'libzip'\n        dry-run: false\n    - name: Run Fuzzers\n      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'libzip'\n        fuzz-seconds: 600\n        dry-run: false\n    - name: Upload Crash\n      uses: actions/upload-artifact@v4\n      if: failure()\n      with:\n        name: artifacts\n        path: ./out/artifacts\n"
  },
  {
    "path": "external/libzip/.github/workflows/bsd.yml",
    "content": "name: BSD\non: [push]\npermissions:\n  contents: read\njobs:\n  NetBSD:\n    runs-on: ubuntu-latest\n    steps:\n    - name: checkout\n      uses: actions/checkout@v4\n    - name: NetBSD test\n      uses: vmactions/netbsd-vm@v1\n      with:\n        usesh: true\n        copyback: false\n        prepare: |\n          /usr/sbin/pkg_add cmake zstd py313-pip\n          /usr/pkg/bin/pip-3.13 install nihtest\n          # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path\n          echo \"/usr/pkg/bin\" >> \"$GITHUB_PATH\"\n        run: |\n          cmake -E make_directory ${{runner.workspace}}/build\n          cmake ${{ matrix.cmake_extra }} ${{github.workspace}}\n          cmake --build . --config Release\n          ctest --output-on-failure -V -C Release\n"
  },
  {
    "path": "external/libzip/.github/workflows/build.yml",
    "content": "name: build\non: [push]\npermissions:\n  contents: read\njobs:\n  all:\n    runs-on: ${{ matrix.os }}\n    name: ${{ matrix.os }}${{ matrix.name_extra }}\n    strategy:\n      fail-fast: false\n      matrix:\n        # os: [macos-latest, ubuntu-latest, windows-latest]\n        os: [macos-latest, ubuntu-latest]\n        cmake_extra: [\"\"]\n        name_extra: [\"\"]\n        # include:\n        #   - os: windows-latest\n        #     cmake_extra: \"-T ClangCl\"\n        #     name_extra: \" clang-cl\"\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n      - name: install python and pip\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.11'\n      - name: install dependencies (Linux)\n        if: ${{ runner.os == 'Linux' }}\n        run: |\n          sudo apt-get install libzstd-dev\n      - name: install latest CMake and Ninja for lukka/run-vcpkg (Windows)\n        if: ${{ runner.os == 'Windows' }}\n        uses: lukka/get-cmake@latest\n      - name: install dependencies (Windows)\n        if: ${{ runner.os == 'Windows' }}\n        uses: lukka/run-vcpkg@v11\n        with:\n          vcpkgGitCommitId: 2cf957350da28ad032178a974607f59f961217d9\n      - name: prepare build directory and install nihtest\n        run: |\n          cmake -E make_directory ${{runner.workspace}}/build\n          pip install nihtest\n      - name: configure (Unix)\n        if: ${{ runner.os != 'Windows' }}\n        working-directory: ${{runner.workspace}}/build\n        run: |\n          cmake ${{ matrix.cmake_extra }} ${{github.workspace}}\n      - name: configure (Windows)\n        if: ${{ runner.os == 'Windows' }}\n        working-directory: ${{runner.workspace}}/build\n        run: |\n          cmake ${{ matrix.cmake_extra }} -DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake ${{github.workspace}}\n      - name: build\n        working-directory: ${{runner.workspace}}/build\n        run: |\n          cmake --build . --config Release\n      - name: Archive production artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: regress-directory-${{ matrix.os }}-${{ matrix.name_extra }}\n          path: |\n            ${{runner.workspace}}/build/regress\n      - name: test\n        working-directory: ${{runner.workspace}}/build\n        run: |\n          ctest --output-on-failure -V -C Release\n"
  },
  {
    "path": "external/libzip/.github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [master]\n  schedule:\n    - cron: '0 10 * * 4'\n\npermissions:\n  contents: read\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        # Override automatic language detection by changing the below list\n        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']\n        language: ['cpp']\n        # Learn more...\n        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n      with:\n        # We must fetch at least the immediate parents so that if this is\n        # a pull request then we can checkout the head.\n        fetch-depth: 2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file. \n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v3\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": "external/libzip/.github/workflows/coverity.yml",
    "content": "name: Coverity\n\non:\n  schedule:\n    - cron: '0 3 * * 1'\n      # Mondays at 03:00\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    name: Coverity\n    runs-on: ubuntu-latest\n    environment: coverity\n\n    env:\n      TOKEN: ${{ secrets.COVERITY_TOKEN }}\n      PROJECT: libzip\n      SHORT_PROJECT: libzip\n      EMAIL: wiz@gatalith.at\n      COV_TOOLS: cov-tools\n      COV_RESULTS: cov-int\n\n    steps:\n    - name: Check Secret\n      run: |\n        [ -n \"${{ secrets.COVERITY_TOKEN }}\" ]\n\n    - name: Checkout Code\n      uses: actions/checkout@v4\n\n    - name: Install Dependencies\n      run: |\n        sudo apt-get install libzstd-dev\n\n    - name: Configure\n      run: |\n        cmake -E make_directory ${{runner.workspace}}/build\n        cmake ${{ matrix.cmake_extra }} ${{github.workspace}}\n\n    - name: Download Coverity\n      run: |\n        wget --quiet https://scan.coverity.com/download/linux64 --post-data \"token=$TOKEN&project=$PROJECT\" -O \"$COV_TOOLS.tar.gz\"\n        mkdir \"$COV_TOOLS\"\n        tar xzf \"$COV_TOOLS.tar.gz\" --strip 1 -C \"$COV_TOOLS\"\n        ls -l \"$COV_TOOLS\"\n\n    - name: Build with Coverity\n      run: |\n        export PATH=\"$(pwd)/$COV_TOOLS/bin:$PATH\"\n        cov-build --dir $COV_RESULTS make -j ${{steps.cpu-cores.outputs.count}}\n        # Filter out private info\n        sed -E -i 's/TOKEN=([-_A-Za-z0-9]+)/TOKEN=XXX/g' cov-int/build-log.txt\n\n    - name: Upload build log\n      uses: actions/upload-artifact@v4\n      with:\n        name: build-log\n        path: cov-int/build-log.txt\n        retention-days: 10\n\n    - name: Submit Results\n      run: |\n        tar -czf $SHORT_PROJECT.tgz $COV_RESULTS\n        ls -lh $SHORT_PROJECT.tgz\n        git config --global --add safe.directory \"$GITHUB_WORKSPACE\"\n        GIT_HASH=\"$(git rev-parse --short HEAD)\"\n        echo \"HASH: $GIT_HASH\"\n        GIT_DESC=\"$(git log -n1 --format=\"%s\" $GIT_HASH)\"\n        echo \"DESC: $GIT_DESC\"\n        curl --fail --output curl.log \\\n          --form token=$TOKEN \\\n          --form email=$EMAIL \\\n          --form file=@$SHORT_PROJECT.tgz \\\n          --form version=\"$GIT_HASH\" \\\n          --form description=\"$GIT_DESC\" \\\n          https://scan.coverity.com/builds?project=$PROJECT\n        # If we go over quota, alert the user\n        cat curl.log\n        grep -qv \"quota.*reached\" curl.log || false\n\n"
  },
  {
    "path": "external/libzip/API-CHANGES.md",
    "content": "# libzip API changes\n\nThis file describes changes in the libzip API and how to adapt your\ncode for them.\n\nYou can define `ZIP_DISABLE_DEPRECATED` before including `<zip.h>` to hide\nprototypes for deprecated functions, to find out about functions that\nmight be removed at some point.\n\n## Changed in libzip-1.10.0\n\n### deprecated `zip_source_zip` and `zip_source_zip_create`\n\nThese functions were replaced with `zip_source_zip_file` and `zip_source_zip_file_create`. The implicit handling of the flag `ZIP_FL_COMPRESSED` was removed, the flag can now be specified explicitly.\n\nIf you want to get the compressed data for the whole file, use \n\n```C\nzip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL)\n```\n\n## Changed in libzip-1.0\n\n### new type `zip_error_t`\n\nError information is stored in the newly public type `zip_error_t`. Use\nthis to access information about an error, instead of the deprecated\nfunctions that operated on two ints.\n\ndeprecated functions:\n- `zip_error_get_sys_type()`\n- `zip_error_get()`\n- `zip_error_to_str()`\n- `zip_file_error_get()`\n\nSee their man pages for instructions on how to replace them.\n\nThe most common affected use is `zip_open`. The new recommended usage\nis:\n\n```c\nint err;\nif ((za = zip_open(archive, flags, &err)) == NULL) {\n\tzip_error_t error;\n\tzip_error_init_with_code(&error, err);\n\tfprintf(stderr, \"can't open zip archive '%s': %s\\n\", archive, zip_error_strerror(&error));\n\tzip_error_fini(&error);\n}\n```\n\n### more typedefs\n\nThe following typedefs have been added for better readability:\n\n```c\ntypedef struct zip zip_t;\ntypedef struct zip_file zip_file_t;\ntypedef struct zip_source zip_source_t;\ntypedef struct zip_stat zip_stat_t;\n```\n\nThis means you can use \"`zip_t`\" instead of \"`struct zip`\", etc.\n\n\n### torrentzip support removed\n\ntorrentzip depends on a particular zlib version which is by now quite\nold.\n\n## Changed in libzip-0.11\n\n### new type `zip_flags_t`\n\nThe functions which have flags now use the `zip_flags_t` type for this.\nAll old flags fit; you need only to adapt code if you were saving flags in a\nlocal variable. Use `zip_flags_t` for such a variable.\nThis affects:\n- `zip_fopen()`\n- `zip_fopen_encrypted()`\n- `zip_fopen_index()`\n- `zip_fopen_index_encrypted()`\n- `zip_get_archive_comment()`\n- `zip_get_archive_flag()`\n- `zip_get_num_entries()`\n- `zip_get_name()`\n- `zip_name_locate()`\n- `zip_set_archive_flag()`\n- `zip_source_zip()`\n- `zip_stat()`\n- `zip_stat_index()`\n\n#### `ZIP_FL_*`, `ZIP_AFL_*`, `ZIP_STAT_*` are now unsigned constants\n\nTo match the new `zip_flags_t` type.\n\n#### `zip_add()`, `zip_add_dir()`\n\nThese functions were replaced with `zip_file_add()` and `zip_dir_add()`, respectively,\nto add a flags argument.\n\n#### `zip_rename()`, `zip_replace()`\n\nThese functions were replaced with `zip_file_rename()` and `zip_file_replace()`,\nrespectively, to add a flags argument.\n\n#### `zip_get_file_comment()`\n\nThis function was replaced with `zip_file_get_comment()`; one argument was promoted from\n`int` to `zip_uint32_t`, the other is now a `zip_flags_t`.\n\n#### `zip_set_file_comment()`\n\nThis function was replaced with `zip_file_set_comment()`; an argument was promoted from\n`int` to `zip_uint16_t`, and a `zip_flags_t` argument was added.\n\n### integer type size changes\n\nSome argument and return values were not the right size or sign.\n\n#### `zip_name_locate()`\n\nThe return value was `int`, which can be too small. The function now returns `zip_int64_t`.\n\n\n#### `zip_get_num_entries()`\n\nThe return type is now signed, to allow signaling errors.\n\n#### `zip_set_archive_comment()`\n\nThe last argument changed from `int` to `zip_uint16_t`.\n\n### extra field handling rewritten\n\nThe `zip_get_file_extra()` and `zip_set_file_extra()` functions were removed.\nThey only worked on the whole extra field set.\n\nInstead, you can now set, get, count, and delete each extra field separately,\nusing the functions:\n- `zip_file_extra_field_delete()`\n- `zip_file_extra_field_delete_by_id()`\n- `zip_file_extra_field_get()`\n- `zip_file_extra_field_get_by_id()`\n- `zip_file_extra_fields_count()`\n- `zip_file_extra_fields_count_by_id()`\n- `zip_file_extra_field_set()`\n\nPlease read the corresponding man pages for details.\n\n### new functions\n\n#### `zip_discard()`\n\nThe new `zip_discard()` function closes an archive without committing the\nscheduled changes.\n\n#### `zip_set_file_compression()`\n\nThe new `zip_set_file_compression()` function allows setting compression\nlevels for files.\n\n### argument changes\n\n#### file names\n\nFile names arguments are now allowed to be `NULL` to have an empty file name.\nThis mostly affects `zip_file_add()`, `zip_dir_add()`, and `zip_file_rename()`.\n\nFor `zip_get_name()`, `zip_file_get_comment()`, and `zip_get_archive_comment()`, if\nthe file name or comment is empty, a string of length 0 is returned.\n`NULL` is returned for errors only.\n\nPreviously, `NULL` was returned for empty/unset file names and comments and\nerrors, leaving no way to differentiate between the two.\n"
  },
  {
    "path": "external/libzip/AUTHORS",
    "content": "Dieter Baron <dillo@nih.at>\nThomas Klausner <wiz@gatalith.at>\n"
  },
  {
    "path": "external/libzip/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\n\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\nif (${CMAKE_VERSION} VERSION_LESS \"3.17.0\")\n  list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-compat)\nendif()\n\nproject(libzip\n  VERSION 1.11.4\n  LANGUAGES C)\n\nif(NOT libzip_VERSION_PATCH)\n  set(libzip_VERSION_PATCH 0)\nendif()\n\noption(ENABLE_COMMONCRYPTO \"Enable use of CommonCrypto\" ON)\noption(ENABLE_GNUTLS \"Enable use of GnuTLS\" ON)\noption(ENABLE_MBEDTLS \"Enable use of mbed TLS\" ON)\noption(ENABLE_OPENSSL \"Enable use of OpenSSL\" ON)\noption(ENABLE_WINDOWS_CRYPTO \"Enable use of Windows cryptography libraries\" ON)\n\noption(ENABLE_BZIP2 \"Enable use of BZip2\" ON)\noption(ENABLE_LZMA \"Enable use of LZMA\" ON)\noption(ENABLE_ZSTD \"Enable use of Zstandard\" ON)\n\noption(ENABLE_FDOPEN \"Enable zip_fdopen, which is not allowed in Microsoft CRT secure libraries\" ON)\n\noption(BUILD_TOOLS \"Build tools in the src directory (zipcmp, zipmerge, ziptool)\" ON)\noption(BUILD_REGRESS \"Build regression tests\" ON)\noption(BUILD_OSSFUZZ \"Build fuzzers for ossfuzz\" ON)\noption(BUILD_EXAMPLES \"Build examples\" ON)\noption(BUILD_DOC \"Build documentation\" ON)\n\ninclude(CheckFunctionExists)\ninclude(CheckIncludeFiles)\ninclude(CheckLibraryExists)\ninclude(CheckSymbolExists)\ninclude(CheckTypeSize)\ninclude(CheckCSourceRuns)\ninclude(CheckCSourceCompiles)\ninclude(CheckStructHasMember)\ninclude(TestBigEndian)\ninclude(GNUInstallDirs)\n\nif(ENABLE_COMMONCRYPTO)\n  check_include_files(CommonCrypto/CommonCrypto.h COMMONCRYPTO_FOUND)\nendif()\nif(ENABLE_GNUTLS)\n  find_package(Nettle 3.0)\n  find_package(GnuTLS)\nendif()\nif(ENABLE_MBEDTLS)\n  find_package(MbedTLS 1.0)\nendif()\nif(ENABLE_OPENSSL)\n  find_package(OpenSSL)\nendif()\nif(WIN32)\n  if(ENABLE_WINDOWS_CRYPTO)\n    set(WINDOWS_CRYPTO_FOUND TRUE)\n  endif()\nendif()\n\noption(BUILD_SHARED_LIBS \"Build shared libraries\" ON)\noption(LIBZIP_DO_INSTALL \"Install libzip and the related files\" ON)\n\noption(SHARED_LIB_VERSIONNING \"Add SO version in .so build\" ON)\n\nfind_program(MDOCTOOL NAMES mandoc groff)\nif (MDOCTOOL)\n  set(DOCUMENTATION_FORMAT \"mdoc\" CACHE STRING \"Documentation format\")\nelse()\n  find_program(MANTOOL NAMES nroff)\n  if (MANTOOL)\n    set(DOCUMENTATION_FORMAT \"man\" CACHE STRING \"Documentation format\")\n  else()\n    set(DOCUMENTATION_FORMAT \"html\" CACHE STRING \"Documentation format\")\n  endif()\nendif()\n\ninclude(Dist)\nDist(${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION})\n\n#ADD_CUSTOM_TARGET(uninstall\n#  COMMAND cat ${PROJECT_BINARY_DIR}/install_manifest.txt | xargs rm\n#  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}\n#  )\n\nif(BUILD_SHARED_LIBS)\n  set(HAVE_SHARED TRUE)\nelse()\n  set(ZIP_STATIC TRUE)\nendif()\n\n# Checks\n\n# Request ISO C secure library functions (memcpy_s &c)\nlist(APPEND CMAKE_REQUIRED_DEFINITIONS -D__STDC_WANT_LIB_EXT1__=1)\n\ncheck_function_exists(_close HAVE__CLOSE)\ncheck_function_exists(_dup HAVE__DUP)\ncheck_function_exists(_fdopen HAVE__FDOPEN)\ncheck_function_exists(_fileno HAVE__FILENO)\ncheck_function_exists(_fseeki64 HAVE__FSEEKI64)\ncheck_function_exists(_fstat64 HAVE__FSTAT64)\ncheck_function_exists(_setmode HAVE__SETMODE)\ncheck_function_exists(_stat64 HAVE__STAT64)\ncheck_symbol_exists(_snprintf stdio.h HAVE__SNPRINTF)\ncheck_symbol_exists(_snprintf_s stdio.h HAVE__SNPRINTF_S)\ncheck_symbol_exists(_snwprintf_s stdio.h HAVE__SNWPRINTF_S)\ncheck_function_exists(_strdup HAVE__STRDUP)\ncheck_symbol_exists(_stricmp string.h HAVE__STRICMP)\ncheck_function_exists(_strtoi64 HAVE__STRTOI64)\ncheck_function_exists(_strtoui64 HAVE__STRTOUI64)\ncheck_function_exists(_unlink HAVE__UNLINK)\ncheck_function_exists(arc4random HAVE_ARC4RANDOM)\ncheck_function_exists(clonefile HAVE_CLONEFILE)\ncheck_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)\ncheck_function_exists(explicit_memset HAVE_EXPLICIT_MEMSET)\ncheck_function_exists(fchmod HAVE_FCHMOD)\ncheck_function_exists(fileno HAVE_FILENO)\ncheck_function_exists(fseeko HAVE_FSEEKO)\ncheck_function_exists(ftello HAVE_FTELLO)\ncheck_function_exists(getprogname HAVE_GETPROGNAME)\ncheck_function_exists(GetSecurityInfo HAVE_GETSECURITYINFO)\ncheck_symbol_exists(localtime_r time.h HAVE_LOCALTIME_R)\ncheck_symbol_exists(localtime_s time.h HAVE_LOCALTIME_S)\ncheck_function_exists(memcpy_s HAVE_MEMCPY_S)\ncheck_function_exists(random HAVE_RANDOM)\ncheck_function_exists(setmode HAVE_SETMODE)\ncheck_symbol_exists(snprintf stdio.h HAVE_SNPRINTF)\ncheck_symbol_exists(snprintf_s stdio.h HAVE_SNPRINTF_S)\ncheck_symbol_exists(strcasecmp strings.h HAVE_STRCASECMP)\ncheck_function_exists(strdup HAVE_STRDUP)\ncheck_function_exists(strerror_s HAVE_STRERROR_S)\ncheck_function_exists(strerrorlen_s HAVE_STRERRORLEN_S)\ncheck_function_exists(stricmp HAVE_STRICMP)\ncheck_function_exists(strncpy_s HAVE_STRNCPY_S)\ncheck_function_exists(strtoll HAVE_STRTOLL)\ncheck_function_exists(strtoull HAVE_STRTOULL)\n\ncheck_include_files(\"sys/types.h;sys/stat.h;fts.h\" HAVE_FTS_H)\n# fts functions may be in external library\nif(HAVE_FTS_H)\n  check_function_exists(fts_open HAVE_FTS_OPEN)\n  if(NOT HAVE_FTS_OPEN)\n    check_library_exists(fts fts_open \"\" HAVE_LIB_FTS)\n  else(NOT HAVE_FTS_OPEN)\n    set(HAVE_LIB_FTS \"\" CACHE INTERNAL \"\")\n  endif(NOT HAVE_FTS_OPEN)\nelse(HAVE_FTS_H)\n  set(HAVE_LIB_FTS \"\" CACHE INTERNAL \"\")\nendif(HAVE_FTS_H)\n\nif(HAVE_LIB_FTS)\n  set(FTS_LIB fts CACHE INTERNAL \"\")\nelse()\n  set(FTS_LIB \"\" CACHE INTERNAL \"\")\nendif()\n\ncheck_include_files(stdbool.h HAVE_STDBOOL_H)\ncheck_include_files(strings.h HAVE_STRINGS_H)\ncheck_include_files(unistd.h HAVE_UNISTD_H)\n\ncheck_include_files(inttypes.h HAVE_INTTYPES_H_LIBZIP)\ncheck_include_files(stdint.h HAVE_STDINT_H_LIBZIP)\ncheck_include_files(sys/types.h HAVE_SYS_TYPES_H_LIBZIP)\n\n# TODO: fix test\n# this test does not find __progname even when it exists\n#check_symbol_exists(__progname stdlib.h HAVE___PROGNAME)\n\ncheck_type_size(__int8 __INT8_LIBZIP)\ncheck_type_size(int8_t INT8_T_LIBZIP)\ncheck_type_size(uint8_t UINT8_T_LIBZIP)\ncheck_type_size(__int16 __INT16_LIBZIP)\ncheck_type_size(int16_t INT16_T_LIBZIP)\ncheck_type_size(uint16_t UINT16_T_LIBZIP)\ncheck_type_size(__int32 __INT32_LIBZIP)\ncheck_type_size(int32_t INT32_T_LIBZIP)\ncheck_type_size(uint32_t UINT32_T_LIBZIP)\ncheck_type_size(__int64 __INT64_LIBZIP)\ncheck_type_size(int64_t INT64_T_LIBZIP)\ncheck_type_size(uint64_t UINT64_T_LIBZIP)\ncheck_type_size(\"short\" SHORT_LIBZIP)\ncheck_type_size(\"int\" INT_LIBZIP)\ncheck_type_size(\"long\" LONG_LIBZIP)\ncheck_type_size(\"long long\" LONG_LONG_LIBZIP)\ncheck_type_size(\"off_t\" SIZEOF_OFF_T)\ncheck_type_size(\"size_t\" SIZEOF_SIZE_T)\n\ncheck_c_source_compiles(\"#include <sys/ioctl.h>\n#include <linux/fs.h>\nint main(int argc, char *argv[]) { unsigned long x = FICLONERANGE; }\" HAVE_FICLONERANGE)\n\ntest_big_endian(WORDS_BIGENDIAN)\n\nfind_package(ZLIB 1.1.2 REQUIRED)\n# so developers on systems where zlib is named differently (Windows, sometimes)\n# can override the name used in the pkg-config file\nif (NOT ZLIB_LINK_LIBRARY_NAME)\n  set(ZLIB_LINK_LIBRARY_NAME \"z\")\n\n  # Get the correct name in common cases\n  list(LENGTH ZLIB_LIBRARIES N_ZLIB_LIBRARIES)\n  if(N_ZLIB_LIBRARIES EQUAL 1)\n    set(ZLIB_FILENAME ${ZLIB_LIBRARIES})\n  elseif(N_ZLIB_LIBRARIES EQUAL 4)\n    # ZLIB_LIBRARIES might have the target_link_library() format like\n    # \"optimized;path/to/zlib.lib;debug;path/to/zlibd.lib\". Use the 'optimized'\n    # case unless we know we are in a Debug build.\n    if(CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n      list(FIND ZLIB_LIBRARIES \"debug\" ZLIB_LIBRARIES_INDEX_OF_CONFIG)\n    else()\n      list(FIND ZLIB_LIBRARIES \"optimized\" ZLIB_LIBRARIES_INDEX_OF_CONFIG)\n    endif()\n    if(ZLIB_LIBRARIES_INDEX_OF_CONFIG GREATER_EQUAL 0)\n      math(EXPR ZLIB_FILENAME_INDEX \"${ZLIB_LIBRARIES_INDEX_OF_CONFIG}+1\")\n      list(GET ZLIB_LIBRARIES ${ZLIB_FILENAME_INDEX} ZLIB_FILENAME)\n    endif()\n  endif()\n  if(ZLIB_FILENAME)\n    get_filename_component(ZLIB_FILENAME ${ZLIB_FILENAME} NAME_WE)\n    string(REGEX REPLACE \"^lib\" \"\" ZLIB_LINK_LIBRARY_NAME ${ZLIB_FILENAME})\n  endif()\nendif(NOT ZLIB_LINK_LIBRARY_NAME)\n\nif(ENABLE_BZIP2)\n  find_package(BZip2)\n  if(BZIP2_FOUND)\n    set(HAVE_LIBBZ2 1)\n  else()\n    message(WARNING \"-- bzip2 library not found; bzip2 support disabled\")\n  endif(BZIP2_FOUND)\nendif(ENABLE_BZIP2)\n\nif(ENABLE_LZMA)\n  find_package(LibLZMA 5.2)\n  if(LIBLZMA_FOUND)\n    set(HAVE_LIBLZMA 1)\n  else()\n    message(WARNING \"-- lzma library not found; lzma/xz support disabled\")\n  endif(LIBLZMA_FOUND)\nendif(ENABLE_LZMA)\n\nif(ENABLE_ZSTD)\n  find_package(zstd 1.4.0)\n  if(zstd_FOUND)\n    set(HAVE_LIBZSTD 1)\n    if(TARGET zstd::libzstd_shared AND BUILD_SHARED_LIBS)\n      set(zstd_TARGET zstd::libzstd_shared)\n    else()\n      set(zstd_TARGET zstd::libzstd_static)\n    endif()\n  else()\n    message(WARNING \"-- zstd library not found; zstandard support disabled\")\n  endif(zstd_FOUND)\nendif(ENABLE_ZSTD)\n\nif (COMMONCRYPTO_FOUND)\n  set(HAVE_CRYPTO 1)\n  set(HAVE_COMMONCRYPTO 1)\nelseif (WINDOWS_CRYPTO_FOUND)\n  set(HAVE_CRYPTO 1)\n  set(HAVE_WINDOWS_CRYPTO 1)\nelseif (OPENSSL_FOUND)\n  set(HAVE_CRYPTO 1)\n  set(HAVE_OPENSSL 1)\nelseif (GNUTLS_FOUND AND NETTLE_FOUND)\n  set(HAVE_CRYPTO 1)\n  set(HAVE_GNUTLS 1)\nelseif (MBEDTLS_FOUND)\n  set(HAVE_CRYPTO 1)\n  set(HAVE_MBEDTLS 1)\nendif()\n\nif ((ENABLE_COMMONCRYPTO OR ENABLE_GNUTLS OR ENABLE_MBEDTLS OR ENABLE_OPENSSL OR ENABLE_WINDOWS_CRYPTO) AND NOT HAVE_CRYPTO)\n  message(WARNING \"-- neither Common Crypto, GnuTLS, mbed TLS, OpenSSL, nor Windows Cryptography found; AES support disabled\")\nendif()\n\nif(MSVC)\n  add_compile_definitions(_CRT_SECURE_NO_WARNINGS)\n  add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE)\nendif(MSVC)\n\nif(WIN32)\n  if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)\n    add_compile_definitions(MS_UWP)\n  endif(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)\nendif(WIN32)\n\n# rpath handling: use rpath in installed binaries\nif(NOT CMAKE_SYSTEM_NAME MATCHES Linux)\n  set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})\n  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)\nendif()\n\n# for code completion frameworks\nset(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\n# Testing\nENABLE_TESTING()\n\n# Targets\nADD_SUBDIRECTORY(lib)\n\nif(BUILD_DOC)\n  ADD_SUBDIRECTORY(man)\nendif()\n\nif(BUILD_TOOLS)\n  ADD_SUBDIRECTORY(src)\nelse(BUILD_TOOLS)\n  if(BUILD_REGRESS)\n    message(WARNING \"-- tools build has been disabled, but they are needed for regression tests; regression testing disabled\")\n    set(BUILD_REGRESS OFF)\n  endif(BUILD_REGRESS)\nendif()\n\nfind_program(NIHTEST nihtest)\n\nif(BUILD_REGRESS AND NOT NIHTEST)\n  message(WARNING \"-- nihtest not found, regression testing disabled\")\n  set(BUILD_REGRESS OFF)\nendif()\n\nif(BUILD_REGRESS)\n  add_subdirectory(regress)\nendif()\n\nif(BUILD_OSSFUZZ)\n  add_subdirectory(ossfuzz)\nendif()\n\nif(BUILD_EXAMPLES)\n  add_subdirectory(examples)\nendif()\n\n\n# pkgconfig file\nfile(RELATIVE_PATH pc_relative_bindir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_BINDIR})\nset(bindir \"\\${prefix}/${pc_relative_bindir}\")\nfile(RELATIVE_PATH pc_relative_libdir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_LIBDIR})\nset(libdir \"\\${prefix}/${pc_relative_libdir}\")\nfile(RELATIVE_PATH pc_relative_includedir ${CMAKE_INSTALL_PREFIX} ${CMAKE_INSTALL_FULL_INCLUDEDIR})\nset(includedir \"\\${prefix}/${pc_relative_includedir}\")\nif(CMAKE_SYSTEM_NAME MATCHES BSD)\n  set(PKG_CONFIG_RPATH \"-Wl,-R\\${libdir}\")\nendif(CMAKE_SYSTEM_NAME MATCHES BSD)\nget_target_property(LIBS_PRIVATE zip LINK_LIBRARIES)\nforeach(LIB ${LIBS_PRIVATE})\n  if(LIB MATCHES \"^/\")\n    get_filename_component(LIB ${LIB} NAME_WE)\n    string(REGEX REPLACE \"^lib\" \"\" LIB ${LIB})\n  endif()\n  set(LIBS \"${LIBS} -l${LIB}\")\nendforeach()\nSTRING(CONCAT zlib_link_name \"-l\" ${ZLIB_LINK_LIBRARY_NAME})\nstring(REGEX REPLACE \"-lBZip2::BZip2\" \"-lbz2\" LIBS ${LIBS})\nstring(REGEX REPLACE \"-lLibLZMA::LibLZMA\" \"-llzma\" LIBS ${LIBS})\nif(zstd_TARGET)\n  string(REGEX REPLACE \"-l${zstd_TARGET}\" \"-lzstd\" LIBS ${LIBS})\nendif()\nstring(REGEX REPLACE \"-lOpenSSL::Crypto\" \"-lssl -lcrypto\" LIBS ${LIBS})\nstring(REGEX REPLACE \"-lZLIB::ZLIB\" ${zlib_link_name} LIBS ${LIBS})\nstring(REGEX REPLACE \"-lGnuTLS::GnuTLS\" \"-lgnutls\" LIBS ${LIBS})\nstring(REGEX REPLACE \"-lNettle::Nettle\" \"-lnettle\" LIBS ${LIBS})\nconfigure_file(libzip.pc.in libzip.pc @ONLY)\nif(LIBZIP_DO_INSTALL)\n  install(FILES ${PROJECT_BINARY_DIR}/libzip.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)\nendif()\n\n# fixed size integral types\n\nif(HAVE_INTTYPES_H_LIBZIP)\n  set(LIBZIP_TYPES_INCLUDE \"#if !defined(__STDC_FORMAT_MACROS)\n#define __STDC_FORMAT_MACROS 1\n#endif\n#include <inttypes.h>\")\nelseif(HAVE_STDINT_H_LIBZIP)\n  set(LIBZIP_TYPES_INCLUDE \"#include <stdint.h>\")\nelseif(HAVE_SYS_TYPES_H_LIBZIP)\n  set(LIBZIP_TYPES_INCLUDE \"#include <sys/types.h>\")\nendif()\n\nif(HAVE_INT8_T_LIBZIP)\n  set(ZIP_INT8_T int8_t)\nelseif(HAVE___INT8_LIBZIP)\n  set(ZIP_INT8_T __int8)\nelse()\n  set(ZIP_INT8_T \"signed char\")\nendif()\n\nif(HAVE_UINT8_T_LIBZIP)\n  set(ZIP_UINT8_T uint8_t)\nelseif(HAVE___INT8_LIBZIP)\n  set(ZIP_UINT8_T \"unsigned __int8\")\nelse()\n  set(ZIP_UINT8_T \"unsigned char\")\nendif()\n\nif(HAVE_INT16_T_LIBZIP)\n  set(ZIP_INT16_T int16_t)\nelseif(HAVE___INT16_LIBZIP)\n  set(INT16_T_LIBZIP __int16)\nelseif(SHORT_LIBZIP EQUAL 2)\n  set(INT16_T_LIBZIP short)\nendif()\n\nif(HAVE_UINT16_T_LIBZIP)\n  set(ZIP_UINT16_T uint16_t)\nelseif(HAVE___INT16_LIBZIP)\n  set(UINT16_T_LIBZIP \"unsigned __int16\")\nelseif(SHORT_LIBZIP EQUAL 2)\n  set(UINT16_T_LIBZIP \"unsigned short\")\nendif()\n\nif(HAVE_INT32_T_LIBZIP)\n  set(ZIP_INT32_T int32_t)\nelseif(HAVE___INT32_LIBZIP)\n  set(ZIP_INT32_T __int32)\nelseif(INT_LIBZIP EQUAL 4)\n  set(ZIP_INT32_T int)\nelseif(LONG_LIBZIP EQUAL 4)\n  set(ZIP_INT32_T long)\nendif()\n\nif(HAVE_UINT32_T_LIBZIP)\n  set(ZIP_UINT32_T uint32_t)\nelseif(HAVE___INT32_LIBZIP)\n  set(ZIP_UINT32_T \"unsigned __int32\")\nelseif(INT_LIBZIP EQUAL 4)\n  set(ZIP_UINT32_T \"unsigned int\")\nelseif(LONG_LIBZIP EQUAL 4)\n  set(ZIP_UINT32_T \"unsigned long\")\nendif()\n\nif(HAVE_INT64_T_LIBZIP)\n  set(ZIP_INT64_T int64_t)\nelseif(HAVE___INT64_LIBZIP)\n  set(ZIP_INT64_T __int64)\nelseif(LONG_LIBZIP EQUAL 8)\n  set(ZIP_INT64_T long)\nelseif(LONG_LONG_LIBZIP EQUAL 8)\n  set(ZIP_INT64_T \"long long\")\nendif()\n\nif(HAVE_UINT64_T_LIBZIP)\n  set(ZIP_UINT64_T uint64_t)\nelseif(HAVE___INT64_LIBZIP)\n  set(ZIP_UINT64_T \"unsigned __int64\")\nelseif(LONG_LIBZIP EQUAL 8)\n  set(ZIP_UINT64_T \"unsigned long\")\nelseif(LONG_LONG_LIBZIP EQUAL 8)\n  set(ZIP_UINT64_T \"unsigned long long\")\nendif()\n\n# write out config file\nconfigure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h)\nconfigure_file(${CMAKE_CURRENT_SOURCE_DIR}/zipconf.h.in ${PROJECT_BINARY_DIR}/zipconf.h)\n\n# for tests\n\nset(srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)\nset(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)\nset(top_builddir ${PROJECT_BINARY_DIR}) # used to find config.h\n\n# create package config file\ninclude(CMakePackageConfigHelpers)\nwrite_basic_package_version_file(\"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake\"\n  COMPATIBILITY AnyNewerVersion)\n\nif(LIBZIP_DO_INSTALL)\n  configure_package_config_file(\"${PROJECT_NAME}-config.cmake.in\" \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake\"\n    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libzip)\n\n  # Install Find* modules, they are required by libzip-config.cmake to resolve dependencies\n  install(FILES\n    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindNettle.cmake\n    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findzstd.cmake\n    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindMbedTLS.cmake\n    DESTINATION\n    ${CMAKE_INSTALL_LIBDIR}/cmake/libzip/modules\n  )\n\n  # Add targets to the build-tree export set\n  export(TARGETS zip\n    FILE \"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake\")\n\n  # installation\n  install(FILES ${PROJECT_BINARY_DIR}/zipconf.h DESTINATION include)\n  install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\n    )\n  install(EXPORT ${PROJECT_NAME}-targets NAMESPACE libzip:: FILE ${PROJECT_NAME}-targets.cmake\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\n    )\n  if(BUILD_TOOLS)\n    install(EXPORT ${PROJECT_NAME}-bin-targets NAMESPACE libzip:: FILE ${PROJECT_NAME}-bin-targets.cmake\n          DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}\n    )\n  endif()\nendif()\n"
  },
  {
    "path": "external/libzip/INSTALL.md",
    "content": "libzip uses [cmake](https://cmake.org) to build.\n\nYou'll need [zlib](http://www.zlib.net/) (at least version 1.1.2). It\ncomes with most operating systems.\n\nFor supporting bzip2-compressed zip archives, you need\n[bzip2](http://bzip.org/).\n\nFor supporting lzma- and xz-compressed zip archives, you need\n[liblzma](https://tukaani.org/xz/) which is part of xz, at least version 5.2.\n\nFor supporting zstd-compressed zip archives, you need\n[zstd](https://github.com/facebook/zstd/).\n\nFor AES (encryption) support, you need one of these cryptographic libraries,\nlisted in order of preference:\n\n- Apple's CommonCrypto (available on macOS and iOS)\n- Microsoft Windows Cryptography Framework\n- [OpenSSL](https://www.openssl.org/) >= 1.0.\n- [GnuTLS](https://www.gnutls.org/) and [Nettle](https://www.lysator.liu.se/~nisse/nettle/) (at least nettle 3.0)\n- [mbed TLS](https://tls.mbed.org/)\n\nIf you don't want a library even if it is installed, you can\npass `-DENABLE_<LIBRARY>=OFF` to cmake, where `<LIBRARY>` is one of\n`COMMONCRYPTO`, `GNUTLS`, `MBEDTLS`, or `OPENSSL`.\n\nFor running the tests, you need to have\n[Python](https://www.python.org/) and\n[nihtest](https://pypi.org/project/nihtest/) installed.\n\nThe basic usage is\n```sh\nmkdir build\ncd build\ncmake ..\nmake\nmake test\nmake install\n```\n\nSome useful parameters you can pass to `cmake` with `-Dparameter=value`:\n\n- `BUILD_SHARED_LIBS`: set to `ON` or `OFF` to enable/disable building\n  of shared libraries, defaults to `ON`\n- `CMAKE_INSTALL_PREFIX`: for setting the installation path\n- `DOCUMENTATION_FORMAT`: choose one of `man`, `mdoc`, and `html` for\n  the installed documentation (default: decided by cmake depending on\n  available tools)\n- `LIBZIP_DO_INSTALL`: If you include libzip as a subproject, link it\n  statically and do not want to let it install its files, set this\n  variable to `OFF`. Defaults to `ON`.\n\nIf you want to compile with custom `CFLAGS`, set them in the environment\nbefore running `cmake`:\n```sh\nCFLAGS=-DMY_CUSTOM_FLAG cmake ..\n```\n\nIf you are compiling on a system with a small stack size, add\n`-DZIP_ALLOCATE_BUFFER` to `CFLAGS`.\n\nIf you are building on a 32-bit Linux system it might be necessary\nto define `_FILE_OFFSET_BITS` to `64`. Your distro will need to provide\na `fts.h` file that is new enough to support this, or the build\nwill break in `zipcmp`.\n\nYou can get verbose build output with by passing `VERBOSE=1` to\n`make`.\n\nYou can also check the [cmake FAQ](https://gitlab.kitware.com/cmake/community/-/wikis/FAQ).\n"
  },
  {
    "path": "external/libzip/LICENSE",
    "content": "Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner\n\nThe authors can be contacted at <info@libzip.org>\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n\n3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\nOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\nGOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\nIN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\nIF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "external/libzip/NEWS.md",
    "content": "# 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 [2025-01-20]\n\n* Report read error for corrupted encrypted file data.\n* Avoid unnecessary seeks when writing archive.\n* Don't hardcode `_Nullable` support in `zip.h` to allow it to be used with different compilers.\n* Improve check for GetSecurityInformation availability on Windows.\n\n# 1.11.2 [2024-10-31]\n\n* Fix performance regression in `zip_stat` introduced in 1.11.\n\n# 1.11.1 [2024-09-19]\n\n* Fix zipconf.h for version number with missing third component.\n\n# 1.11 [2024-09-19]\n\n* Stop searching after finding acceptable central directory, even if it contains inconsistencies.\n* Only write Zip64 EOCD if fields don't fit in normal EOCD. Previously libzip also wrote it when any directory entry required Zip64.\n* Allow bytes from 0x00-0x1F as UTF-8.\n* Add new error code `ZIP_ER_TRUNCATED_ZIP` for files that start with a valid local header signature.\n* `zipcmp`: add `-T` option for comparing timestamps.\n* `zip_file_replace` now removes the target's extra field information.\n\n# 1.10.1 [2023-08-23]\n\n* Add `ZIP_LENGTH_TO_END` and `ZIP_LENGTH_UNCHECKED`. Unless `ZIP_LENGTH_UNCHECKED` is used as `length`, it is an error for a file to shrink between the time when the source is created and when its data is read.\n* Fix test on Windows.\n\n# 1.10.0 [2023-06-23]\n\n* Make support for layered sources public.\n* Add `zip_source_zip_file` and `zip_source_zip_file_create`, deprecate `zip_source_zip` and `zip_source_zip_create`.\n* Allow reading changed file data.\n* Fix handling of files of size 4294967295.\n* `zipmerge`: copy extra fields.\n* `zipmerge`: add option to keep files uncompressed.\n* Switch test framework to use nihtest instead of Perl.\n* Fix reading/writing compressed data with buffers > 4GiB.\n* Restore support for torrentzip.\n* Add warnings when using deprecated functions.\n* Allow keeping files for empty archives.\n* Support mbedTLS>=3.3.0.\n* Support OpenSSL 3.\n* Use ISO C secure library functions, if available.\n\n\n# 1.9.2 [2022-06-28]\n\n* Fix version number in header file.\n\n\n# 1.9.1 [2022-06-28]\n\n* Fix `zip_file_is_seekable()`.\n\n\n# 1.9.0 [2022-06-13]\n\n* Add `zip_file_is_seekable()`.\n* Improve compatibility with WinAES.\n* Fix encoding handling in `zip_name_locate()`.\n* Add option to `zipcmp` to output summary of changes.\n* Various bug fixes and documentation improvements.\n\n\n# 1.8.0 [2021-06-18]\n\n* Add support for zstd (Zstandard) compression.\n* Add support for lzma (ID 14) compression.\n* Add `zip_source_window_create()`.\n* Add `zip_source_zip_create()` variant to `zip_source_zip()`.\n* Allow method specific `comp_flags` in `zip_set_file_compression()`.\n* Allow `zip_source_tell()` on sources that don't support seeking and `zip_ftell()` on compressed data.\n* Provide more details for consistency check errors.\n* Improve output of `zipcmp`.\n* In `zipcmp`, don’t ignore empty directories when comparing directory listing.\n* Treat empty string as no password given in `zip_file_set_encryption()`, `zip_fopen_encrypted()`, and `zip_set_default_password()`.\n\n\n# 1.7.3 [2020-07-15]\n\n* Support cmake < 3.17 again.\n* Fix pkgconfig file (regression in 1.7.2).\n\n\n# 1.7.2 [2020-07-11]\n\n* Fixes for the CMake `find_project()` files.\n* libzip moved to the CMake `libzip::` `NAMESPACE`.\n* CMake usage best practice cleanups.\n\n\n# 1.7.1 [2020-06-13]\n\n* Restore `LIBZIP_VERSION_{MAJOR,MINOR,MICRO}` symbols.\n* Fixes warnings reported by PVS-Studio.\n* Add `LIBZIP_DO_INSTALL` build setting to make it easier to use\n  libzip as subproject.\n\n\n# 1.7.0 [2020-06-05]\n\n* Add support for encrypting using traditional PKWare encryption.\n* Add `zip_compression_method_supported()`.\n* Add `zip_encryption_method_supported()`.\n* Add the `ZIP_SOURCE_GET_FILE_ATTRIBUTES` source command.\n* Refactor stdio file backend.\n* Add CMake find_project() support.\n\n\n# 1.6.1 [2020-02-03]\n\n* Bugfix for double-free in `zipcmp(1)` during cleanup.\n\n\n# 1.6.0 [2020-01-24]\n\n* Avoid using `umask()` since it's not thread-safe.\n* Set close-on-exec flag when opening files.\n* Do not accept empty files as valid zip archives any longer.\n* Add support for XZ compressed files (using liblzma).\n* Add support for cancelling while closing zip archives.\n* Add support for setting the time in the on-disk format.\n\n\n# 1.5.2 [2019-03-12]\n\n* Fix bug in AES encryption affecting certain file sizes\n* Keep file permissions when modifying zip archives\n* Support systems with small stack size.\n* Support mbed TLS as crypto backend.\n* Add nullability annotations.\n\n\n# 1.5.1 [2018-04-11]\n\n* Choose format of installed documentation based on available tools.\n* Fix visibility of symbols.\n* Fix zipcmp directory support.\n* Don't set RPATH on Linux.\n* Use Libs.private for link dependencies in pkg-config file.\n* Fix build with LibreSSL.\n* Various bugfixes.\n\n\n# 1.5.0 [2018-03-11]\n\n* Use standard cryptographic library instead of custom AES implementation.\n  This also simplifies the license.\n* Use `clang-format` to format the source code.\n* More Windows improvements.\n\n\n# 1.4.0 [2017-12-29]\n\n* Improve build with cmake\n* Retire autoconf/automake build system\n* Add `zip_source_buffer_fragment()`.\n* Add support to clone unchanged beginning of archive (instead of rewriting it).\n  Supported for buffer sources and on Apple File System.\n* Add support for Microsoft Universal Windows Platform.\n\n\n# 1.3.2 [2017-11-20]\n\n* Fix bug introduced in last: zip_t was erroneously freed if zip_close() failed.\n\n\n# 1.3.1 [2017-11-19]\n\n* Install zipconf.h into ${PREFIX}/include\n* Add zip_libzip_version()\n* Fix AES tests on Linux\n\n\n# 1.3.0 [2017-09-02]\n\n* Support bzip2 compressed zip archives\n* Improve file progress callback code\n* Fix zip_fdopen()\n* CVE-2017-12858: Fix double free()\n* CVE-2017-14107: Improve EOCD64 parsing\n\n\n# 1.2.0 [2017-02-19]\n\n* Support for AES encryption (Winzip version), both encryption\n  and decryption\n* Support legacy zip files with >64k entries\n* Fix seeking in zip_source_file if start > 0\n* Add zip_fseek() for seeking in uncompressed data\n* Add zip_ftell() for telling position in uncompressed data\n* Add zip_register_progress_callback() for UI updates during zip_close()\n\n\n# 1.1.3 [2016-05-28]\n\n* Fix build on Windows when using autoconf\n\n\n# 1.1.2 [2016-02-19]\n\n* Improve support for 3MF files\n\n\n# 1.1.1 [2016-02-07]\n\n* Build fixes for Linux\n* Fix some warnings reported by PVS-Studio\n\n\n# 1.1 [2016-01-26]\n\n* ziptool(1): command line tool to modify zip archives\n* Speedups for archives with many entries\n* Coverity fixes\n* Better APK support\n* Support for running tests on Windows\n* More build fixes for Windows\n* Portability fixes\n* Documentation improvements\n\n\n# 1.0.1 [2015-05-04]\n\n* Build fixes for Windows\n\n\n# 1.0 [2015-05-03]\n\n* Implemented an I/O abstraction layer\n* Added support for native Windows API for files\n* Added support for setting the last modification time for a file\n* Added a new type zip_error_t for errors\n* Added more typedefs for structs\n* Torrentzip support was removed\n* CVE-2015-2331 was fixed\n* Addressed all Coverity CIDs\n\n\n# 0.11.2 [2013-12-19]\n\n* Support querying/setting operating system and external attributes\n* For newly added files, set operating system to UNIX, permissions\n  to 0666 (0777 for directories)\n* Fix bug when writing zip archives containing files bigger than 4GB\n\n\n# 0.11.1 [2013-04-27]\n\n* Fix bugs in zip_set_file_compression()\n* Include Xcode build infrastructure\n\n\n# 0.11 [2013-03-23]\n\n* Added Zip64 support (large file support)\n* Added UTF-8 support for file names, file comments, and archive comments\n* Changed API for name and comment related functions for UTF-8 support\n* Added zip_discard()\n* Added ZIP_TRUNCATE for zip_open()\n* Added zip_set_file_compression()\n* Added API for accessing and modifying extra fields\n* Improved API type consistency\n* Use gcc4's visibility __attribute__\n* More changes for Windows support\n* Additional test cases\n\n\n# 0.10.1 [2012-03-20]\n\n* Fixed CVE-2012-1162\n* Fixed CVE-2012-1163\n\n\n# 0.10 [2010-03-18]\n\n* Added zip_get_num_entries(), deprecated zip_get_num_files()\n* Better windows support\n* Support for traditional PKWARE encryption added\n* Fix opening archives with more than 65535 entries\n* Fix some memory leaks\n* Fix cmake build and installation\n* Fix memory leak in error case in zip_open()\n* Fixed CVE-2011-0421 (no security implications though)\n* More documentation\n\n\n# 0.9.3 [2010-02-01]\n\n* Include m4/ directory in distribution; some packagers need it\n\n\n# 0.9.2 [2010-01-31]\n\n* Avoid passing uninitialized data to deflate()\n* Fix memory leak when closing zip archives\n\n\n# 0.9.1 [2010-01-24]\n\n* Fix infinite loop on reading some broken files\n* Optimization in time conversion (don't call localtime())\n* Clear data descriptor flag in central directory, fixing Open Office files\n* Allow more than 64k entries\n\n\n# 0.9 [2008-07-25]\n\n* on Windows, explicitly set dllimport/dllexport\n* remove erroneous references to GPL\n* add support for torrentzip\n* new functions: zip_get_archive_flag, zip_set_archive_flag\n* zip_source_zip: add flag to force recompression\n* zip_sorce_file: only keep file open while reading from it\n\n\n# 0.8 [2007-06-06]\n\n* fix for zip archives larger than 2GiB\n* fix zip_error_strerror to include libzip error string\n* add support for reading streamed zip files\n* new functions: zip_add_dir, zip_error_clear, zip_file_error_clear\n* add basic support for building with CMake (incomplete)\n\n\n# 0.7.1 [2006-05-18]\n\n* bugfix for zip_close\n\n\n# 0.7 [2006-05-06]\n\n* struct zip_stat increased for future encryption support\n* zip_add return value changed (now returns new index of added file)\n* shared library major bump because of previous two\n* added functions for reading and writing file and archive comments\n  New functions: zip_get_archive_comment, zip_get_file_comment,\n  zip_set_archive_comment, zip_set_file_comment, zip_unchange_archive\n\n\n# 0.6.1 [2005-07-14]\n\n* various bug fixes\n\n\n# 0.6 [2005-06-09]\n\n* first standalone release\n* changed license to three-clause BSD\n* overhauled API\n* added man pages\n* install zipcmp and zipmerge\n"
  },
  {
    "path": "external/libzip/README.md",
    "content": "# libzip\n\n## A C Library for Reading, Creating, and Modifying Zip Archives\n\n\n## Why Use libzip?\n\nlibzip has been continuously developed since 2005. It is efficient, small, and flexible. It is usable on Linux, macOS, and Windows and many other operating systems.\n\nThe main design criteria are:\n\n- Maintain a stable API without breaking backwards compatibility.\n- Do not create corrupt files, even in case of errors.\n- Do not delete data.\n- Be efficient.\n\nIt supports the following features:\n\n- Reading archives and file data from files or memory buffers\n- Reverting unsaved changes\n- Zip64 large archives\n- Deflate, bzip2, LZMA, and zstd compression\n- Winzip AES and legacy PKWARE encryption\n\nThe [BSD license](LICENSE) used for libzip allows its use in commercial products. \n\n## Who Uses libzip?\n\nlibzip is used in major open source projects like [KDE](https://kde.org/), [Chromium](https://www.chromium.org/Home), [ImageMagick](https://github.com/ImageMagick/ImageMagick/), and [VeraCrypt](https://www.veracrypt.fr/).\n\nCommercial products using libzip include [Lightroom from Adobe](https://lightroom.adobe.com/) and the [Kobo eReader](http://www.kobo.com/desktop).\n\nThere are also bindings for other programming languages: [Python](https://github.com/KOLANICH-libs/libzip.py), [Ruby](http://rubygems.org/gems/zipruby/), [Lua](https://github.com/brimworks/lua-zip), [PHP](http://pecl.php.net/package/zip), and others.\n\nThere is a more complete [list of projects](https://libzip.org/users/).\n\n\n## Getting Started\n\nMost Linux and other Unix distributions include libzip in their package distributions, it is usually called `libzip` or `libzip-dev`. \n\nOn macOS, it is included in both Homebrew and Mac Ports.\n\nOn Windows, it is in vcpkg.\n\nA list of available packages can be found on [Repology](https://repology.org/project/libzip/versions). \n\nFor building and installing libzip from source, see the [INSTALL.md](INSTALL.md) file.\n\n\n## Using libzip\n\nlibzip is fully documented via man pages. HTML versions of the man\npages are on [libzip.org](https://libzip.org/documentation/) and in the [man](man) directory. You can start with\n[libzip(3)](https://libzip.org/documentation/libzip.html), which lists\nall others. Example source code is in the [examples](examples) and\n[src](src) subdirectories.\n\nIf you have developed an application using libzip, you can find out\nabout API changes and how to adapt your code for them in the included\nfile [API-CHANGES.md](API-CHANGES.md).\n\n\n## Staying in Touch\n\nMore information and the latest version can always be found on [libzip.org](https://libzip.org).  The official repository is at [GitHub](https://github.com/nih-at/libzip/).\n\nIf you want to reach the authors in private, use <info@libzip.org>.\n\n[![Packaging status](https://repology.org/badge/tiny-repos/libzip.svg)](https://repology.org/project/libzip/versions)\n\n[![Github Actions Build Status](https://github.com/nih-at/libzip/workflows/build/badge.svg)](https://github.com/nih-at/libzip/actions?query=workflow%3Abuild)\n[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/f1bqqt9djvf22f5g?svg=true)](https://ci.appveyor.com/project/nih-at/libzip)\n[![Coverity Status](https://scan.coverity.com/projects/127/badge.svg)](https://scan.coverity.com/projects/libzip)\n[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libzip.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libzip)\n"
  },
  {
    "path": "external/libzip/SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nWe are not maintaining multiple branches, so all fixes will be committed to head and included in the next release.\n\nWe take great care to maintain backwards compatibility, so we expect our users to use the latest version.\n\n## Reporting a Vulnerability\n\nYou can reach us per email at info@libzip.org.\n\nFor less sensitive reports, you can also open an issue or pull request on GitHub.\n"
  },
  {
    "path": "external/libzip/THANKS",
    "content": "Thanks to Info-ZIP for info on the DOS-time/date conversion code,\nand some other general information gathered from their sources.\n\nThanks to these people for suggestions, testing, and bug reports:\n\nag2s20150909\nAgostino Sarubbo\nAlberto Spin\nAlexander Galanin <al@galanin.nnov.ru>\nAlexandr Shadchin <alexandr.shadchin@gmail.com>\nAlexey Bykov <gnfalex@rambler.ru>\nAndreas Deininger <andreas@deininger.net>\nAndreas Falkenhahn <andreas@falkenhahn.com>\nAndrew Brampton <brampton@gmail.com>\nAndrew Molyneux <andrew@molyneuxfamily.co.uk>\nAnkur Kothari <ankz.kothari@gmail.com>\nAntonin Décimo <antonin.decimo@gmail.com>\nArseniy Terekhin <senyai@gmail.com>\nBALATON Zoltan <balaton@eik.bme.hu>\nBenjamin Gilbert <bgilbert@backtick.net>\nBeuc <beuc@beuc.net>\nBoaz Stolk <bstolk@aweta.nl>\nBob Friesenhahn\nBogdan <bogiebog@gmail.com>\nBrian 'geeknik' Carpenter <geeknik@protonmail.ch>\nBruceFan <fanrong_1992@163.com>\nCarl Mastrangelo <notcarl@google.com>\nCédric Tabin\ncelan69\nchaoticgd\nCharlie Li <git@vishwin.info>\nChrisAm1224\nChris Mayo\nChris Nehren <cnehren+libzip@pobox.com>\nChristoph Cullmann <cullmann@kde.org>\nChristoph M. Becker <cmbecker69@gmx.de>\nCorentin Schreiber\nCoverity <info@coverity.com>\ncryi <cryi@tutanota.com>\nctenter-scs\nDane Springmeyer <dane.springmeyer@gmail.com>\nDaniel Russel <drussel@gmail.com>\nЛарионов Даниил <scumcoder@yandex.ru>\nDavid Demelier <demelier.david@gmail.com>\nDean Ellis <dellis1972@googlemail.com>\nDeclan Moran\nDel Merritt <del@alum.mit.edu>\nDevin Davila <daviladsoftware@gmail.com>\nDmytro Rybachenko <atmoliton@gmail.com>\nDylan T. <dktapps@pmmp.io>\nEelco Dolstra\nElvis Angelaccio\nErin Melucci <emelucci@opera.com>\nErwin Haid <erwin.haid@gmx.de>\nEun-cheol Joo\nFabrice Fontaine\nFilip Niksic\nFlorian Delizy <florian.delizy@gmail.com>\nForce Charlie <charlieio@outlook.com>\nFrançois Simon <AT.GFI.Francois.SIMON@sesam-vitale.fr>\nFrederik Ramm <frederik@remote.org>\nGabriela Gutierrez <gabigutierrez@google.com>\nGerard ODonnell\nGiovanni\ngk7huki <gk7huki@gmail.com>\nHanno Böck <hanno@hboeck.de>\nHeeMyung\nHeiko Becker\nHeiko Hund <heiko@ist.eigentlich.net>\nhongjunwang\nIlya Voronin\nInfo-ZIP group\nIvan Kolesnikov <kiv.apple@gmail.com>\nJan Weiß <jan@geheimwerk.de>\nJay Freeman (saurik) <saurik@saurik.com>\njloqfjgk@github\nJoachim Reichel <joachim.reichel@gmx.de>\nJoão Custódio <joao_custodio@symantec.com>\nJoel Ebrahimi <joel.ebrahimi@gmail.com>\nJono Spiro <jono.spiro@gmail.com>\nJulien Matthey <julien@turtlespeak.net>\nJulien Schueller <schueller@phimeca.com>\nJustin Cohen <justincohen@google.com>\nKate Raggett\nkensington <kensington@gentoo.org>\nKei Takahashi <ktakahashi@minitab.com>\nKeith Jones <keith@keithjjones.com>\nKhaled Mardam-Bey\nKohei Yoshida <kohei.yoshida@gmail.com>\nKrzesimir Nowak <qdlacz@gmail.com>\nLeith Bade <leith@mapbox.com>\nLubomir I. Ivanov <neolit123@gmail.com>\nLucas Bustamante\nLudovic LANGE\nM. Reiningħaus\nMaël Nison\nManuel Massing <m.massing@virtualities.de>\nMarcin Kowalczyk <QrczakMK@gmail.com>\nMark A. Tsuchida <marktsuchida@gmail.com>\nMartin Buchholz <martinrb@google.com>\nMartin Herkt <lachs0r@srsfckn.biz>\nMartin Szulecki <m.szulecki@libimobiledevice.org>\nMathieu Pujol\nMichael Balzer\nMichael Beck <mm.beck@gmx.net>\nMichael Heimpold <mhei@heimpold.de>\nMichał Janiszewski <janisozaur+libzip@gmail.com>\nMichal Vyskocil <mvyskocil@suse.cz>\nMikhail Gusarov <dottedmag@dottedmag.net>.\nMiklos Vajna\nMorris Hafner\nMuhammad Arslan Kabeer\nMykyta Mudryi <Nikita.Mudryi@leviathansecurity.com>\nnieder <nieder@users.sourceforge.net>\nOliver Kaiser <under.northern.sky@googlemail.com>\nOliver Kuckertz <oliver.kuckertz@mologie.de>\nOSS-Fuzz Team\nØrjan Malde <red@foxi.me>\nPascal Terjan <pterjan@gmail.com>\nPatrick Spendrin <ps_ml@gmx.de>\nPaul Harris <harris.pc@gmail.com>\nPaul Sheppard <shepsoft@googlemail.com>\nPavel Raiskup <praiskup@redhat.com>\nPierre Joye <pierre.php@gmail.com>\nPierre Wendling <pierre.wendling.4@gmail.com>\nPierre-Louis Cabelguen <plcabelguen@googlemail.com>\nPW Hu <jlu.hpw@foxmail.com>\nRafał Mikrut\nralfjunker\nRandy <randy408@protonmail.com>\nRemi Collet <remi@fedoraproject.org>\nrezso <rezso@rezso.net>\nRichard Schütz\nRick Carback <carback1@umbc.edu>\nRikard Falkeborn <rikard.falkeborn@gmail.com>\nRobert Norris <rw_norris@hotmail.com>\nRoberto Tirabassi <rtirabassi@3di.it>\nrobhz786 <robhz786@gmail.com>\nRoland Ortloff <Ortloff.R@gmx.de>\nRosen Penev <rosenp@gmail.com>\nRudi Heitbaum\nRyan Burns <rtburns@protonmail.com>\nSam James\nSam Sappenfield\nSandro Mani <manisandro@gmail.com>\nscribam\nSebastian Kemper <sebastian_ml@gmx.net>\nSebastian Schmitt <sebastian.schmitt@auvesy.de>\nSergei Ozerov <ru.programmist@gmail.com>\nshenlebantongying\nShimi\nSimon Talbot <simont@nse.co.uk>\nSpaceIm\nStephen Bryant <steve@bawue.de>\nsxkan\nTabata Shintaro <tabata.shintaro@gmail.com>\ntakase1121\nTarmo Pikaro <tapika@yahoo.com>\nTaylor C. Richberger\nTC\nThomas Debesse <dev@illwieckz.net>\nTim Lunn <Tim@feathertop.org>\nTimo Warns <warns@pre-sense.de>\nTimofey\nTom Callaway <tcallawa@redhat.com>\nTomas Hoger <thoger@redhat.com>\nTomáš Malý <malytomas@ucpu.cz>\nTorsten Paul <Torsten.Paul@gmx.de>\nTransporter <ogre.transporter@gmail.com>\nVassili Courzakis <vcoxvco@googlemail.com>\nVinpasso\nVitaly Murashev <vitaly.murashev@gmail.com>\nWilliam Lee\nWilliam Ouwehand <mail@syncoda.nl>\nWojciech Michalski <wmichalski@quay.pl>\nWolfgang Glunz <Wolfgang.Glunz@gmx.de>\nYufan You\n"
  },
  {
    "path": "external/libzip/TODO.md",
    "content": "## Fuzzing\n\n- improve AES and PKWARE encryption tests\n- add more\n- review memset() uses\n\n### Torrentzip\n\n- Handle data sources with unknown uncompressed size: if we forced ZIP64 and don't need it, return specific error (so calling code can decide what to do (e. g. clear torrentzip flag and call `zip_close()` again)).\n\n## Other\n\n- split `zip_source_t` in main part and reference so we can keep track which reference called open and we can invalidate references if the underlying source gets invalidated (e. g. by `zip_close`).\n\n## Prefixes\n\nFor example for adding extractors for self-extracting zip archives.\n````c\nzip_set_archive_prefix(struct zip *za, const zip_uint8_t *data, zip_uint64_t length);\nconst zip_uint8_t *zip_get_archive_prefix(struct zip *za, zip_uint64_t *lengthp);\n````\n\n## Compression\n\n* add lzma2 support\n* add deflate64 support (https://github.com/madler/zlib/blob/master/contrib/infback9/infback9.h)\n\n## API Issues\n\n* Add `zip_file_use_password` to set per-file password to use if libzip needs to decrypt the file (e.g. when changing encryption or compression method).\n\n* `zip_get_archive_comment` has `int *lenp` argument.  Cleaner would be `zip_uint32_t *`.\n  rename and fix.  which other functions for naming consistency?\n* rename remaining `zip_XXX_{file,archive}_*` to `zip_{file,archive}_XXX_*`?\n* compression/crypt implementations: how to set error code on failure\n* compression/crypt error messages a la `ZIP_ER_ZLIB` (no detailed info passing)\n\n## Features\n\n* consistently use `_zip_crypto_clear()` for passwords\n* support setting extra fields from `zip_source`\n  * introduce layers of extra fields:\n    * original\n    * from `zip_source`\n    * manually set\n  * when querying extra fields, search all of them in reverse order\n  * add whiteout (deleted) flag\n  * allow invalid data flag, used when computing extra field size before writing data\n  * new command `ZIP_SOURCE_EXTRA_FIELDS`\n  * no support for multiple copies of same extra field\n* function to copy file from one archive to another\n* set `O_CLOEXEC` flag after fopen and mkstemp\n* support streaming output (creating new archive to e.g. stdout)\n* add function to read/set ASCII file flag\n* add custom compression function support\n* `zip_source_zip()`: allow rewinding\n* `zipcmp`: add option for file content comparison\n* `zipcmp`: add more paranoid checks:\n  * external attributes/opsys\n  * version needed/made by\n  * general purpose bit flags\n* add more consistency checks:\n  * for stored files, test compressed = uncompressed\n  * data descriptor\n  * local headers come before central dir\n* support for old compression methods?\n\n## Bugs\n\n* ensure that nentries is small enough not to cause overflow (size_t for entry, uint64 for CD on disk)\n* check for limits imposed by format (central dir size, file size, extra fields, ...)\n* `_zip_u2d_time()`: handle `localtime(3)` failure\n* POSIX: `zip_open()`: check whether file can be created and fail if not\n* fix inconsistent usage of valid flags (not checked in many places)\n* `cdr == NULL` -> `ER_NOENT` vs. `idx > cdir->nentry` -> `ER_INVAL` inconsistent (still there?)\n\n## Cleanup\n\n* go over cdir parser and rename various offset/size variables to make it clearer\n* use bool\n* use `ZIP_SOURCE_SUPPORTS_{READABLE,SEEKABLE,WRITABLE}`\n* use `zip_source_seek_compute_offset()`\n* get rid of `zip_get_encryption_implementation()`\n* use `zip_*int*_t` internally\n* `zip_source_file()`: don't allow write if start/len specify a part of the file\n\n## Documentation\n\n* document valid file paths\n* document: `zip_source_write()`: length can't be > `ZIP_INT64_MAX`\n* document: `ZIP_SOURCE_CLOSE` implementation can't return error\n* keep error codes in man pages in sync\n* document error codes in new man pages\n\n## Infrastructure\n\n* add coverage reports, e.g. using gcovr or https://github.com/eddyxu/cpp-coveralls (coveralls.io)\n* review guidelines/community standards\n  - [Linux Foundation Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/)\n  - [Readme Maturity Level](https://github.com/LappleApple/feedmereadmes/blob/master/README-maturity-model.md)\n  - [Github Community Profile](https://github.com/nih-at/libzip/community)\n* test different crypto backends with GitHub actions.\n* improve man page formatting of tagged lists on webpage (`<dl>`)\n* rewrite `make_zip_errors.sh` in cmake\n* script to check if all exported symbols are marked with `ZIP_EXTERN`, add to `make distcheck`\n\n## macOS / iOS framework\n\n* get cmake to optionally build frameworks\n\n## Test Case Issues\n\n* add test cases for all `ZIP_INCONS` detail errors\n* `incons-local-filename-short.zzip` doesn't test short filename, since extra fields fail to parse.\n* test error cases with special source\n  - tell it which command should fail\n  - use it both as source for `zip_add` and `zip_open_from_source`\n  - `ziptool_regress`:\n    - `-e error_spec`: source containing zip fails depending on `error_spec`\n    - `add_with_error name content error_spec`: add content to archive, where source fails depending on `error_spec`\n    - `add_file_with_error name file_to_add offset len error_spec`: add file to archive, len bytes starting from offset, where source fails depending on `error_spec`\n  - `error_spec`:\n    - source command that fails\n\t- error code that source returns\n\t- conditions that must be met for error to trigger\n\t  - Nth call of command\n      - read/write: total byte count so far\n\t  - state of source (opened, EOF reached, ...)\n* test for zipcmp reading directory (requires fts)\n* add test case for clone with files > 4k\n* consider testing for `malloc`/`realloc` failures\n* Winzip AES support\n  * test cases decryption: <=20, >20, stat for both\n  * test cases encryption: no password, default password, file-specific password, 128/192/256, <=20, >20\n  * support testing on macOS\n* add test cases for lots of files (including too many)\n* add test cases for holes (between files, between files and cdir, between cdir and eocd, + zip64 where appropriate)\n* test seek in `zip_source_crc_create()`\n* test cases for `set_extra*`, `delete_extra*`, `*extra_field*`\n* test cases for in memory archives\n  * add\n  * delete\n  * delete all\n  * modify\n* use gcov output to increase test coverage\n* add test case to change values for newly added files (name, compression method, comment, mtime, . . .)\n* `zip_open()` file less than `EOCDLEN` bytes long\n* test calls against old API\n* rename file to dir/ and vice versa (fails)\n* fix comment test to be newline insensitive\n* check if http://bugs.python.org/issue20078 provides ideas for new tests\n\n* (`add`, `replace`)\n  * add to empty zip\n  * add to existing zip\n  * add w/ existing file name [E]\n  * replace ok\n  * replace w/ illegal index [E]\n  * replace w/ deleted name [E]\n  * unchange added/replaced file\n* (`close`)\n  * copy zip file\n  * open copy\n  * rename, delete, replace, add w/ new name, add w/ deleted name\n  * close\n  * zipcmp copy expected\n  * remove copy\n* (`error_get`)\n* (`error_get_sys_type`)\n* (`error_to_str`)\n* (`extra_fields`)\n* (`file_error_get`)\n* (`file_strerror`)\n* (`replace`)\n* (`source_buffer`)\n* (`source_file`)\n* (`source_filep`)\n* (`source_free`)\n* (`source_function`)\n* (`source_zip`)\n* (`strerror`)\n* (`unchange`)\n* (`unchange_all`)\n* `open(ZIP_RDONLY)`\n* I/O abstraction layer\n  * `zip_open_from_source`\n* read two zip entries interleaved\n* test `zip_file_is_seekable` (via `ziptool`?)\n"
  },
  {
    "path": "external/libzip/android/do.sh",
    "content": "\n# Author: Declan Moran\n# www.silverglint.com \n# Thanks to damaex (https://github.com/damaex), for significant contributions\n\nANDROID_NDK_ROOT=/home/android/android-ndk-r19c\n\nINSTALL_DIR=install\nBUILD_DIR=build\nSTART_DIR=$(pwd)\n\nrm -rf $INSTALL_DIR\nrm -rf $BUILD_DIR\nmkdir -p $BUILD_DIR #\"${ANDROID_TARGET_PLATFORM}\"\n\n#--------------------------------------------------------------------\nbuild_it()\n{\n    # builds either a static or shared lib depending on parm passed (ON or OFF)\n    want_shared=$1\n\n\tcmake -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \\\n\t\t-DCMAKE_INSTALL_PREFIX:PATH=$(pwd)/../../${INSTALL_DIR}/${ANDROID_TARGET_PLATFORM} \\\n\t\t-DANDROID_ABI=${ANDROID_TARGET_PLATFORM} \\\n\t\t-DENABLE_OPENSSL:BOOL=OFF \\\n\t\t-DENABLE_COMMONCRYPTO:BOOL=OFF \\\n\t\t-DENABLE_GNUTLS:BOOL=OFF \\\n\t\t-DENABLE_MBEDTLS:BOOL=OFF \\\n\t\t-DENABLE_OPENSSL:BOOL=OFF \\\n\t\t-DENABLE_WINDOWS_CRYPTO:BOOL=OFF \\\n\t\t-DBUILD_TOOLS:BOOL=OFF \\\n\t\t-DBUILD_REGRESS:BOOL=OFF \\\n\t\t-DBUILD_EXAMPLES:BOOL=OFF \\\n\t\t-DBUILD_SHARED_LIBS:BOOL=$want_shared \\\n\t\t-DBUILD_DOC:BOOL=OFF \\\n\t\t-DANDROID_TOOLCHAIN=clang  cmake -H.. -B$BUILD_DIR/${ANDROID_TARGET_PLATFORM}\n\t\t   \t\n        #run make with all system threads and install\n        cd $BUILD_DIR/${ANDROID_TARGET_PLATFORM}\n        make install -j$(nproc --all)\n        cd $START_DIR\n    }\n\n#--------------------------------------------------------------------\nfor ANDROID_TARGET_PLATFORM in armeabi-v7a arm64-v8a x86 x86_64\ndo\n\techo \"Building libzip for ${ANDROID_TARGET_PLATFORM}\" \n\t\n\tbuild_it ON\n\tbuild_it OFF\n\t\n\tif [ $? -ne 0 ]; then\n\t\techo \"Error executing: cmake\"\n\t\texit 1\n\tfi\n\n\t\n\tif [ $? -ne 0 ]; then\n\t\techo \"Error executing make install for platform: ${ANDROID_TARGET_PLATFORM}\"\n\t\texit 1\n    fi\n    \ndone    \n"
  },
  {
    "path": "external/libzip/android/docker/Dockerfile",
    "content": "# Version: 1.0\n\n# Dockerfile for building libzip for android\n# https://github.com/dec1/libzip.git\n# creates docker container with all tools, libraries and sources required to build libzip for android.\n\n# Author: Declan Moran\n# www.silverglint.com\n\n\n# Usage:\n#---------\n# download the libzip repository\n# > git clone https://github.com/dec1/libzip.git\n# > cd libzip\n#\n# build docker image \"my_img_zip\" from the dockerfile in \"docker\" dir\n# > docker build -t my_img_zip ./android/docker\n#\n# run docker container \"my_ctr_zip\" from this image, mounting the current dir. (Need to pass absolute host paths to mount volume- hence \"pwd\")\n# > docker run  -v $(pwd):/home/docker-share/libzip -it --entrypoint=/bin/bash --name my_ctr_zip my_img_zip\n#\n# Now inside docker container\n# $ cd /home/docker-share/libzip/android\n#\n# Modify ./do.sh (on host), to match the boost and android ndk versions/paths in the \"Configure here\" section below\n# Build from running docker container.\n# $./do.sh\n#\n# \"./build\" dir contains required build, but owned by root. chown to your username/group\n# > sudo chown -R <userid>:<groupid> ./build\n# > sudo chown -R <userid>:<groupid> ./install\n#\n# Exit container, when build is finished.\n# $ exit\n#\n\n\n\n\nFROM ubuntu:18.04\n\n\n## --------------------------------------------------------------------\n##              Configure here\n# ---------------------------------------------------------------------\n# ---------------------------------------------------------------------\n# Here you can speciofy exactly what android ndk (and sdk) version you want to use.\n\n\n\n# (2) Android SDK\n# https://developer.android.com/studio#downloads\nARG SDK_URL_BASE=https://dl.google.com/android/repository\nARG SDK_FILE=sdk-tools-linux-4333796.zip\n\n# the sdk platform to use\n# https://developer.android.com/guide/topics/manifest/uses-sdk-element\nARG ANDROID_SDK_PLATFORM_VERS=\"platforms;android-28\"\n\n\n\n# (3) Android NDK\n# https://developer.android.com/ndk/downloads\nARG NDK_URL_BASE=https://dl.google.com/android/repository\nARG NDK_FILE=android-ndk-r19c-linux-x86_64.zip\n# ---------------------------------------------------------------------\n## --------------------------------------------------------------------\n\nRUN apt-get update\nRUN apt-get -y dist-upgrade\n\n\n# for downloading archives\nRUN apt-get -y install wget\n\n# for unzipping downloaded android archives\nRUN apt-get -y install zip\nRUN apt-get -y install cmake\n\nRUN apt-get -y install lib32z1\n\n\n# need this this to install some (32 bit) prerequisites for android builds\nRUN dpkg --add-architecture i386\nRUN apt-get update\nRUN apt-get -y dist-upgrade\nRUN apt-get install -y  libc6:i386 libncurses5:i386 libstdc++6:i386 libbz2-1.0:i386\n\n\n# need c compiler to set up create boost build system (before building boost with it and android toolchain)\nRUN apt-get -y install build-essential\nRUN apt-get -y install libc6-dev-i386\nRUN apt-get -y install clang\n\nRUN apt-get -y install openjdk-8-jdk\n#--------------------------------------\n\nARG ANDROID_HOME=/home/android\nWORKDIR ${ANDROID_HOME}\n\n\n# SDK\n# ----\n# download android sdk command line tools\nRUN wget ${SDK_URL_BASE}/$SDK_FILE\nRUN unzip $SDK_FILE\n\nENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools\n\n\nRUN yes | sdkmanager --licenses\n\nRUN sdkmanager \"platform-tools\" $ANDROID_SDK_PLATFORM_VERS\n#RUN sdkmanager \"platform-tools\" \"platforms;android-28\"\n\n\n# NDK\n# ----\nRUN wget ${NDK_URL_BASE}/$NDK_FILE\nRUN unzip $NDK_FILE\n\n"
  },
  {
    "path": "external/libzip/android/readme.txt",
    "content": "\nCross compile libzip for android.\n--------------------------------\nModify \"do.sh\" as appropriate if you need to specify a different ndk dir or wish to specify different build parameters\n\nPrerequisites for the development machine - see docker/Dockerfile\n\nYou can either set you host machine up with these prerequisites or simply use docker (in which case you need not install anything on your host machine except docker itself).\n\nSee \"Usage\" in docker/Dockerfile for detailed instructions.\n\n\nPlease note: The libzip development team does not use Android, so this script is provided as is, as we cannot properly maintain it. We will, however, gladly accept fixes and try to work with users to resolve any issues they may have.\n"
  },
  {
    "path": "external/libzip/appveyor.yml",
    "content": "os:\n- Visual Studio 2019\n\nenvironment:\n  PATH: C:\\Python311-x64\\Scripts;C:\\Python311-arm\\Scripts;$(PATH)\n  VCPKG_BINARY_SOURCES: clear;files,C:\\vcpkg.cache,readwrite\n  matrix:\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: x64\n      TRIPLET: x64-windows\n      CMAKE_OPTS: \"-DBUILD_SHARED_LIBS=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: yes\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: x64\n      TRIPLET: x64-uwp\n      CMAKE_OPTS: \"-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: Win32\n      TRIPLET: x86-windows\n      CMAKE_OPTS: \"-DBUILD_SHARED_LIBS=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: yes\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: Win32\n      TRIPLET: x86-uwp\n      CMAKE_OPTS: \"-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: ARM\n      TRIPLET: arm-windows\n      CMAKE_OPTS: \"-DENABLE_OPENSSL=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: ARM\n      TRIPLET: arm-uwp\n      CMAKE_OPTS: \"-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: ARM64\n      TRIPLET: arm64-windows\n      CMAKE_OPTS: \"-DENABLE_OPENSSL=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n    - GENERATOR: \"Visual Studio 16 2019\"\n      PLATFORM: ARM64\n      TRIPLET: arm64-uwp\n      CMAKE_OPTS: \"-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off\"\n      CMAKE_CONFIG: Release\n      RUN_TESTS: no\n      TOXENV: py311\n\nbefore_build:\n  cmd: >-\n    py -m pip install nihtest\n\n    mkdir build\n\n    cd build\n\n    cmake -DCMAKE_TOOLCHAIN_FILE=C:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. -G \"%GENERATOR%\" -A \"%PLATFORM%\" %CMAKE_OPTS%\n\n    appveyor PushArtifact config.h\n\n    appveyor PushArtifact CMakeCache.txt\n\nbuild_script:\n  cmd: >-\n    cmake --build . --config %CMAKE_CONFIG% --target INSTALL\n\n    cmake --build . --config %CMAKE_CONFIG%\n\ntest_script:\n  cmd: >-\n    set VERBOSE=yes\n\n    IF %RUN_TESTS%==yes ( ctest -C %CMAKE_CONFIG% --output-on-failure )\n\ncache:\n  - c:\\vcpkg.cache -> vcpkg.json\n"
  },
  {
    "path": "external/libzip/cmake/Dist.cmake",
    "content": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# 1. Redistributions of source code must retain the above copyright\n#   notice, this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#   notice, this list of conditions and the following disclaimer in\n#   the documentation and/or other materials provided with the\n#   distribution.\n#\n# 3. The names of the authors may not be used to endorse or promote\n#   products derived from this software without specific prior\n#   written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#[=======================================================================[.rst:\nDist\n-------\n\nProvide ``dist`` and ``distcheck`` targets similar to\nautoconf/automake functionality.\n\nThe ``dist`` target creates tarballs of the project in ``.tar.gz`` and\n``.tar.xz`` formats.\n\nThe ``distcheck`` target extracts one of created tarballs, builds the\nsoftware using its defaults, and runs the tests.\n\nBoth targets use Unix shell commands.\n\nThe Dist target takes one argument, the file name (before the extension).\n\nThe ``distcheck`` target creates (and removes) ``${ARCHIVE_NAME}-build``\nand ``${ARCHIVE_NAME}-dest``.\n\n#]=======================================================================]\nfunction(Dist ARCHIVE_NAME)\n  if(NOT TARGET dist AND NOT TARGET distcheck)\n    add_custom_target(dist\n      COMMAND git config tar.tar.xz.command \"xz -c\"\n      COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz HEAD\n      COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.xz HEAD\n      WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n      )\n    add_custom_target(distcheck\n      COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest 2>/dev/null || true\n      COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest\n      COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz\n      COMMAND chmod -R u-w ${ARCHIVE_NAME}\n      COMMAND mkdir ${ARCHIVE_NAME}-build\n      COMMAND mkdir ${ARCHIVE_NAME}-dest\n      COMMAND ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${ARCHIVE_NAME}-dest ${ARCHIVE_NAME} -B ${ARCHIVE_NAME}-build\n      COMMAND make -C ${ARCHIVE_NAME}-build -j4\n      COMMAND make -C ${ARCHIVE_NAME}-build test\n      COMMAND make -C ${ARCHIVE_NAME}-build install\n      #  COMMAND make -C ${ARCHIVE_NAME}-build uninstall\n      #  COMMAND if [ `find ${ARCHIVE_NAME}-dest ! -type d | wc -l` -ne 0 ]; then echo leftover files in ${ARCHIVE_NAME}-dest; false; fi\n      COMMAND make -C ${ARCHIVE_NAME}-build clean\n      COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest\n      COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest\n      COMMAND echo \"${ARCHIVE_NAME}.tar.gz is ready for distribution.\"\n      WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n      )\n    add_dependencies(distcheck dist)\n  endif()\nendfunction()\n"
  },
  {
    "path": "external/libzip/cmake/FindMbedTLS.cmake",
    "content": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# 1. Redistributions of source code must retain the above copyright\n#   notice, this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#   notice, this list of conditions and the following disclaimer in\n#   the documentation and/or other materials provided with the\n#   distribution.\n#\n# 3. The names of the authors may not be used to endorse or promote\n#   products derived from this software without specific prior\n#   written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#[=======================================================================[.rst:\nFindMbedTLS\n-------\n\nFinds the Mbed TLS library.\n\nImported Targets\n^^^^^^^^^^^^^^^^\n\nThis module provides the following imported targets, if found:\n\n``MbedTLS::MbedTLS``\n  The Mbed TLS library\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\nThis will define the following variables:\n\n``MbedTLS_FOUND``\n  True if the system has the Mbed TLS library.\n``MbedTLS_VERSION``\n  The version of the Mbed TLS library which was found.\n``MbedTLS_INCLUDE_DIRS``\n  Include directories needed to use Mbed TLS.\n``MbedTLS_LIBRARIES``\n  Libraries needed to link to Mbed TLS.\n\nCache Variables\n^^^^^^^^^^^^^^^\n\nThe following cache variables may also be set:\n\n``MbedTLS_INCLUDE_DIR``\n  The directory containing ``mbedtls/aes.h``.\n``MbedTLS_LIBRARY``\n  The path to the Mbed TLS library.\n\n#]=======================================================================]\n\n# I'm not aware of a pkg-config file for mbedtls as of 2020/07/08.\n#find_package(PkgConfig)\n#pkg_check_modules(PC_MbedTLS QUIET mbedtls)\n\nfind_path(MbedTLS_INCLUDE_DIR\n  NAMES mbedtls/aes.h\n#  PATHS ${PC_MbedTLS_INCLUDE_DIRS}\n)\nfind_library(MbedTLS_LIBRARY\n  NAMES mbedcrypto\n#  PATHS ${PC_MbedTLS_LIBRARY_DIRS}\n)\n\n# Extract version information from the header file\nif(MbedTLS_INCLUDE_DIR)\n  # for major version 3\n  if(EXISTS ${MbedTLS_INCLUDE_DIR}/mbedtls/build_info.h)\n    file(STRINGS ${MbedTLS_INCLUDE_DIR}/mbedtls/build_info.h _ver_line\n        REGEX \"^#define MBEDTLS_VERSION_STRING  *\\\"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\"\"\n        LIMIT_COUNT 1)\n    string(REGEX MATCH \"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\"\n        MbedTLS_VERSION \"${_ver_line}\")\n    unset(_ver_line)\n  # for major version 2\n  elseif(EXISTS ${MbedTLS_INCLUDE_DIR}/mbedtls/version.h)\n    file(STRINGS ${MbedTLS_INCLUDE_DIR}/mbedtls/version.h _ver_line\n         REGEX \"^#define MBEDTLS_VERSION_STRING  *\\\"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\"\"\n         LIMIT_COUNT 1)\n    string(REGEX MATCH \"[0-9]+\\\\.[0-9]+\\\\.[0-9]+\"\n           MbedTLS_VERSION \"${_ver_line}\")\n    unset(_ver_line)\n  else()\n    if(PC_MbedTLS_VERSION)\n      set(MbedTLS_VERSION ${PC_MbedTLS_VERSION})\n    else()\n      # version unknown\n      set(MbedTLS_VERSION \"0.0\")\n    endif()\n  endif()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(MbedTLS\n  FOUND_VAR MbedTLS_FOUND\n  REQUIRED_VARS\n    MbedTLS_LIBRARY\n    MbedTLS_INCLUDE_DIR\n  VERSION_VAR MbedTLS_VERSION\n)\n\nif(MbedTLS_FOUND)\n  set(MbedTLS_LIBRARIES ${MbedTLS_LIBRARY})\n  set(MbedTLS_INCLUDE_DIRS ${MbedTLS_INCLUDE_DIR})\n#  set(MbedTLS_DEFINITIONS ${PC_MbedTLS_CFLAGS_OTHER})\nendif()\n\nif(MbedTLS_FOUND AND NOT TARGET MbedTLS::MbedTLS)\n  add_library(MbedTLS::MbedTLS UNKNOWN IMPORTED)\n  set_target_properties(MbedTLS::MbedTLS PROPERTIES\n    IMPORTED_LOCATION \"${MbedTLS_LIBRARY}\"\n#    INTERFACE_COMPILE_OPTIONS \"${PC_MbedTLS_CFLAGS_OTHER}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${MbedTLS_INCLUDE_DIR}\"\n  )\nendif()\n\nmark_as_advanced(\n  MbedTLS_INCLUDE_DIR\n  MbedTLS_LIBRARY\n  )\n"
  },
  {
    "path": "external/libzip/cmake/FindNettle.cmake",
    "content": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# 1. Redistributions of source code must retain the above copyright\n#   notice, this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#   notice, this list of conditions and the following disclaimer in\n#   the documentation and/or other materials provided with the\n#   distribution.\n#\n# 3. The names of the authors may not be used to endorse or promote\n#   products derived from this software without specific prior\n#   written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#[=======================================================================[.rst:\nFindNettle\n-------\n\nFinds the Nettle library.\n\nImported Targets\n^^^^^^^^^^^^^^^^\n\nThis module provides the following imported targets, if found:\n\n``Nettle::Nettle``\n  The Nettle library\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\nThis will define the following variables:\n\n``Nettle_FOUND``\n  True if the system has the Nettle library.\n``Nettle_VERSION``\n  The version of the Nettle library which was found.\n``Nettle_INCLUDE_DIRS``\n  Include directories needed to use Nettle.\n``Nettle_LIBRARIES``\n  Libraries needed to link to Nettle.\n\nCache Variables\n^^^^^^^^^^^^^^^\n\nThe following cache variables may also be set:\n\n``Nettle_INCLUDE_DIR``\n  The directory containing ``nettle/aes.h``.\n``Nettle_LIBRARY``\n  The path to the Nettle library.\n\n#]=======================================================================]\n\nfind_package(PkgConfig)\npkg_check_modules(PC_Nettle QUIET nettle)\n\nfind_path(Nettle_INCLUDE_DIR\n  NAMES nettle/aes.h nettle/md5.h nettle/pbkdf2.h nettle/ripemd160.h nettle/sha.h\n  PATHS ${PC_Nettle_INCLUDE_DIRS}\n)\nfind_library(Nettle_LIBRARY\n  NAMES nettle\n  PATHS ${PC_Nettle_LIBRARY_DIRS}\n)\n\nif(Nettle_INCLUDE_DIR)\n  if(PC_Nettle_VERSION)\n    set(Nettle_VERSION ${PC_Nettle_VERSION})\n  elseif(EXISTS ${Nettle_INCLUDE_DIR}/nettle/version.h)\n    # Extract version information from the header file\n    # This file only exists in nettle>=3.0\n    file(STRINGS ${Nettle_INCLUDE_DIR}/nettle/version.h _ver_major_line\n         REGEX \"^#define NETTLE_VERSION_MAJOR  *[0-9]+\"\n         LIMIT_COUNT 1)\n    string(REGEX MATCH \"[0-9]+\"\n           Nettle_MAJOR_VERSION \"${_ver_major_line}\")\n    file(STRINGS ${Nettle_INCLUDE_DIR}/nettle/version.h _ver_minor_line\n         REGEX \"^#define NETTLE_VERSION_MINOR  *[0-9]+\"\n         LIMIT_COUNT 1)\n    string(REGEX MATCH \"[0-9]+\"\n           Nettle_MINOR_VERSION \"${_ver_minor_line}\")\n    set(Nettle_VERSION \"${Nettle_MAJOR_VERSION}.${Nettle_MINOR_VERSION}\")\n    unset(_ver_major_line)\n    unset(_ver_minor_line)\n  else()\n    set(Nettle_VERSION \"1.0\")\n  endif()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(Nettle\n  FOUND_VAR Nettle_FOUND\n  REQUIRED_VARS\n    Nettle_LIBRARY\n    Nettle_INCLUDE_DIR\n  VERSION_VAR Nettle_VERSION\n)\n\nif(Nettle_FOUND)\n  set(Nettle_LIBRARIES ${Nettle_LIBRARY})\n  set(Nettle_INCLUDE_DIRS ${Nettle_INCLUDE_DIR})\n  set(Nettle_DEFINITIONS ${PC_Nettle_CFLAGS_OTHER})\nendif()\n\nif(Nettle_FOUND AND NOT TARGET Nettle::Nettle)\n  add_library(Nettle::Nettle UNKNOWN IMPORTED)\n  set_target_properties(Nettle::Nettle PROPERTIES\n    IMPORTED_LOCATION \"${Nettle_LIBRARY}\"\n    INTERFACE_COMPILE_OPTIONS \"${PC_Nettle_CFLAGS_OTHER}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${Nettle_INCLUDE_DIR}\"\n  )\nendif()\n\nmark_as_advanced(\n  Nettle_INCLUDE_DIR\n  Nettle_LIBRARY\n)\n\n# compatibility variables\nset(Nettle_VERSION_STRING ${Nettle_VERSION})\n"
  },
  {
    "path": "external/libzip/cmake/Findzstd.cmake",
    "content": "# Copyright (C) 2020 Dieter Baron and Thomas Klausner\n#\n# The authors can be contacted at <info@libzip.org>\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# 1. Redistributions of source code must retain the above copyright\n#   notice, this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#   notice, this list of conditions and the following disclaimer in\n#   the documentation and/or other materials provided with the\n#   distribution.\n#\n# 3. The names of the authors may not be used to endorse or promote\n#   products derived from this software without specific prior\n#   written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#[=======================================================================[.rst:\nFindzstd\n-------\n\nFinds the Zstandard (zstd) library.\n\nImported Targets\n^^^^^^^^^^^^^^^^\n\nThis module provides the following imported targets, if found:\n\n``zstd::libzstd_shared``\n  The shared Zstandard library\n``zstd::libzstd_static``\n  The shared Zstandard library\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\nThis will define the following variables:\n\n``zstd_FOUND``\n  True if the system has the Zstandard library.\n``zstd_VERSION``\n  The version of the Zstandard library which was found.\n\nCache Variables\n^^^^^^^^^^^^^^^\n\nThe following cache variables may also be set:\n\n``zstd_INCLUDE_DIR``\n  The directory containing ``zstd.h``.\n``zstd_STATIC_LIBRARY``\n  The path to the Zstandard static library.\n``zstd_SHARED_LIBRARY``\n  The path to the Zstandard shared library.\n``zstd_DLL``\n  The path to the Zstandard DLL.\n\n#]=======================================================================]\n\nfind_package(PkgConfig)\npkg_check_modules(PC_zstd QUIET libzstd)\n\nfind_path(zstd_INCLUDE_DIR\n  NAMES zstd.h\n  HINTS ${PC_zstd_INCLUDE_DIRS}\n)\n\nfind_file(zstd_DLL\n  NAMES libzstd.dll zstd.dll\n  PATH_SUFFIXES bin\n  HINTS ${PC_zstd_PREFIX}\n)\n\n# On Windows, we manually define the library names to avoid mistaking the\n# implib for the static library\nif(zstd_DLL)\n  set(_zstd_win_static_name zstd-static)\n  set(_zstd_win_shared_name zstd)\nelse()\n  # vcpkg removes the -static suffix in static builds\n  set(_zstd_win_static_name zstd zstd_static)\n  set(_zstd_win_shared_name)\nendif()\n\nset(_previous_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES})\nset(CMAKE_FIND_LIBRARY_SUFFIXES \".so\" \".dylib\" \".dll.a\" \".lib\")\nfind_library(zstd_SHARED_LIBRARY\n  NAMES zstd ${_zstd_win_shared_name}\n  HINTS ${PC_zstd_LIBDIR}\n)\n\nset(CMAKE_FIND_LIBRARY_SUFFIXES \".a\" \".lib\")\nfind_library(zstd_STATIC_LIBRARY\n  NAMES zstd ${_zstd_win_static_name}\n  HINTS ${PC_zstd_LIBDIR}\n)\nset(CMAKE_FIND_LIBRARY_SUFFIXES ${_previous_suffixes})\n\n# Set zstd_LIBRARY to the shared library or fall back to the static library\nif(zstd_SHARED_LIBRARY)\n  set(_zstd_LIBRARY ${zstd_SHARED_LIBRARY})\nelse()\n  set(_zstd_LIBRARY ${zstd_STATIC_LIBRARY})\nendif()\n\n# Extract version information from the header file\nif(zstd_INCLUDE_DIR)\n  file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_major_line\n    REGEX \"^#define ZSTD_VERSION_MAJOR  *[0-9]+\"\n    LIMIT_COUNT 1)\n  string(REGEX MATCH \"[0-9]+\"\n    zstd_MAJOR_VERSION \"${_ver_major_line}\")\n  file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_minor_line\n    REGEX \"^#define ZSTD_VERSION_MINOR  *[0-9]+\"\n    LIMIT_COUNT 1)\n  string(REGEX MATCH \"[0-9]+\"\n    zstd_MINOR_VERSION \"${_ver_minor_line}\")\n  file(STRINGS ${zstd_INCLUDE_DIR}/zstd.h _ver_release_line\n    REGEX \"^#define ZSTD_VERSION_RELEASE  *[0-9]+\"\n    LIMIT_COUNT 1)\n  string(REGEX MATCH \"[0-9]+\"\n    zstd_RELEASE_VERSION \"${_ver_release_line}\")\n  set(Zstd_VERSION \"${zstd_MAJOR_VERSION}.${zstd_MINOR_VERSION}.${zstd_RELEASE_VERSION}\")\n  unset(_ver_major_line)\n  unset(_ver_minor_line)\n  unset(_ver_release_line)\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(zstd\n  FOUND_VAR zstd_FOUND\n  REQUIRED_VARS\n    _zstd_LIBRARY\n    zstd_INCLUDE_DIR\n  VERSION_VAR zstd_VERSION\n)\n\nif(zstd_FOUND AND zstd_SHARED_LIBRARY AND NOT TARGET zstd::libzstd_shared)\n  add_library(zstd::libzstd_shared SHARED IMPORTED)\n  if(WIN32)\n    set_target_properties(zstd::libzstd_shared PROPERTIES\n      IMPORTED_LOCATION \"${zstd_DLL}\"\n      IMPORTED_IMPLIB \"${zstd_SHARED_LIBRARY}\"\n    )\n  else()\n    set_target_properties(zstd::libzstd_shared PROPERTIES\n      IMPORTED_LOCATION \"${zstd_SHARED_LIBRARY}\"\n    )\n  endif()\n\n  set_target_properties(zstd::libzstd_shared PROPERTIES\n    INTERFACE_COMPILE_OPTIONS \"${PC_zstd_CFLAGS_OTHER}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${zstd_INCLUDE_DIR}\"\n  )\nendif()\n\nif(zstd_FOUND AND zstd_STATIC_LIBRARY AND NOT TARGET zstd::libzstd_static)\n  add_library(zstd::libzstd_static STATIC IMPORTED)\n  set_target_properties(zstd::libzstd_static PROPERTIES\n    IMPORTED_LOCATION \"${zstd_STATIC_LIBRARY}\"\n    INTERFACE_COMPILE_OPTIONS \"${PC_zstd_CFLAGS_OTHER}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${zstd_INCLUDE_DIR}\"\n  )\nendif()\n\nmark_as_advanced(\n  zstd_INCLUDE_DIR\n  zstd_DLL\n  zstd_SHARED_LIBRARY\n  zstd_STATIC_LIBRARY\n)\n"
  },
  {
    "path": "external/libzip/cmake/GenerateZipErrorStrings.cmake",
    "content": "# create zip_err_str.c from zip.h and zipint.h\nfile(READ ${PROJECT_SOURCE_DIR}/lib/zip.h zip_h)\nstring(REGEX MATCHALL \"#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \\t]+/([-*0-9a-zA-Z, ']*)/\" zip_h_err ${zip_h})\nfile(READ ${PROJECT_SOURCE_DIR}/lib/zipint.h zipint_h)\nstring(REGEX MATCHALL \"#define ZIP_ER_DETAIL_([A-Z0-9_]+) ([0-9]+)[ \\t]+/([-*0-9a-zA-Z, ']*)/\" zipint_h_err ${zipint_h})\nset(zip_err_str [=[\n/*\n  This file was generated automatically by CMake\n  from zip.h and zipint.h\\; make changes there.\n*/\n\n#include \"zipint.h\"\n\n#define L ZIP_ET_LIBZIP\n#define N ZIP_ET_NONE\n#define S ZIP_ET_SYS\n#define Z ZIP_ET_ZLIB\n\n#define E ZIP_DETAIL_ET_ENTRY\n#define G ZIP_DETAIL_ET_GLOBAL\n\nconst struct _zip_err_info _zip_err_str[] = {\n]=])\nset(zip_err_type)\nforeach(errln ${zip_h_err})\n  string(REGEX MATCH \"#define ZIP_ER_([A-Z0-9_]+) ([0-9]+)[ \\t]+/([-*0-9a-zA-Z, ']*)/\" err_t_tt ${errln})\n  string(REGEX MATCH \"([L|N|S|Z]+) ([-0-9a-zA-Z,, ']*)\" err_t_tt \"${CMAKE_MATCH_3}\")\n  string(STRIP \"${CMAKE_MATCH_2}\" err_t_tt)\n  string(APPEND zip_err_str \"    { ${CMAKE_MATCH_1}, \\\"${err_t_tt}\\\" },\\n\")\nendforeach()\nstring(APPEND zip_err_str [=[}\\;\n\nconst int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0])\\;\n\nconst struct _zip_err_info _zip_err_details[] = {\n]=])\nforeach(errln ${zipint_h_err})\n  string(REGEX MATCH \"#define ZIP_ER_DETAIL_([A-Z0-9_]+) ([0-9]+)[ \\t]+/([-*0-9a-zA-Z, ']*)/\" err_t_tt ${errln})\n  string(REGEX MATCH \"([E|G]+) ([-0-9a-zA-Z, ']*)\" err_t_tt \"${CMAKE_MATCH_3}\")\n  string(STRIP \"${CMAKE_MATCH_2}\" err_t_tt)\n  string(APPEND zip_err_str \"    { ${CMAKE_MATCH_1}, \\\"${err_t_tt}\\\" },\\n\")\nendforeach()\nstring(APPEND zip_err_str [=[}\\;\n\nconst int _zip_err_details_count = sizeof(_zip_err_details)/sizeof(_zip_err_details[0])\\;\n]=])\nfile(WRITE ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c ${zip_err_str})\n"
  },
  {
    "path": "external/libzip/cmake-compat/CMakePushCheckState.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nCMakePushCheckState\n-------------------\n\n\n\nThis module defines three macros: ``CMAKE_PUSH_CHECK_STATE()``\n``CMAKE_POP_CHECK_STATE()`` and ``CMAKE_RESET_CHECK_STATE()`` These macros can\nbe used to save, restore and reset (i.e., clear contents) the state of\nthe variables ``CMAKE_REQUIRED_FLAGS``, ``CMAKE_REQUIRED_DEFINITIONS``,\n``CMAKE_REQUIRED_LINK_OPTIONS``, ``CMAKE_REQUIRED_LIBRARIES``,\n``CMAKE_REQUIRED_INCLUDES`` and ``CMAKE_EXTRA_INCLUDE_FILES`` used by the\nvarious Check-files coming with CMake, like e.g. ``check_function_exists()``\netc.\nThe variable contents are pushed on a stack, pushing multiple times is\nsupported.  This is useful e.g.  when executing such tests in a Find-module,\nwhere they have to be set, but after the Find-module has been executed they\nshould have the same value as they had before.\n\n``CMAKE_PUSH_CHECK_STATE()`` macro receives optional argument ``RESET``.\nWhether it's specified, ``CMAKE_PUSH_CHECK_STATE()`` will set all\n``CMAKE_REQUIRED_*`` variables to empty values, same as\n``CMAKE_RESET_CHECK_STATE()`` call will do.\n\nUsage:\n\n.. code-block:: cmake\n\n   cmake_push_check_state(RESET)\n   set(CMAKE_REQUIRED_DEFINITIONS -DSOME_MORE_DEF)\n   check_function_exists(...)\n   cmake_reset_check_state()\n   set(CMAKE_REQUIRED_DEFINITIONS -DANOTHER_DEF)\n   check_function_exists(...)\n   cmake_pop_check_state()\n#]=======================================================================]\n\nmacro(CMAKE_RESET_CHECK_STATE)\n\n  set(CMAKE_EXTRA_INCLUDE_FILES)\n  set(CMAKE_REQUIRED_INCLUDES)\n  set(CMAKE_REQUIRED_DEFINITIONS)\n  set(CMAKE_REQUIRED_LINK_OPTIONS)\n  set(CMAKE_REQUIRED_LIBRARIES)\n  set(CMAKE_REQUIRED_FLAGS)\n  set(CMAKE_REQUIRED_QUIET)\n\nendmacro()\n\nmacro(CMAKE_PUSH_CHECK_STATE)\n\n  if(NOT DEFINED _CMAKE_PUSH_CHECK_STATE_COUNTER)\n    set(_CMAKE_PUSH_CHECK_STATE_COUNTER 0)\n  endif()\n\n  math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER \"${_CMAKE_PUSH_CHECK_STATE_COUNTER}+1\")\n\n  set(_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}    ${CMAKE_EXTRA_INCLUDE_FILES})\n  set(_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}      ${CMAKE_REQUIRED_INCLUDES})\n  set(_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}   ${CMAKE_REQUIRED_DEFINITIONS})\n  set(_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}  ${CMAKE_REQUIRED_LINK_OPTIONS})\n  set(_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}     ${CMAKE_REQUIRED_LIBRARIES})\n  set(_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}         ${CMAKE_REQUIRED_FLAGS})\n  set(_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}         ${CMAKE_REQUIRED_QUIET})\n\n  if (${ARGC} GREATER 0 AND \"${ARGV0}\" STREQUAL \"RESET\")\n    cmake_reset_check_state()\n  endif()\n\nendmacro()\n\nmacro(CMAKE_POP_CHECK_STATE)\n\n# don't pop more than we pushed\n  if(\"${_CMAKE_PUSH_CHECK_STATE_COUNTER}\" GREATER \"0\")\n\n    set(CMAKE_EXTRA_INCLUDE_FILES    ${_CMAKE_EXTRA_INCLUDE_FILES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_INCLUDES      ${_CMAKE_REQUIRED_INCLUDES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_DEFINITIONS   ${_CMAKE_REQUIRED_DEFINITIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_LINK_OPTIONS  ${_CMAKE_REQUIRED_LINK_OPTIONS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_LIBRARIES     ${_CMAKE_REQUIRED_LIBRARIES_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_FLAGS         ${_CMAKE_REQUIRED_FLAGS_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n    set(CMAKE_REQUIRED_QUIET         ${_CMAKE_REQUIRED_QUIET_SAVE_${_CMAKE_PUSH_CHECK_STATE_COUNTER}})\n\n    math(EXPR _CMAKE_PUSH_CHECK_STATE_COUNTER \"${_CMAKE_PUSH_CHECK_STATE_COUNTER}-1\")\n  endif()\n\nendmacro()\n"
  },
  {
    "path": "external/libzip/cmake-compat/CheckLibraryExists.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nCheckLibraryExists\n------------------\n\nCheck if the function exists.\n\n.. command:: CHECK_LIBRARY_EXISTS\n\n  .. code-block:: cmake\n\n    CHECK_LIBRARY_EXISTS(LIBRARY FUNCTION LOCATION VARIABLE)\n\n  ::\n\n    LIBRARY  - the name of the library you are looking for\n    FUNCTION - the name of the function\n    LOCATION - location where the library should be found\n    VARIABLE - variable to store the result\n               Will be created as an internal cache variable.\n\n\n\nThe following variables may be set before calling this macro to modify\nthe way the check is run:\n\n::\n\n  CMAKE_REQUIRED_FLAGS = string of compile command line flags\n  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)\n  CMAKE_REQUIRED_LINK_OPTIONS = list of options to pass to link command\n  CMAKE_REQUIRED_LIBRARIES = list of libraries to link\n  CMAKE_REQUIRED_QUIET = execute quietly without messages\n#]=======================================================================]\n\nif(__CheckLibraryExists_cmake__)\n  return()\nendif()\nset(__CheckLibraryExists_cmake__ TRUE)\n\nmacro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE)\n  if(NOT DEFINED \"${VARIABLE}\")\n    set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION\n      \"-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}\")\n    if(NOT CMAKE_REQUIRED_QUIET)\n      message(CHECK_START \"Looking for ${FUNCTION} in ${LIBRARY}\")\n    endif()\n    set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS)\n    if(CMAKE_REQUIRED_LINK_OPTIONS)\n      set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS\n        LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})\n    endif()\n    set(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY})\n    if(CMAKE_REQUIRED_LIBRARIES)\n      set(CHECK_LIBRARY_EXISTS_LIBRARIES\n        ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES})\n    endif()\n\n    if(CMAKE_C_COMPILER_LOADED)\n      set(_cle_source ${CMAKE_ROOT}/Modules/CheckFunctionExists.c)\n    elseif(CMAKE_CXX_COMPILER_LOADED)\n      set(_cle_source ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CheckLibraryExists/CheckFunctionExists.cxx)\n      configure_file(${CMAKE_ROOT}/Modules/CheckFunctionExists.c \"${_cle_source}\" COPYONLY)\n    else()\n      message(FATAL_ERROR \"CHECK_FUNCTION_EXISTS needs either C or CXX language enabled\")\n    endif()\n\n    try_compile(${VARIABLE}\n      ${CMAKE_BINARY_DIR}\n      ${_cle_source}\n      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}\n      ${CHECK_LIBRARY_EXISTS_LINK_OPTIONS}\n      LINK_LIBRARIES ${CHECK_LIBRARY_EXISTS_LIBRARIES}\n      CMAKE_FLAGS\n      -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}\n      -DLINK_DIRECTORIES:STRING=${LOCATION}\n      OUTPUT_VARIABLE OUTPUT)\n    unset(_cle_source)\n\n    if(${VARIABLE})\n      if(NOT CMAKE_REQUIRED_QUIET)\n        message(CHECK_PASS \"found\")\n      endif()\n      set(${VARIABLE} 1 CACHE INTERNAL \"Have library ${LIBRARY}\")\n      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log\n        \"Determining if the function ${FUNCTION} exists in the ${LIBRARY} \"\n        \"passed with the following output:\\n\"\n        \"${OUTPUT}\\n\\n\")\n    else()\n      if(NOT CMAKE_REQUIRED_QUIET)\n        message(CHECK_FAIL \"not found\")\n      endif()\n      set(${VARIABLE} \"\" CACHE INTERNAL \"Have library ${LIBRARY}\")\n      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log\n        \"Determining if the function ${FUNCTION} exists in the ${LIBRARY} \"\n        \"failed with the following output:\\n\"\n        \"${OUTPUT}\\n\\n\")\n    endif()\n  endif()\nendmacro()\n"
  },
  {
    "path": "external/libzip/cmake-compat/CheckSymbolExists.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nCheckSymbolExists\n-----------------\n\nProvides a macro to check if a symbol exists as a function, variable,\nor macro in ``C``.\n\n.. command:: check_symbol_exists\n\n  .. code-block:: cmake\n\n    check_symbol_exists(<symbol> <files> <variable>)\n\n  Check that the ``<symbol>`` is available after including given header\n  ``<files>`` and store the result in a ``<variable>``.  Specify the list\n  of files in one argument as a semicolon-separated list.\n  ``<variable>`` will be created as an internal cache variable.\n\nIf the header files define the symbol as a macro it is considered\navailable and assumed to work.  If the header files declare the symbol\nas a function or variable then the symbol must also be available for\nlinking (so intrinsics may not be detected).\nIf the symbol is a type, enum value, or intrinsic it will not be recognized\n(consider using :module:`CheckTypeSize` or :module:`CheckCSourceCompiles`).\nIf the check needs to be done in C++, consider using\n:module:`CheckCXXSymbolExists` instead.\n\nThe following variables may be set before calling this macro to modify\nthe way the check is run:\n\n``CMAKE_REQUIRED_FLAGS``\n  string of compile command line flags.\n``CMAKE_REQUIRED_DEFINITIONS``\n  a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar).\n``CMAKE_REQUIRED_INCLUDES``\n  a :ref:`;-list <CMake Language Lists>` of header search paths to pass to\n  the compiler.\n``CMAKE_REQUIRED_LINK_OPTIONS``\n  a :ref:`;-list <CMake Language Lists>` of options to add to the link command.\n``CMAKE_REQUIRED_LIBRARIES``\n  a :ref:`;-list <CMake Language Lists>` of libraries to add to the link\n  command. See policy :policy:`CMP0075`.\n``CMAKE_REQUIRED_QUIET``\n  execute quietly without messages.\n\nFor example:\n\n.. code-block:: cmake\n\n  include(CheckSymbolExists)\n\n  # Check for macro SEEK_SET\n  check_symbol_exists(SEEK_SET \"stdio.h\" HAVE_SEEK_SET)\n  # Check for function fopen\n  check_symbol_exists(fopen \"stdio.h\" HAVE_FOPEN)\n#]=======================================================================]\n\nif(__CheckSymbolExists_cmake__)\n  return()\nendif()\nset(__CheckSymbolExists_cmake__ TRUE)\n\ncmake_policy(PUSH)\ncmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced\n\nmacro(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE)\n  if(CMAKE_C_COMPILER_LOADED)\n    __CHECK_SYMBOL_EXISTS_IMPL(\"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c\" \"${SYMBOL}\" \"${FILES}\" \"${VARIABLE}\" )\n  elseif(CMAKE_CXX_COMPILER_LOADED)\n    __CHECK_SYMBOL_EXISTS_IMPL(\"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.cxx\" \"${SYMBOL}\" \"${FILES}\" \"${VARIABLE}\" )\n  else()\n    message(FATAL_ERROR \"CHECK_SYMBOL_EXISTS needs either C or CXX language enabled\")\n  endif()\nendmacro()\n\nmacro(__CHECK_SYMBOL_EXISTS_IMPL SOURCEFILE SYMBOL FILES VARIABLE)\n  if(NOT DEFINED \"${VARIABLE}\" OR \"x${${VARIABLE}}\" STREQUAL \"x${VARIABLE}\")\n    set(CMAKE_CONFIGURABLE_FILE_CONTENT \"/* */\\n\")\n    set(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS})\n    if(CMAKE_REQUIRED_LINK_OPTIONS)\n      set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS\n        LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})\n    else()\n      set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS)\n    endif()\n    if(CMAKE_REQUIRED_LIBRARIES)\n      set(CHECK_SYMBOL_EXISTS_LIBS\n        LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})\n    else()\n      set(CHECK_SYMBOL_EXISTS_LIBS)\n    endif()\n    if(CMAKE_REQUIRED_INCLUDES)\n      set(CMAKE_SYMBOL_EXISTS_INCLUDES\n        \"-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}\")\n    else()\n      set(CMAKE_SYMBOL_EXISTS_INCLUDES)\n    endif()\n    foreach(FILE ${FILES})\n      string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT\n        \"#include <${FILE}>\\n\")\n    endforeach()\n    string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT \"\nint main(int argc, char** argv)\n{\n  (void)argv;\")\n    set(_CSE_CHECK_NON_MACRO \"return ((int*)(&${SYMBOL}))[argc];\")\n    if(\"${SYMBOL}\" MATCHES \"^[a-zA-Z_][a-zA-Z0-9_]*$\")\n      # The SYMBOL has a legal macro name.  Test whether it exists as a macro.\n      string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT \"\n#ifndef ${SYMBOL}\n  ${_CSE_CHECK_NON_MACRO}\n#else\n  (void)argc;\n  return 0;\n#endif\")\n    else()\n      # The SYMBOL cannot be a macro (e.g., a template function).\n      string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT \"\n  ${_CSE_CHECK_NON_MACRO}\")\n    endif()\n    string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT \"\n}\")\n    unset(_CSE_CHECK_NON_MACRO)\n\n    configure_file(\"${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in\"\n      \"${SOURCEFILE}\" @ONLY)\n\n    if(NOT CMAKE_REQUIRED_QUIET)\n      message(CHECK_START \"Looking for ${SYMBOL}\")\n    endif()\n    try_compile(${VARIABLE}\n      ${CMAKE_BINARY_DIR}\n      \"${SOURCEFILE}\"\n      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}\n      ${CHECK_SYMBOL_EXISTS_LINK_OPTIONS}\n      ${CHECK_SYMBOL_EXISTS_LIBS}\n      CMAKE_FLAGS\n      -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}\n      \"${CMAKE_SYMBOL_EXISTS_INCLUDES}\"\n      OUTPUT_VARIABLE OUTPUT)\n    if(${VARIABLE})\n      if(NOT CMAKE_REQUIRED_QUIET)\n        message(CHECK_PASS \"found\")\n      endif()\n      set(${VARIABLE} 1 CACHE INTERNAL \"Have symbol ${SYMBOL}\")\n      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log\n        \"Determining if the ${SYMBOL} \"\n        \"exist passed with the following output:\\n\"\n        \"${OUTPUT}\\nFile ${SOURCEFILE}:\\n\"\n        \"${CMAKE_CONFIGURABLE_FILE_CONTENT}\\n\")\n    else()\n      if(NOT CMAKE_REQUIRED_QUIET)\n        message(CHECK_FAIL \"not found\")\n      endif()\n      set(${VARIABLE} \"\" CACHE INTERNAL \"Have symbol ${SYMBOL}\")\n      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log\n        \"Determining if the ${SYMBOL} \"\n        \"exist failed with the following output:\\n\"\n        \"${OUTPUT}\\nFile ${SOURCEFILE}:\\n\"\n        \"${CMAKE_CONFIGURABLE_FILE_CONTENT}\\n\")\n    endif()\n    unset(CMAKE_CONFIGURABLE_FILE_CONTENT)\n  endif()\nendmacro()\n\ncmake_policy(POP)\n"
  },
  {
    "path": "external/libzip/cmake-compat/FindBZip2.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindBZip2\n---------\n\nTry to find BZip2\n\nIMPORTED Targets\n^^^^^^^^^^^^^^^^\n\nThis module defines :prop_tgt:`IMPORTED` target ``BZip2::BZip2``, if\nBZip2 has been found.\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\nThis module defines the following variables:\n\n``BZIP2_FOUND``\n  system has BZip2\n``BZIP2_INCLUDE_DIRS``\n  the BZip2 include directories\n``BZIP2_LIBRARIES``\n  Link these to use BZip2\n``BZIP2_NEED_PREFIX``\n  this is set if the functions are prefixed with ``BZ2_``\n``BZIP2_VERSION_STRING``\n  the version of BZip2 found\n\nCache variables\n^^^^^^^^^^^^^^^\n\nThe following cache variables may also be set:\n\n``BZIP2_INCLUDE_DIR``\n  the BZip2 include directory\n#]=======================================================================]\n\nset(_BZIP2_PATHS PATHS\n  \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\GnuWin32\\\\Bzip2;InstallPath]\"\n  )\n\nfind_path(BZIP2_INCLUDE_DIR bzlib.h ${_BZIP2_PATHS} PATH_SUFFIXES include)\n\nif (NOT BZIP2_LIBRARIES)\n    find_library(BZIP2_LIBRARY_RELEASE NAMES bz2 bzip2 libbz2 libbzip2 ${_BZIP2_PATHS} PATH_SUFFIXES lib)\n    find_library(BZIP2_LIBRARY_DEBUG NAMES bz2d bzip2d libbz2d libbzip2d ${_BZIP2_PATHS} PATH_SUFFIXES lib)\n\n    include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)\n    SELECT_LIBRARY_CONFIGURATIONS(BZIP2)\nelse ()\n    file(TO_CMAKE_PATH \"${BZIP2_LIBRARIES}\" BZIP2_LIBRARIES)\nendif ()\n\nif (BZIP2_INCLUDE_DIR AND EXISTS \"${BZIP2_INCLUDE_DIR}/bzlib.h\")\n    file(STRINGS \"${BZIP2_INCLUDE_DIR}/bzlib.h\" BZLIB_H REGEX \"bzip2/libbzip2 version [0-9]+\\\\.[^ ]+ of [0-9]+ \")\n    string(REGEX REPLACE \".* bzip2/libbzip2 version ([0-9]+\\\\.[^ ]+) of [0-9]+ .*\" \"\\\\1\" BZIP2_VERSION_STRING \"${BZLIB_H}\")\nendif ()\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(BZip2\n                                  REQUIRED_VARS BZIP2_LIBRARIES BZIP2_INCLUDE_DIR\n                                  VERSION_VAR BZIP2_VERSION_STRING)\n\nif (BZIP2_FOUND)\n  set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})\n  include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake)\n  include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)\n  cmake_push_check_state()\n  set(CMAKE_REQUIRED_QUIET ${BZip2_FIND_QUIETLY})\n  set(CMAKE_REQUIRED_INCLUDES ${BZIP2_INCLUDE_DIR})\n  set(CMAKE_REQUIRED_LIBRARIES ${BZIP2_LIBRARIES})\n  CHECK_SYMBOL_EXISTS(BZ2_bzCompressInit \"bzlib.h\" BZIP2_NEED_PREFIX)\n  cmake_pop_check_state()\n\n  if(NOT TARGET BZip2::BZip2)\n    add_library(BZip2::BZip2 UNKNOWN IMPORTED)\n    set_target_properties(BZip2::BZip2 PROPERTIES\n      INTERFACE_INCLUDE_DIRECTORIES \"${BZIP2_INCLUDE_DIRS}\")\n\n    if(BZIP2_LIBRARY_RELEASE)\n      set_property(TARGET BZip2::BZip2 APPEND PROPERTY\n        IMPORTED_CONFIGURATIONS RELEASE)\n      set_target_properties(BZip2::BZip2 PROPERTIES\n        IMPORTED_LOCATION_RELEASE \"${BZIP2_LIBRARY_RELEASE}\")\n    endif()\n\n    if(BZIP2_LIBRARY_DEBUG)\n      set_property(TARGET BZip2::BZip2 APPEND PROPERTY\n        IMPORTED_CONFIGURATIONS DEBUG)\n      set_target_properties(BZip2::BZip2 PROPERTIES\n        IMPORTED_LOCATION_DEBUG \"${BZIP2_LIBRARY_DEBUG}\")\n    endif()\n\n    if(NOT BZIP2_LIBRARY_RELEASE AND NOT BZIP2_LIBRARY_DEBUG)\n      set_property(TARGET BZip2::BZip2 APPEND PROPERTY\n        IMPORTED_LOCATION \"${BZIP2_LIBRARY}\")\n    endif()\n  endif()\nendif ()\n\nmark_as_advanced(BZIP2_INCLUDE_DIR)\n"
  },
  {
    "path": "external/libzip/cmake-compat/FindGnuTLS.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindGnuTLS\n----------\n\nFind the GNU Transport Layer Security library (gnutls)\n\nIMPORTED Targets\n^^^^^^^^^^^^^^^^\n\nThis module defines :prop_tgt:`IMPORTED` target ``GnuTLS::GnuTLS``, if\ngnutls has been found.\n\nResult Variables\n^^^^^^^^^^^^^^^^\n\n``GNUTLS_FOUND``\n  System has gnutls\n``GNUTLS_INCLUDE_DIR``\n  The gnutls include directory\n``GNUTLS_LIBRARIES``\n  The libraries needed to use gnutls\n``GNUTLS_DEFINITIONS``\n  Compiler switches required for using gnutls\n``GNUTLS_VERSION``\n  version of gnutls.\n#]=======================================================================]\n\n# Note that this doesn't try to find the gnutls-extra package.\n\n\nif (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARY)\n  # in cache already\n  set(gnutls_FIND_QUIETLY TRUE)\nendif ()\n\nif (NOT WIN32)\n  # try using pkg-config to get the directories and then use these values\n  # in the find_path() and find_library() calls\n  # also fills in GNUTLS_DEFINITIONS, although that isn't normally useful\n  find_package(PkgConfig QUIET)\n  PKG_CHECK_MODULES(PC_GNUTLS QUIET gnutls)\n  set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER})\n  set(GNUTLS_VERSION ${PC_GNUTLS_VERSION})\n  # keep for backward compatibility\n  set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION})\nendif ()\n\nfind_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h\n  HINTS\n    ${PC_GNUTLS_INCLUDEDIR}\n    ${PC_GNUTLS_INCLUDE_DIRS}\n  )\n\nfind_library(GNUTLS_LIBRARY NAMES gnutls libgnutls\n  HINTS\n    ${PC_GNUTLS_LIBDIR}\n    ${PC_GNUTLS_LIBRARY_DIRS}\n  )\n\nmark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY)\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(GnuTLS\n                                  REQUIRED_VARS GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR\n                                  VERSION_VAR GNUTLS_VERSION_STRING)\n\nif(GNUTLS_FOUND)\n  set(GNUTLS_LIBRARIES    ${GNUTLS_LIBRARY})\n  set(GNUTLS_INCLUDE_DIRS ${GNUTLS_INCLUDE_DIR})\n\n  if(NOT TARGET GnuTLS::GnuTLS)\n    add_library(GnuTLS::GnuTLS UNKNOWN IMPORTED)\n    set_target_properties(GnuTLS::GnuTLS PROPERTIES\n      INTERFACE_INCLUDE_DIRECTORIES \"${GNUTLS_INCLUDE_DIRS}\"\n      INTERFACE_COMPILE_DEFINITIONS \"${GNUTLS_DEFINITIONS}\"\n      IMPORTED_LINK_INTERFACE_LANGUAGES \"C\"\n      IMPORTED_LOCATION \"${GNUTLS_LIBRARIES}\")\n  endif()\nendif()\n"
  },
  {
    "path": "external/libzip/cmake-compat/FindLibLZMA.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindLibLZMA\n-----------\n\nFind LZMA compression algorithm headers and library.\n\n\nImported Targets\n^^^^^^^^^^^^^^^^\n\nThis module defines :prop_tgt:`IMPORTED` target ``LibLZMA::LibLZMA``, if\nliblzma has been found.\n\nResult variables\n^^^^^^^^^^^^^^^^\n\nThis module will set the following variables in your project:\n\n``LIBLZMA_FOUND``\n  True if liblzma headers and library were found.\n``LIBLZMA_INCLUDE_DIRS``\n  Directory where liblzma headers are located.\n``LIBLZMA_LIBRARIES``\n  Lzma libraries to link against.\n``LIBLZMA_HAS_AUTO_DECODER``\n  True if lzma_auto_decoder() is found (required).\n``LIBLZMA_HAS_EASY_ENCODER``\n  True if lzma_easy_encoder() is found (required).\n``LIBLZMA_HAS_LZMA_PRESET``\n  True if lzma_lzma_preset() is found (required).\n``LIBLZMA_VERSION_MAJOR``\n  The major version of lzma\n``LIBLZMA_VERSION_MINOR``\n  The minor version of lzma\n``LIBLZMA_VERSION_PATCH``\n  The patch version of lzma\n``LIBLZMA_VERSION_STRING``\n  version number as a string (ex: \"5.0.3\")\n#]=======================================================================]\n\nfind_path(LIBLZMA_INCLUDE_DIR lzma.h )\nif(NOT LIBLZMA_LIBRARY)\n  find_library(LIBLZMA_LIBRARY_RELEASE NAMES lzma liblzma PATH_SUFFIXES lib)\n  find_library(LIBLZMA_LIBRARY_DEBUG NAMES lzmad liblzmad PATH_SUFFIXES lib)\n  include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)\n  select_library_configurations(LIBLZMA)\nelse()\n  file(TO_CMAKE_PATH \"${LIBLZMA_LIBRARY}\" LIBLZMA_LIBRARY)\nendif()\n\nif(LIBLZMA_INCLUDE_DIR AND EXISTS \"${LIBLZMA_INCLUDE_DIR}/lzma/version.h\")\n    file(STRINGS \"${LIBLZMA_INCLUDE_DIR}/lzma/version.h\" LIBLZMA_HEADER_CONTENTS REGEX \"#define LZMA_VERSION_[A-Z]+ [0-9]+\")\n\n    string(REGEX REPLACE \".*#define LZMA_VERSION_MAJOR ([0-9]+).*\" \"\\\\1\" LIBLZMA_VERSION_MAJOR \"${LIBLZMA_HEADER_CONTENTS}\")\n    string(REGEX REPLACE \".*#define LZMA_VERSION_MINOR ([0-9]+).*\" \"\\\\1\" LIBLZMA_VERSION_MINOR \"${LIBLZMA_HEADER_CONTENTS}\")\n    string(REGEX REPLACE \".*#define LZMA_VERSION_PATCH ([0-9]+).*\" \"\\\\1\" LIBLZMA_VERSION_PATCH \"${LIBLZMA_HEADER_CONTENTS}\")\n\n    set(LIBLZMA_VERSION_STRING \"${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}\")\n    unset(LIBLZMA_HEADER_CONTENTS)\nendif()\n\n# We're using new code known now as XZ, even library still been called LZMA\n# it can be found in http://tukaani.org/xz/\n# Avoid using old codebase\nif (LIBLZMA_LIBRARY)\n  include(${CMAKE_CURRENT_LIST_DIR}/CheckLibraryExists.cmake)\n  set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})\n  set(CMAKE_REQUIRED_QUIET ${LibLZMA_FIND_QUIETLY})\n  if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)\n    set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY})\n  elseif(LIBLZMA_LIBRARY_RELEASE)\n    set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_RELEASE})\n  elseif(LIBLZMA_LIBRARY_DEBUG)\n    set(LIBLZMA_LIBRARY_check ${LIBLZMA_LIBRARY_DEBUG})\n  endif()\n  CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_auto_decoder \"\" LIBLZMA_HAS_AUTO_DECODER)\n  CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_easy_encoder \"\" LIBLZMA_HAS_EASY_ENCODER)\n  CHECK_LIBRARY_EXISTS(${LIBLZMA_LIBRARY_check} lzma_lzma_preset \"\" LIBLZMA_HAS_LZMA_PRESET)\n  unset(LIBLZMA_LIBRARY_check)\n  set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})\nendif ()\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)\nfind_package_handle_standard_args(LibLZMA  REQUIRED_VARS  LIBLZMA_LIBRARY\n                                                          LIBLZMA_INCLUDE_DIR\n                                                          LIBLZMA_HAS_AUTO_DECODER\n                                                          LIBLZMA_HAS_EASY_ENCODER\n                                                          LIBLZMA_HAS_LZMA_PRESET\n                                           VERSION_VAR    LIBLZMA_VERSION_STRING\n                                 )\nmark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY )\n\nif (LIBLZMA_FOUND)\n    set(LIBLZMA_LIBRARIES ${LIBLZMA_LIBRARY})\n    set(LIBLZMA_INCLUDE_DIRS ${LIBLZMA_INCLUDE_DIR})\n    if(NOT TARGET LibLZMA::LibLZMA)\n        add_library(LibLZMA::LibLZMA UNKNOWN IMPORTED)\n        set_target_properties(LibLZMA::LibLZMA PROPERTIES\n                              INTERFACE_INCLUDE_DIRECTORIES ${LIBLZMA_INCLUDE_DIR}\n                              IMPORTED_LINK_INTERFACE_LANGUAGES C)\n\n        if(LIBLZMA_LIBRARY_RELEASE)\n            set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY\n                IMPORTED_CONFIGURATIONS RELEASE)\n            set_target_properties(LibLZMA::LibLZMA PROPERTIES\n                IMPORTED_LOCATION_RELEASE \"${LIBLZMA_LIBRARY_RELEASE}\")\n        endif()\n\n        if(LIBLZMA_LIBRARY_DEBUG)\n            set_property(TARGET LibLZMA::LibLZMA APPEND PROPERTY\n                IMPORTED_CONFIGURATIONS DEBUG)\n            set_target_properties(LibLZMA::LibLZMA PROPERTIES\n                IMPORTED_LOCATION_DEBUG \"${LIBLZMA_LIBRARY_DEBUG}\")\n        endif()\n\n        if(NOT LIBLZMA_LIBRARY_RELEASE AND NOT LIBLZMA_LIBRARY_DEBUG)\n            set_target_properties(LibLZMA::LibLZMA PROPERTIES\n                IMPORTED_LOCATION \"${LIBLZMA_LIBRARY}\")\n        endif()\n    endif()\nendif ()\n"
  },
  {
    "path": "external/libzip/cmake-compat/FindPackageHandleStandardArgs.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindPackageHandleStandardArgs\n-----------------------------\n\nThis module provides a function intended to be used in :ref:`Find Modules`\nimplementing :command:`find_package(<PackageName>)` calls.  It handles the\n``REQUIRED``, ``QUIET`` and version-related arguments of ``find_package``.\nIt also sets the ``<PackageName>_FOUND`` variable.  The package is\nconsidered found if all variables listed contain valid results, e.g.\nvalid filepaths.\n\n.. command:: find_package_handle_standard_args\n\n  There are two signatures::\n\n    find_package_handle_standard_args(<PackageName>\n      (DEFAULT_MSG|<custom-failure-message>)\n      <required-var>...\n      )\n\n    find_package_handle_standard_args(<PackageName>\n      [FOUND_VAR <result-var>]\n      [REQUIRED_VARS <required-var>...]\n      [VERSION_VAR <version-var>]\n      [HANDLE_COMPONENTS]\n      [CONFIG_MODE]\n      [NAME_MISMATCHED]\n      [REASON_FAILURE_MESSAGE <reason-failure-message>]\n      [FAIL_MESSAGE <custom-failure-message>]\n      )\n\n  The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all\n  the variables ``<required-var>...`` are valid and any optional\n  constraints are satisfied, and ``FALSE`` otherwise.  A success or\n  failure message may be displayed based on the results and on\n  whether the ``REQUIRED`` and/or ``QUIET`` option was given to\n  the :command:`find_package` call.\n\n  The options are:\n\n  ``(DEFAULT_MSG|<custom-failure-message>)``\n    In the simple signature this specifies the failure message.\n    Use ``DEFAULT_MSG`` to ask for a default message to be computed\n    (recommended).  Not valid in the full signature.\n\n  ``FOUND_VAR <result-var>``\n    Obsolete.  Specifies either ``<PackageName>_FOUND`` or\n    ``<PACKAGENAME>_FOUND`` as the result variable.  This exists only\n    for compatibility with older versions of CMake and is now ignored.\n    Result variables of both names are always set for compatibility.\n\n  ``REQUIRED_VARS <required-var>...``\n    Specify the variables which are required for this package.\n    These may be named in the generated failure message asking the\n    user to set the missing variable values.  Therefore these should\n    typically be cache entries such as ``FOO_LIBRARY`` and not output\n    variables like ``FOO_LIBRARIES``.\n\n  ``VERSION_VAR <version-var>``\n    Specify the name of a variable that holds the version of the package\n    that has been found.  This version will be checked against the\n    (potentially) specified required version given to the\n    :command:`find_package` call, including its ``EXACT`` option.\n    The default messages include information about the required\n    version and the version which has been actually found, both\n    if the version is ok or not.\n\n  ``HANDLE_COMPONENTS``\n    Enable handling of package components.  In this case, the command\n    will report which components have been found and which are missing,\n    and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``\n    if any of the required components (i.e. not the ones listed after\n    the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are\n    missing.\n\n  ``CONFIG_MODE``\n    Specify that the calling find module is a wrapper around a\n    call to ``find_package(<PackageName> NO_MODULE)``.  This implies\n    a ``VERSION_VAR`` value of ``<PackageName>_VERSION``.  The command\n    will automatically check whether the package configuration file\n    was found.\n\n  ``REASON_FAILURE_MESSAGE <reason-failure-message>``\n    Specify a custom message of the reason for the failure which will be\n    appended to the default generated message.\n\n  ``FAIL_MESSAGE <custom-failure-message>``\n    Specify a custom failure message instead of using the default\n    generated message.  Not recommended.\n\n  ``NAME_MISMATCHED``\n    Indicate that the ``<PackageName>`` does not match\n    ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a\n    warning, but it may be intentional for usage of the command for components\n    of a larger package.\n\nExample for the simple signature:\n\n.. code-block:: cmake\n\n  find_package_handle_standard_args(LibXml2 DEFAULT_MSG\n    LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)\n\nThe ``LibXml2`` package is considered to be found if both\n``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.\nThen also ``LibXml2_FOUND`` is set to ``TRUE``.  If it is not found\nand ``REQUIRED`` was used, it fails with a\n:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was\nused or not.  If it is found, success will be reported, including\nthe content of the first ``<required-var>``.  On repeated CMake runs,\nthe same message will not be printed again.\n\n.. note::\n\n  If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the\n  calling module, a warning that there is a mismatch is given. The\n  ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using\n  the old signature and the ``NAME_MISMATCHED`` argument using the new\n  signature. To avoid forcing the caller to require newer versions of CMake for\n  usage, the variable's value will be used if defined when the\n  ``NAME_MISMATCHED`` argument is not passed for the new signature (but using\n  both is an error)..\n\nExample for the full signature:\n\n.. code-block:: cmake\n\n  find_package_handle_standard_args(LibArchive\n    REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR\n    VERSION_VAR LibArchive_VERSION)\n\nIn this case, the ``LibArchive`` package is considered to be found if\nboth ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.\nAlso the version of ``LibArchive`` will be checked by using the version\ncontained in ``LibArchive_VERSION``.  Since no ``FAIL_MESSAGE`` is given,\nthe default messages will be printed.\n\nAnother example for the full signature:\n\n.. code-block:: cmake\n\n  find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)\n  find_package_handle_standard_args(Automoc4  CONFIG_MODE)\n\nIn this case, a ``FindAutmoc4.cmake`` module wraps a call to\n``find_package(Automoc4 NO_MODULE)`` and adds an additional search\ndirectory for ``automoc4``.  Then the call to\n``find_package_handle_standard_args`` produces a proper success/failure\nmessage.\n#]=======================================================================]\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)\n\n# internal helper macro\nmacro(_FPHSA_FAILURE_MESSAGE _msg)\n  set (__msg \"${_msg}\")\n  if (FPHSA_REASON_FAILURE_MESSAGE)\n    string(APPEND __msg \"\\n    Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\\n\")\n  endif()\n  if (${_NAME}_FIND_REQUIRED)\n    message(FATAL_ERROR \"${__msg}\")\n  else ()\n    if (NOT ${_NAME}_FIND_QUIETLY)\n      message(STATUS \"${__msg}\")\n    endif ()\n  endif ()\nendmacro()\n\n\n# internal helper macro to generate the failure message when used in CONFIG_MODE:\nmacro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)\n  # <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:\n  if(${_NAME}_CONFIG)\n    _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})\")\n  else()\n    # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.\n    # List them all in the error message:\n    if(${_NAME}_CONSIDERED_CONFIGS)\n      set(configsText \"\")\n      list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)\n      math(EXPR configsCount \"${configsCount} - 1\")\n      foreach(currentConfigIndex RANGE ${configsCount})\n        list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)\n        list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)\n        string(APPEND configsText \"\\n    ${filename} (version ${version})\")\n      endforeach()\n      if (${_NAME}_NOT_FOUND_MESSAGE)\n        if (FPHSA_REASON_FAILURE_MESSAGE)\n          string(PREPEND FPHSA_REASON_FAILURE_MESSAGE \"${${_NAME}_NOT_FOUND_MESSAGE}\\n    \")\n        else()\n          set(FPHSA_REASON_FAILURE_MESSAGE \"${${_NAME}_NOT_FOUND_MESSAGE}\")\n        endif()\n      else()\n        string(APPEND configsText \"\\n\")\n      endif()\n      _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}\")\n\n    else()\n      # Simple case: No Config-file was found at all:\n      _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}\")\n    endif()\n  endif()\nendmacro()\n\n\nfunction(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)\n\n  # Set up the arguments for `cmake_parse_arguments`.\n  set(options  CONFIG_MODE  HANDLE_COMPONENTS NAME_MISMATCHED)\n  set(oneValueArgs  FAIL_MESSAGE  REASON_FAILURE_MESSAGE VERSION_VAR  FOUND_VAR)\n  set(multiValueArgs REQUIRED_VARS)\n\n  # Check whether we are in 'simple' or 'extended' mode:\n  set(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )\n  list(FIND _KEYWORDS_FOR_EXTENDED_MODE \"${_FIRST_ARG}\" INDEX)\n\n  unset(FPHSA_NAME_MISMATCHED_override)\n  if (DEFINED FPHSA_NAME_MISMATCHED)\n    # If the variable NAME_MISMATCHED variable is set, error if it is passed as\n    # an argument. The former is for old signatures, the latter is for new\n    # signatures.\n    list(FIND ARGN \"NAME_MISMATCHED\" name_mismatched_idx)\n    if (NOT name_mismatched_idx EQUAL \"-1\")\n      message(FATAL_ERROR\n        \"The `NAME_MISMATCHED` argument may only be specified by the argument or \"\n        \"the variable, not both.\")\n    endif ()\n\n    # But use the variable if it is not an argument to avoid forcing minimum\n    # CMake version bumps for calling modules.\n    set(FPHSA_NAME_MISMATCHED_override \"${FPHSA_NAME_MISMATCHED}\")\n  endif ()\n\n  if(${INDEX} EQUAL -1)\n    set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})\n    set(FPHSA_REQUIRED_VARS ${ARGN})\n    set(FPHSA_VERSION_VAR)\n  else()\n    cmake_parse_arguments(FPHSA \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\"  ${_FIRST_ARG} ${ARGN})\n\n    if(FPHSA_UNPARSED_ARGUMENTS)\n      message(FATAL_ERROR \"Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \\\"${FPHSA_UNPARSED_ARGUMENTS}\\\"\")\n    endif()\n\n    if(NOT FPHSA_FAIL_MESSAGE)\n      set(FPHSA_FAIL_MESSAGE  \"DEFAULT_MSG\")\n    endif()\n\n    # In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()\n    # when it successfully found the config-file, including version checking:\n    if(FPHSA_CONFIG_MODE)\n      list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)\n      list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)\n      set(FPHSA_VERSION_VAR ${_NAME}_VERSION)\n    endif()\n\n    if(NOT FPHSA_REQUIRED_VARS)\n      message(FATAL_ERROR \"No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()\")\n    endif()\n  endif()\n\n  if (DEFINED FPHSA_NAME_MISMATCHED_override)\n    set(FPHSA_NAME_MISMATCHED \"${FPHSA_NAME_MISMATCHED_override}\")\n  endif ()\n\n  if (DEFINED CMAKE_FIND_PACKAGE_NAME\n      AND NOT FPHSA_NAME_MISMATCHED\n      AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)\n    message(AUTHOR_WARNING\n      \"The package name passed to `find_package_handle_standard_args` \"\n      \"(${_NAME}) does not match the name of the calling package \"\n      \"(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling \"\n      \"code that expects `find_package` result variables (e.g., `_FOUND`) \"\n      \"to follow a certain pattern.\")\n  endif ()\n\n# now that we collected all arguments, process them\n\n  if(\"x${FPHSA_FAIL_MESSAGE}\" STREQUAL \"xDEFAULT_MSG\")\n    set(FPHSA_FAIL_MESSAGE \"Could NOT find ${_NAME}\")\n  endif()\n\n  list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)\n\n  string(TOUPPER ${_NAME} _NAME_UPPER)\n  string(TOLOWER ${_NAME} _NAME_LOWER)\n\n  if(FPHSA_FOUND_VAR)\n    set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)\n    set(_FOUND_VAR_MIXED ${_NAME}_FOUND)\n    if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED  OR  FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)\n      set(_FOUND_VAR ${FPHSA_FOUND_VAR})\n    else()\n      message(FATAL_ERROR \"The argument for FOUND_VAR is \\\"${FPHSA_FOUND_VAR}\\\", but only \\\"${_FOUND_VAR_MIXED}\\\" and \\\"${_FOUND_VAR_UPPER}\\\" are valid names.\")\n    endif()\n  else()\n    set(_FOUND_VAR ${_NAME_UPPER}_FOUND)\n  endif()\n\n  # collect all variables which were not found, so they can be printed, so the\n  # user knows better what went wrong (#6375)\n  set(MISSING_VARS \"\")\n  set(DETAILS \"\")\n  # check if all passed variables are valid\n  set(FPHSA_FOUND_${_NAME} TRUE)\n  foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})\n    if(NOT ${_CURRENT_VAR})\n      set(FPHSA_FOUND_${_NAME} FALSE)\n      string(APPEND MISSING_VARS \" ${_CURRENT_VAR}\")\n    else()\n      string(APPEND DETAILS \"[${${_CURRENT_VAR}}]\")\n    endif()\n  endforeach()\n  if(FPHSA_FOUND_${_NAME})\n    set(${_NAME}_FOUND TRUE)\n    set(${_NAME_UPPER}_FOUND TRUE)\n  else()\n    set(${_NAME}_FOUND FALSE)\n    set(${_NAME_UPPER}_FOUND FALSE)\n  endif()\n\n  # component handling\n  unset(FOUND_COMPONENTS_MSG)\n  unset(MISSING_COMPONENTS_MSG)\n\n  if(FPHSA_HANDLE_COMPONENTS)\n    foreach(comp ${${_NAME}_FIND_COMPONENTS})\n      if(${_NAME}_${comp}_FOUND)\n\n        if(NOT DEFINED FOUND_COMPONENTS_MSG)\n          set(FOUND_COMPONENTS_MSG \"found components:\")\n        endif()\n        string(APPEND FOUND_COMPONENTS_MSG \" ${comp}\")\n\n      else()\n\n        if(NOT DEFINED MISSING_COMPONENTS_MSG)\n          set(MISSING_COMPONENTS_MSG \"missing components:\")\n        endif()\n        string(APPEND MISSING_COMPONENTS_MSG \" ${comp}\")\n\n        if(${_NAME}_FIND_REQUIRED_${comp})\n          set(${_NAME}_FOUND FALSE)\n          string(APPEND MISSING_VARS \" ${comp}\")\n        endif()\n\n      endif()\n    endforeach()\n    set(COMPONENT_MSG \"${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}\")\n    string(APPEND DETAILS \"[c${COMPONENT_MSG}]\")\n  endif()\n\n  # version handling:\n  set(VERSION_MSG \"\")\n  set(VERSION_OK TRUE)\n\n  # check with DEFINED here as the requested or found version may be \"0\"\n  if (DEFINED ${_NAME}_FIND_VERSION)\n    if(DEFINED ${FPHSA_VERSION_VAR})\n      set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})\n\n      if(${_NAME}_FIND_VERSION_EXACT)       # exact version required\n        # count the dots in the version string\n        string(REGEX REPLACE \"[^.]\" \"\" _VERSION_DOTS \"${_FOUND_VERSION}\")\n        # add one dot because there is one dot more than there are components\n        string(LENGTH \"${_VERSION_DOTS}.\" _VERSION_DOTS)\n        if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)\n          # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT\n          # is at most 4 here. Therefore a simple lookup table is used.\n          if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)\n            set(_VERSION_REGEX \"[^.]*\")\n          elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)\n            set(_VERSION_REGEX \"[^.]*\\\\.[^.]*\")\n          elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)\n            set(_VERSION_REGEX \"[^.]*\\\\.[^.]*\\\\.[^.]*\")\n          else ()\n            set(_VERSION_REGEX \"[^.]*\\\\.[^.]*\\\\.[^.]*\\\\.[^.]*\")\n          endif ()\n          string(REGEX REPLACE \"^(${_VERSION_REGEX})\\\\..*\" \"\\\\1\" _VERSION_HEAD \"${_FOUND_VERSION}\")\n          unset(_VERSION_REGEX)\n          if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)\n            set(VERSION_MSG \"Found unsuitable version \\\"${_FOUND_VERSION}\\\", but required is exact version \\\"${${_NAME}_FIND_VERSION}\\\"\")\n            set(VERSION_OK FALSE)\n          else ()\n            set(VERSION_MSG \"(found suitable exact version \\\"${_FOUND_VERSION}\\\")\")\n          endif ()\n          unset(_VERSION_HEAD)\n        else ()\n          if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _FOUND_VERSION)\n            set(VERSION_MSG \"Found unsuitable version \\\"${_FOUND_VERSION}\\\", but required is exact version \\\"${${_NAME}_FIND_VERSION}\\\"\")\n            set(VERSION_OK FALSE)\n          else ()\n            set(VERSION_MSG \"(found suitable exact version \\\"${_FOUND_VERSION}\\\")\")\n          endif ()\n        endif ()\n        unset(_VERSION_DOTS)\n\n      else()     # minimum version specified:\n        if (${_NAME}_FIND_VERSION VERSION_GREATER _FOUND_VERSION)\n          set(VERSION_MSG \"Found unsuitable version \\\"${_FOUND_VERSION}\\\", but required is at least \\\"${${_NAME}_FIND_VERSION}\\\"\")\n          set(VERSION_OK FALSE)\n        else ()\n          set(VERSION_MSG \"(found suitable version \\\"${_FOUND_VERSION}\\\", minimum required is \\\"${${_NAME}_FIND_VERSION}\\\")\")\n        endif ()\n      endif()\n\n    else()\n\n      # if the package was not found, but a version was given, add that to the output:\n      if(${_NAME}_FIND_VERSION_EXACT)\n         set(VERSION_MSG \"(Required is exact version \\\"${${_NAME}_FIND_VERSION}\\\")\")\n      else()\n         set(VERSION_MSG \"(Required is at least version \\\"${${_NAME}_FIND_VERSION}\\\")\")\n      endif()\n\n    endif()\n  else ()\n    # Check with DEFINED as the found version may be 0.\n    if(DEFINED ${FPHSA_VERSION_VAR})\n      set(VERSION_MSG \"(found version \\\"${${FPHSA_VERSION_VAR}}\\\")\")\n    endif()\n  endif ()\n\n  if(VERSION_OK)\n    string(APPEND DETAILS \"[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]\")\n  else()\n    set(${_NAME}_FOUND FALSE)\n  endif()\n\n\n  # print the result:\n  if (${_NAME}_FOUND)\n    FIND_PACKAGE_MESSAGE(${_NAME} \"Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}\" \"${DETAILS}\")\n  else ()\n\n    if(FPHSA_CONFIG_MODE)\n      _FPHSA_HANDLE_FAILURE_CONFIG_MODE()\n    else()\n      if(NOT VERSION_OK)\n        _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})\")\n      else()\n        _FPHSA_FAILURE_MESSAGE(\"${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}\")\n      endif()\n    endif()\n\n  endif ()\n\n  set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)\n  set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)\nendfunction()\n"
  },
  {
    "path": "external/libzip/cmake-compat/FindPackageMessage.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nFindPackageMessage\n------------------\n\n.. code-block:: cmake\n\n  find_package_message(<name> \"message for user\" \"find result details\")\n\nThis function is intended to be used in FindXXX.cmake modules files.\nIt will print a message once for each unique find result.  This is\nuseful for telling the user where a package was found.  The first\nargument specifies the name (XXX) of the package.  The second argument\nspecifies the message to display.  The third argument lists details\nabout the find result so that if they change the message will be\ndisplayed again.  The macro also obeys the QUIET argument to the\nfind_package command.\n\nExample:\n\n.. code-block:: cmake\n\n  if(X11_FOUND)\n    find_package_message(X11 \"Found X11: ${X11_X11_LIB}\"\n      \"[${X11_X11_LIB}][${X11_INCLUDE_DIR}]\")\n  else()\n   ...\n  endif()\n#]=======================================================================]\n\nfunction(find_package_message pkg msg details)\n  # Avoid printing a message repeatedly for the same find result.\n  if(NOT ${pkg}_FIND_QUIETLY)\n    string(REPLACE \"\\n\" \"\" details \"${details}\")\n    set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})\n    if(NOT \"${details}\" STREQUAL \"${${DETAILS_VAR}}\")\n      # The message has not yet been printed.\n      message(STATUS \"${msg}\")\n\n      # Save the find details in the cache to avoid printing the same\n      # message again.\n      set(\"${DETAILS_VAR}\" \"${details}\"\n        CACHE INTERNAL \"Details about finding ${pkg}\")\n    endif()\n  endif()\nendfunction()\n"
  },
  {
    "path": "external/libzip/cmake-compat/SelectLibraryConfigurations.cmake",
    "content": "# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying\n# file Copyright.txt or https://cmake.org/licensing for details.\n\n#[=======================================================================[.rst:\nSelectLibraryConfigurations\n---------------------------\n\n.. code-block:: cmake\n\n  select_library_configurations(basename)\n\nThis macro takes a library base name as an argument, and will choose\ngood values for the variables\n\n::\n\n  basename_LIBRARY\n  basename_LIBRARIES\n  basename_LIBRARY_DEBUG\n  basename_LIBRARY_RELEASE\n\ndepending on what has been found and set.\n\nIf only ``basename_LIBRARY_RELEASE`` is defined, ``basename_LIBRARY`` will\nbe set to the release value, and ``basename_LIBRARY_DEBUG`` will be set\nto ``basename_LIBRARY_DEBUG-NOTFOUND``.  If only ``basename_LIBRARY_DEBUG``\nis defined, then ``basename_LIBRARY`` will take the debug value, and\n``basename_LIBRARY_RELEASE`` will be set to ``basename_LIBRARY_RELEASE-NOTFOUND``.\n\nIf the generator supports configuration types, then ``basename_LIBRARY``\nand ``basename_LIBRARIES`` will be set with debug and optimized flags\nspecifying the library to be used for the given configuration.  If no\nbuild type has been set or the generator in use does not support\nconfiguration types, then ``basename_LIBRARY`` and ``basename_LIBRARIES``\nwill take only the release value, or the debug value if the release one\nis not set.\n#]=======================================================================]\n\n# This macro was adapted from the FindQt4 CMake module and is maintained by Will\n# Dicharry <wdicharry@stellarscience.com>.\n\nmacro(select_library_configurations basename)\n    if(NOT ${basename}_LIBRARY_RELEASE)\n        set(${basename}_LIBRARY_RELEASE \"${basename}_LIBRARY_RELEASE-NOTFOUND\" CACHE FILEPATH \"Path to a library.\")\n    endif()\n    if(NOT ${basename}_LIBRARY_DEBUG)\n        set(${basename}_LIBRARY_DEBUG \"${basename}_LIBRARY_DEBUG-NOTFOUND\" CACHE FILEPATH \"Path to a library.\")\n    endif()\n\n    get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\n    if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE AND\n           NOT ${basename}_LIBRARY_DEBUG STREQUAL ${basename}_LIBRARY_RELEASE AND\n           ( _isMultiConfig OR CMAKE_BUILD_TYPE ) )\n        # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for\n        # single-config generators, set optimized and debug libraries\n        set( ${basename}_LIBRARY \"\" )\n        foreach( _libname IN LISTS ${basename}_LIBRARY_RELEASE )\n            list( APPEND ${basename}_LIBRARY optimized \"${_libname}\" )\n        endforeach()\n        foreach( _libname IN LISTS ${basename}_LIBRARY_DEBUG )\n            list( APPEND ${basename}_LIBRARY debug \"${_libname}\" )\n        endforeach()\n    elseif( ${basename}_LIBRARY_RELEASE )\n        set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} )\n    elseif( ${basename}_LIBRARY_DEBUG )\n        set( ${basename}_LIBRARY ${${basename}_LIBRARY_DEBUG} )\n    else()\n        set( ${basename}_LIBRARY \"${basename}_LIBRARY-NOTFOUND\")\n    endif()\n\n    set( ${basename}_LIBRARIES \"${${basename}_LIBRARY}\" )\n\n    if( ${basename}_LIBRARY )\n        set( ${basename}_FOUND TRUE )\n    endif()\n\n    mark_as_advanced( ${basename}_LIBRARY_RELEASE\n        ${basename}_LIBRARY_DEBUG\n    )\nendmacro()\n"
  },
  {
    "path": "external/libzip/config.h.in",
    "content": "#ifndef HAD_CONFIG_H\n#define HAD_CONFIG_H\n#ifndef _HAD_ZIPCONF_H\n#include \"zipconf.h\"\n#endif\n/* BEGIN DEFINES */\n#cmakedefine ENABLE_FDOPEN\n#cmakedefine HAVE___PROGNAME\n#cmakedefine HAVE__CLOSE\n#cmakedefine HAVE__DUP\n#cmakedefine HAVE__FDOPEN\n#cmakedefine HAVE__FILENO\n#cmakedefine HAVE__FSEEKI64\n#cmakedefine HAVE__FSTAT64\n#cmakedefine HAVE__SETMODE\n#cmakedefine HAVE__SNPRINTF\n#cmakedefine HAVE__SNPRINTF_S\n#cmakedefine HAVE__SNWPRINTF_S\n#cmakedefine HAVE__STAT64\n#cmakedefine HAVE__STRDUP\n#cmakedefine HAVE__STRICMP\n#cmakedefine HAVE__STRTOI64\n#cmakedefine HAVE__STRTOUI64\n#cmakedefine HAVE__UNLINK\n#cmakedefine HAVE_ARC4RANDOM\n#cmakedefine HAVE_CLONEFILE\n#cmakedefine HAVE_COMMONCRYPTO\n#cmakedefine HAVE_CRYPTO\n#cmakedefine HAVE_FICLONERANGE\n#cmakedefine HAVE_FILENO\n#cmakedefine HAVE_FCHMOD\n#cmakedefine HAVE_FSEEKO\n#cmakedefine HAVE_FTELLO\n#cmakedefine HAVE_GETPROGNAME\n#cmakedefine HAVE_GETSECURITYINFO\n#cmakedefine HAVE_GNUTLS\n#cmakedefine HAVE_LIBBZ2\n#cmakedefine HAVE_LIBLZMA\n#cmakedefine HAVE_LIBZSTD\n#cmakedefine HAVE_LOCALTIME_R\n#cmakedefine HAVE_LOCALTIME_S\n#cmakedefine HAVE_MEMCPY_S\n#cmakedefine HAVE_MBEDTLS\n#cmakedefine HAVE_MKSTEMP\n#cmakedefine HAVE_OPENSSL\n#cmakedefine HAVE_SETMODE\n#cmakedefine HAVE_SNPRINTF\n#cmakedefine HAVE_SNPRINTF_S\n#cmakedefine HAVE_STRCASECMP\n#cmakedefine HAVE_STRDUP\n#cmakedefine HAVE_STRERROR_S\n#cmakedefine HAVE_STRERRORLEN_S\n#cmakedefine HAVE_STRICMP\n#cmakedefine HAVE_STRNCPY_S\n#cmakedefine HAVE_STRTOLL\n#cmakedefine HAVE_STRTOULL\n#cmakedefine HAVE_STRUCT_TM_TM_ZONE\n#cmakedefine HAVE_STDBOOL_H\n#cmakedefine HAVE_STRINGS_H\n#cmakedefine HAVE_UNISTD_H\n#cmakedefine HAVE_WINDOWS_CRYPTO\n#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}\n#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}\n#cmakedefine HAVE_DIRENT_H\n#cmakedefine HAVE_FTS_H\n#cmakedefine HAVE_NDIR_H\n#cmakedefine HAVE_SYS_DIR_H\n#cmakedefine HAVE_SYS_NDIR_H\n#cmakedefine WORDS_BIGENDIAN\n#cmakedefine HAVE_SHARED\n/* END DEFINES */\n#define PACKAGE \"@CMAKE_PROJECT_NAME@\"\n#define VERSION \"@CMAKE_PROJECT_VERSION@\"\n\n#endif /* HAD_CONFIG_H */\n"
  },
  {
    "path": "external/libzip/examples/CMakeLists.txt",
    "content": "foreach(PROGRAM add-compressed-data autoclose-archive in-memory)\n    add_executable(${PROGRAM} ${PROGRAM}.c)\n    target_link_libraries(${PROGRAM} zip)\n    target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})\nendforeach()\n"
  },
  {
    "path": "external/libzip/examples/add-compressed-data.c",
    "content": "/*\n  add-compressed-data.c -- add already compressed file to zip archive\n  Copyright (C) 2022-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <libzip@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\n This layered source can be used to add pre-compressed data to a zip archive.\n The data is taken from the lower layer source.\n Metadata (uncompressed size, crc, compression method) must be provided by the caller.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <zip.h>\n\nstruct ctx {\n    zip_uint64_t uncompressed_size;\n    zip_uint32_t crc;\n    zip_uint32_t compression_method;\n};\n\nzip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64_t length, zip_source_cmd_t command) {\n    struct ctx* ctx = (struct ctx*)ud;\n\n    switch (command) {\n    case ZIP_SOURCE_FREE:\n        /* Free our context. */\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st = (zip_stat_t *)data;\n        /* Fix metadata with provided values. */\n        if (st->valid & ZIP_STAT_SIZE) {\n            st->comp_size = st->size;\n            st->valid |= ZIP_STAT_COMP_SIZE;\n        }\n        st->size = ctx->uncompressed_size;\n        st->crc = ctx->crc;\n        st->comp_method = ctx->compression_method;\n        st->valid |= ZIP_STAT_COMP_METHOD | ZIP_STAT_SIZE | ZIP_STAT_CRC;\n\n        return 0;\n    }\n\n    default:\n        /* For all other commands, use default implementation */\n        return zip_source_pass_to_lower_layer(src, data, length, command);\n    }\n}\n\nzip_source_t* create_layered_compressed_source(zip_source_t* source, zip_uint64_t uncompressed_size, zip_uint32_t crc, zip_uint32_t compression_method, zip_error_t *error) {\n    struct ctx* ctx = (struct ctx*)malloc(sizeof(*ctx));\n    zip_source_t *compressed_source;\n\n    /* Allocate context. */\n    if (ctx == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    /* Initialize context */\n    ctx->compression_method = compression_method;\n    ctx->uncompressed_size = uncompressed_size;\n    ctx->crc = crc;\n\n    /* Create layered source using our callback and context. */\n    compressed_source = zip_source_layered_create(source, callback, ctx, error);\n\n    /* In case of error, free context. */\n    if (compressed_source == NULL) {\n        free(ctx);\n    }\n\n    return compressed_source;\n}\n\n\n/* This is the information needed to add pre-compressed data to a zip archive. data must be compressed in a format compatible with Zip (e.g. no gzip header for deflate). */\n\nzip_uint16_t compression_method = ZIP_CM_DEFLATE;\nzip_uint64_t uncompressed_size = 60;\nzip_uint32_t crc = 0xb0354048;\nzip_uint8_t data[] = {\n    0x4B, 0x4C, 0x44, 0x06, 0x5C, 0x49, 0x28, 0x80,\n    0x2B, 0x11, 0x55 ,0x36, 0x19, 0x05, 0x70, 0x01,\n    0x00\n};\n\n\nint\nmain(int argc, char *argv[]) {\n    const char *archive;\n    zip_source_t *src, *src_comp;\n    zip_t *za;\n    int err;\n\n    if (argc != 2) {\n        fprintf(stderr, \"usage: %s archive\\n\", argv[0]);\n        return 1;\n    }\n    archive = argv[1];\n\n    if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\n\", argv[0], archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        exit(1);\n    }\n\n    /* The data can come from any source. To keep the example simple, it is provided in a static buffer here. */\n    if ((src = zip_source_buffer(za, data, sizeof(data), 0)) == NULL) {\n        fprintf(stderr, \"%s: cannot create buffer source: %s\\n\", argv[0], zip_strerror(za));\n        zip_discard(za);\n        exit(1);\n    }\n\n    zip_error_t error;\n    if ((src_comp = create_layered_compressed_source(src, uncompressed_size, crc, compression_method, &error)) == NULL) {\n        fprintf(stderr, \"%s: cannot create layered source: %s\\n\", argv[0], zip_error_strerror(&error));\n        zip_source_free(src);\n        zip_discard(za);\n        exit(1);\n    }\n\n    if ((zip_file_add(za, \"precompressed\", src_comp, 0)) < 0) {\n        fprintf(stderr, \"%s: cannot add precompressed file: %s\\n\", argv[0], zip_strerror(za));\n        zip_source_free(src_comp);\n        zip_discard(za);\n        exit(1);\n    }\n\n    if ((zip_close(za)) < 0) {\n        fprintf(stderr, \"%s: cannot close archive '%s': %s\\n\", argv[0], archive, zip_strerror(za));\n        zip_discard(za);\n        exit(1);\n    }\n\n    exit(0);\n}\n"
  },
  {
    "path": "external/libzip/examples/autoclose-archive.c",
    "content": "/*\n  autoclose-archive.c -- automatically close archive when source is closed\n  Copyright (C) 2022-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <libzip@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\n  This example layered source takes ownership of a zip archive and discards it when the source is freed.\n  It can be used to add files from various zip archives without having to keep track of them yourself.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <zip.h>\n\nstruct ctx {\n    zip_t* archive;\n};\n\nzip_int64_t callback(zip_source_t* src, void *ud, void* data, zip_uint64_t length, zip_source_cmd_t command) {\n    struct ctx* ctx = (struct ctx*)ud;\n\n    switch (command) {\n    case ZIP_SOURCE_FREE:\n        /* Close zip archive we took ownership of */\n        zip_discard(ctx->archive);\n        /* Free our own context */\n        free(ctx);\n        return 0;\n\n    default:\n        /* For all other commands, use default implementation */\n        return zip_source_pass_to_lower_layer(src, data, length, command);\n    }\n}\n\nzip_source_t* create_layered_autoclose(zip_source_t* source, zip_t *archive, zip_error_t *error) {\n    struct ctx* ctx = (struct ctx*)malloc(sizeof(*ctx));\n    zip_source_t *autoclose_source;\n\n    /* Allocate context. */\n    if (ctx == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    /* Initialize context */\n    ctx->archive = archive;\n\n    /* Create layered source using our callback and context. */\n    autoclose_source = zip_source_layered_create(source, callback, ctx, error);\n\n    /* In case of error, free context. */\n    if (autoclose_source == NULL) {\n        free(ctx);\n    }\n\n    return autoclose_source;\n}\n\n\nint\nmain(int argc, char *argv[]) {\n    const char *destination_archive, *source_archive, *source_file;\n    zip_int64_t index;\n    zip_source_t *src, *src_autoclose;\n    zip_t *z_source, *z_destination;\n    int err;\n\n    if (argc != 4) {\n        fprintf(stderr, \"usage: %s destination-archive source-archive source-file\\n\", argv[0]);\n        return 1;\n    }\n    destination_archive = argv[1];\n    source_archive = argv[2];\n    source_file = argv[3];\n\n\n    if ((z_source = zip_open(source_archive, 0, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\n\", argv[0], source_archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        exit(1);\n    }\n\n    if ((index = zip_name_locate(z_source, source_file, 0)) < 0) {\n        fprintf(stderr, \"%s: cannot find file '%s' in '%s': %s\\n\", argv[0], source_file, source_archive, zip_strerror(z_source));\n        zip_discard(z_source);\n        exit(1);\n\n    }\n    if ((src = zip_source_zip_file(z_source, z_source, index, 0, 0, -1, NULL)) == NULL) {\n        fprintf(stderr, \"%s: cannot open file '%s' in '%s': %s\\n\", argv[0], source_file, source_archive, zip_strerror(z_source));\n        zip_discard(z_source);\n        exit(1);\n    }\n\n    zip_error_t error;\n    if ((src_autoclose = create_layered_autoclose(src, z_source, &error)) == NULL) {\n        fprintf(stderr, \"%s: cannot create layered source: %s\\n\", argv[0], zip_error_strerror(&error));\n        zip_source_free(src);\n        zip_discard(z_source);\n        exit(1);\n    }\n\n    if ((z_destination = zip_open(destination_archive, ZIP_CREATE, &err)) == NULL) {\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\n\", argv[0], destination_archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        zip_source_free(src_autoclose); /* freeing src_autoclose closes z_source */\n        exit(1);\n    }\n\n\n    if ((zip_file_add(z_destination, source_file, src_autoclose, 0)) < 0) {\n        fprintf(stderr, \"%s: cannot add file: %s\\n\", argv[0], zip_strerror(z_source));\n        zip_source_free(src_autoclose);\n        zip_discard(z_destination);\n        exit(1);\n    }\n\n    if ((zip_close(z_destination)) < 0) {\n        fprintf(stderr, \"%s: cannot close archive '%s': %s\\n\", argv[0], destination_archive, zip_strerror(z_source));\n        zip_discard(z_destination);\n        exit(1);\n    }\n\n    exit(0);\n}\n"
  },
  {
    "path": "external/libzip/examples/cmake-project/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\n\nproject(cmake-example\n  VERSION 1.0\n  LANGUAGES C)\n\nfind_package(libzip 1.10 REQUIRED)\n\nadd_executable(cmake-example cmake-example.c)\ntarget_link_libraries(cmake-example PRIVATE libzip::zip)\n"
  },
  {
    "path": "external/libzip/examples/cmake-project/cmake-example.c",
    "content": "/*\n  cmake-example.c -- mininmal code using libzip for CMake example\n  Copyright (C) 2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <zip.h>\n\nint\nmain(int argc, char *argv[]) {\n    printf(\"libzip version is %s\\n\", zip_libzip_version());\n}\n"
  },
  {
    "path": "external/libzip/examples/in-memory.c",
    "content": "/*\n  in-memory.c -- modify zip file in memory\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n\n#include <zip.h>\n\nstatic int\nget_data(void **datap, size_t *sizep, const char *archive) {\n    /* example implementation that reads data from file */\n    struct stat st;\n    FILE *fp;\n\n    if ((fp = fopen(archive, \"rb\")) == NULL) {\n        if (errno != ENOENT) {\n            fprintf(stderr, \"can't open %s: %s\\n\", archive, strerror(errno));\n            return -1;\n        }\n\n        *datap = NULL;\n        *sizep = 0;\n\n        return 0;\n    }\n\n    if (fstat(fileno(fp), &st) < 0) {\n        fprintf(stderr, \"can't stat %s: %s\\n\", archive, strerror(errno));\n        fclose(fp);\n        return -1;\n    }\n\n    if ((*datap = malloc((size_t)st.st_size)) == NULL) {\n        fprintf(stderr, \"can't allocate buffer\\n\");\n        fclose(fp);\n        return -1;\n    }\n\n    if (fread(*datap, 1, (size_t)st.st_size, fp) < (size_t)st.st_size) {\n        fprintf(stderr, \"can't read %s: %s\\n\", archive, strerror(errno));\n        free(*datap);\n        fclose(fp);\n        return -1;\n    }\n\n    fclose(fp);\n\n    *sizep = (size_t)st.st_size;\n    return 0;\n}\n\nstatic int\nmodify_archive(zip_t *za) {\n    /* modify the archive */\n    return 0;\n}\n\n\nstatic int\nuse_data(void *data, size_t size, const char *archive) {\n    /* example implementation that writes data to file */\n    FILE *fp;\n\n    if (data == NULL) {\n        if (remove(archive) < 0 && errno != ENOENT) {\n            fprintf(stderr, \"can't remove %s: %s\\n\", archive, strerror(errno));\n            return -1;\n        }\n        return 0;\n    }\n\n    if ((fp = fopen(archive, \"wb\")) == NULL) {\n        fprintf(stderr, \"can't open %s: %s\\n\", archive, strerror(errno));\n        return -1;\n    }\n    if (fwrite(data, 1, size, fp) < size) {\n        fprintf(stderr, \"can't write %s: %s\\n\", archive, strerror(errno));\n        fclose(fp);\n        return -1;\n    }\n    if (fclose(fp) < 0) {\n        fprintf(stderr, \"can't write %s: %s\\n\", archive, strerror(errno));\n        return -1;\n    }\n\n    return 0;\n}\n\n\nint\nmain(int argc, char *argv[]) {\n    const char *archive;\n    zip_source_t *src;\n    zip_t *za;\n    zip_error_t error;\n    void *data;\n    size_t size;\n\n    if (argc < 2) {\n        fprintf(stderr, \"usage: %s archive\\n\", argv[0]);\n        return 1;\n    }\n    archive = argv[1];\n\n    /* get buffer with zip archive inside */\n    if (get_data(&data, &size, archive) < 0) {\n        return 1;\n    }\n\n    zip_error_init(&error);\n    /* create source from buffer */\n    if ((src = zip_source_buffer_create(data, size, 1, &error)) == NULL) {\n        fprintf(stderr, \"can't create source: %s\\n\", zip_error_strerror(&error));\n        free(data);\n        zip_error_fini(&error);\n        return 1;\n    }\n\n    /* open zip archive from source */\n    if ((za = zip_open_from_source(src, 0, &error)) == NULL) {\n        fprintf(stderr, \"can't open zip from source: %s\\n\", zip_error_strerror(&error));\n        zip_source_free(src);\n        zip_error_fini(&error);\n        return 1;\n    }\n    zip_error_fini(&error);\n\n    /* we'll want to read the data back after zip_close */\n    zip_source_keep(src);\n\n    /* modify archive */\n    modify_archive(za);\n\n    /* close archive */\n    if (zip_close(za) < 0) {\n        fprintf(stderr, \"can't close zip archive '%s': %s\\n\", archive, zip_strerror(za));\n        return 1;\n    }\n\n\n    /* copy new archive to buffer */\n\n    if (zip_source_is_deleted(src)) {\n        /* new archive is empty, thus no data */\n        data = NULL;\n    }\n    else {\n        zip_stat_t zst;\n\n        if (zip_source_stat(src, &zst) < 0) {\n            fprintf(stderr, \"can't stat source: %s\\n\", zip_error_strerror(zip_source_error(src)));\n            return 1;\n        }\n\n        size = zst.size;\n\n        if (zip_source_open(src) < 0) {\n            fprintf(stderr, \"can't open source: %s\\n\", zip_error_strerror(zip_source_error(src)));\n            return 1;\n        }\n        if ((data = malloc(size)) == NULL) {\n            fprintf(stderr, \"malloc failed: %s\\n\", strerror(errno));\n            zip_source_close(src);\n            return 1;\n        }\n        if ((zip_uint64_t)zip_source_read(src, data, size) < size) {\n            fprintf(stderr, \"can't read data from source: %s\\n\", zip_error_strerror(zip_source_error(src)));\n            zip_source_close(src);\n            free(data);\n            return 1;\n        }\n        zip_source_close(src);\n    }\n\n    /* we're done with src */\n    zip_source_free(src);\n\n    /* use new data */\n    use_data(data, size, archive);\n\n    free(data);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/examples/windows-open.c",
    "content": "/*\n  windows-open.c -- open zip archive using Windows UTF-16/Unicode file name\n  Copyright (C) 2015-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <zip.h>\n\nzip_t *\nwindows_open(const wchar_t *name, int flags) {\n    zip_source_t *src;\n    zip_t *za;\n    zip_error_t error;\n\n    zip_error_init(&error);\n    /* create source from buffer */\n    if ((src = zip_source_win32w_create(name, 0, -1, &error)) == NULL) {\n        fprintf(stderr, \"can't create source: %s\\n\", zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    /* open zip archive from source */\n    if ((za = zip_open_from_source(src, flags, &error)) == NULL) {\n        fprintf(stderr, \"can't open zip from source: %s\\n\", zip_error_strerror(&error));\n        zip_source_free(src);\n        zip_error_fini(&error);\n        return NULL;\n    }\n    zip_error_fini(&error);\n\n    return za;\n}\n"
  },
  {
    "path": "external/libzip/lib/CMakeLists.txt",
    "content": "include(CheckFunctionExists)\n\nset(CMAKE_C_VISIBILITY_PRESET hidden)\n\nadd_library(zip\n  zip_add.c\n  zip_add_dir.c\n  zip_add_entry.c\n  zip_algorithm_deflate.c\n  zip_buffer.c\n  zip_close.c\n  zip_delete.c\n  zip_dir_add.c\n  zip_dirent.c\n  zip_discard.c\n  zip_entry.c\n  zip_error.c\n  zip_error_clear.c\n  zip_error_get.c\n  zip_error_get_sys_type.c\n  zip_error_strerror.c\n  zip_error_to_str.c\n  zip_extra_field.c\n  zip_extra_field_api.c\n  zip_fclose.c\n  zip_fdopen.c\n  zip_file_add.c\n  zip_file_error_clear.c\n  zip_file_error_get.c\n  zip_file_get_comment.c\n  zip_file_get_external_attributes.c\n  zip_file_get_offset.c\n  zip_file_rename.c\n  zip_file_replace.c\n  zip_file_set_comment.c\n  zip_file_set_encryption.c\n  zip_file_set_external_attributes.c\n  zip_file_set_mtime.c\n  zip_file_strerror.c\n  zip_fopen.c\n  zip_fopen_encrypted.c\n  zip_fopen_index.c\n  zip_fopen_index_encrypted.c\n  zip_fread.c\n  zip_fseek.c\n  zip_ftell.c\n  zip_get_archive_comment.c\n  zip_get_archive_flag.c\n  zip_get_encryption_implementation.c\n  zip_get_file_comment.c\n  zip_get_name.c\n  zip_get_num_entries.c\n  zip_get_num_files.c\n  zip_hash.c\n  zip_io_util.c\n  zip_libzip_version.c\n  zip_memdup.c\n  zip_name_locate.c\n  zip_new.c\n  zip_open.c\n  zip_pkware.c\n  zip_progress.c\n  zip_realloc.c\n  zip_rename.c\n  zip_replace.c\n  zip_set_archive_comment.c\n  zip_set_archive_flag.c\n  zip_set_default_password.c\n  zip_set_file_comment.c\n  zip_set_file_compression.c\n  zip_set_name.c\n  zip_source_accept_empty.c\n  zip_source_begin_write.c\n  zip_source_begin_write_cloning.c\n  zip_source_buffer.c\n  zip_source_call.c\n  zip_source_close.c\n  zip_source_commit_write.c\n  zip_source_compress.c\n  zip_source_crc.c\n  zip_source_error.c\n  zip_source_file_common.c\n  zip_source_file_stdio.c\n  zip_source_free.c\n  zip_source_function.c\n  zip_source_get_dostime.c\n  zip_source_get_file_attributes.c\n  zip_source_is_deleted.c\n  zip_source_layered.c\n  zip_source_open.c\n  zip_source_pass_to_lower_layer.c\n  zip_source_pkware_decode.c\n  zip_source_pkware_encode.c\n  zip_source_read.c\n  zip_source_remove.c\n  zip_source_rollback_write.c\n  zip_source_seek.c\n  zip_source_seek_write.c\n  zip_source_stat.c\n  zip_source_supports.c\n  zip_source_tell.c\n  zip_source_tell_write.c\n  zip_source_window.c\n  zip_source_write.c\n  zip_source_zip.c\n  zip_source_zip_new.c\n  zip_stat.c\n  zip_stat_index.c\n  zip_stat_init.c\n  zip_strerror.c\n  zip_string.c\n  zip_unchange.c\n  zip_unchange_all.c\n  zip_unchange_archive.c\n  zip_unchange_data.c\n  zip_utf-8.c\n  ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c\n  )\nadd_library(libzip::zip ALIAS zip)\n\nif(WIN32)\n  target_compile_definitions(zip PRIVATE WIN32_LEAN_AND_MEAN)\n  target_sources(zip PRIVATE\n    zip_source_file_win32.c\n    zip_source_file_win32_named.c\n    zip_source_file_win32_utf16.c\n    zip_source_file_win32_utf8.c\n    )\n  if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)\n    target_sources(zip PRIVATE zip_random_uwp.c)\n  else()\n    target_sources(zip PRIVATE zip_source_file_win32_ansi.c zip_random_win32.c)\n    target_link_libraries(zip PRIVATE advapi32)\n  endif()\nelse(WIN32)\n  target_sources(zip PRIVATE\n    zip_source_file_stdio_named.c\n    zip_random_unix.c\n    )\nendif(WIN32)\n\nif(HAVE_LIBBZ2)\n  target_sources(zip PRIVATE zip_algorithm_bzip2.c)\n  target_link_libraries(zip PRIVATE BZip2::BZip2)\nendif()\n\nif(HAVE_LIBLZMA)\n  target_sources(zip PRIVATE zip_algorithm_xz.c)\n  target_link_libraries(zip PRIVATE LibLZMA::LibLZMA)\nendif()\n\nif(HAVE_LIBZSTD)\n  target_sources(zip PRIVATE zip_algorithm_zstd.c)\n  target_link_libraries(zip PRIVATE ${zstd_TARGET})\nendif()\n\nif(HAVE_COMMONCRYPTO)\n  target_sources(zip PRIVATE zip_crypto_commoncrypto.c)\nelseif(HAVE_WINDOWS_CRYPTO)\n  target_sources(zip PRIVATE zip_crypto_win.c)\n  target_link_libraries(zip PRIVATE bcrypt)\nelseif(HAVE_GNUTLS)\n  target_sources(zip PRIVATE zip_crypto_gnutls.c)\n  target_link_libraries(zip PRIVATE GnuTLS::GnuTLS Nettle::Nettle)\nelseif(HAVE_OPENSSL)\n  target_sources(zip PRIVATE zip_crypto_openssl.c)\n  target_link_libraries(zip PRIVATE OpenSSL::Crypto)\nelseif(HAVE_MBEDTLS)\n  target_sources(zip PRIVATE zip_crypto_mbedtls.c)\n  target_link_libraries(zip PRIVATE MbedTLS::MbedTLS)\nendif()\n\nif(HAVE_CRYPTO)\n  target_sources(zip PRIVATE zip_winzip_aes.c zip_source_winzip_aes_decode.c zip_source_winzip_aes_encode.c)\nendif()\n\nif(SHARED_LIB_VERSIONNING)\n  # MACHO_*_VERSION can be removed when SOVERSION gets increased. Cf #405\n  set_target_properties(zip PROPERTIES VERSION 5.5 SOVERSION 5 MACHO_CURRENT_VERSION 6.5 MACHO_COMPATIBILITY_VERSION 6)\nendif()\n\ntarget_link_libraries(zip PRIVATE ZLIB::ZLIB)\ntarget_include_directories(zip\n  PUBLIC\n  $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>\n  $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>\n  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n  )\n\nif(LIBZIP_DO_INSTALL)\n  install(TARGETS zip\n    EXPORT ${PROJECT_NAME}-targets\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})\n  install(FILES zip.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\nendif()\n\n# create zip_err_str.c from zip.h and zipint.h\nadd_custom_command(\n  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zip_err_str.c\n  COMMAND \"${CMAKE_COMMAND}\"\n    \"-DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}\"\n    \"-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}\"\n    \"-P\" \"${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake\"\n  DEPENDS\n    ${PROJECT_SOURCE_DIR}/cmake/GenerateZipErrorStrings.cmake\n    ${PROJECT_SOURCE_DIR}/lib/zip.h\n    ${PROJECT_SOURCE_DIR}/lib/zipint.h\n  COMMENT \"Generating zip_err_str.c\"\n)\n"
  },
  {
    "path": "external/libzip/lib/compat.h",
    "content": "#ifndef _HAD_LIBZIP_COMPAT_H\n#define _HAD_LIBZIP_COMPAT_H\n\n/*\n  compat.h -- compatibility defines.\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipconf.h\"\n\n#include \"config.h\"\n\n/* to have *_MAX definitions for all types when compiling with g++ */\n#define __STDC_LIMIT_MACROS\n\n/* to have ISO C secure library functions */\n#define __STDC_WANT_LIB_EXT1__ 1\n\n#ifdef _WIN32\n#ifndef ZIP_EXTERN\n#ifndef ZIP_STATIC\n#define ZIP_EXTERN __declspec(dllexport)\n#endif\n#endif\n/* for dup(), close(), etc. */\n#include <io.h>\n#endif\n\n#ifdef HAVE_STDBOOL_H\n#include <stdbool.h>\n#else\ntypedef char bool;\n#define true 1\n#define false 0\n#endif\n\n#include <errno.h>\n\n/* at least MinGW does not provide EOPNOTSUPP, see\n * http://sourceforge.net/p/mingw/bugs/263/\n */\n#ifndef EOPNOTSUPP\n#define EOPNOTSUPP EINVAL\n#endif\n\n/* at least MinGW does not provide EOVERFLOW, see\n * http://sourceforge.net/p/mingw/bugs/242/\n */\n#ifndef EOVERFLOW\n#define EOVERFLOW EFBIG\n#endif\n\n/* not supported on at least Windows */\n#ifndef O_CLOEXEC\n#define O_CLOEXEC 0\n#endif\n\n#ifdef _WIN32\n#if defined(HAVE__CLOSE)\n#define close _close\n#endif\n#if defined(HAVE__DUP)\n#define dup _dup\n#endif\n/* crashes reported when using fdopen instead of _fdopen on Windows/Visual Studio 10/Win64 */\n#if defined(HAVE__FDOPEN)\n#define fdopen _fdopen\n#endif\n#if !defined(HAVE_FILENO) && defined(HAVE__FILENO)\n#define fileno _fileno\n#endif\n#if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF)\n#define snprintf _snprintf\n#endif\n#if !defined(HAVE__SNWPRINTF_S)\n#define _snwprintf_s(buf, bufsz, len, fmt, ...) (_snwprintf((buf), (len), (fmt), __VA_ARGS__))\n#endif\n#if defined(HAVE__STRDUP)\n#if !defined(HAVE_STRDUP) || defined(_WIN32)\n#undef strdup\n#define strdup _strdup\n#endif\n#endif\n#if !defined(HAVE__SETMODE) && defined(HAVE_SETMODE)\n#define _setmode setmode\n#endif\n#if !defined(HAVE_STRTOLL) && defined(HAVE__STRTOI64)\n#define strtoll _strtoi64\n#endif\n#if !defined(HAVE_STRTOULL) && defined(HAVE__STRTOUI64)\n#define strtoull _strtoui64\n#endif\n#if defined(HAVE__UNLINK)\n#define unlink _unlink\n#endif\n#endif\n\n\n#if defined(HAVE__FSEEKI64) && defined(HAVE__FSTAT64) && defined(HAVE__SEEK64)\n/* Windows API using int64 */\ntypedef zip_int64_t zip_off_t;\ntypedef struct _stat64 zip_os_stat_t;\n#define zip_os_stat _stat64\n#define zip_os_fstat _fstat64\n#define zip_os_seek _fseeki64\n#define ZIP_FSEEK_MAX ZIP_INT64_MAX\n#define ZIP_FSEEK_MIN ZIP_INT64_MIN\n#else\n\n/* Normal API */\n#include <sys/stat.h>\ntypedef struct stat zip_os_stat_t;\n#define zip_os_fstat fstat\n#define zip_os_stat stat\n\n#if defined(HAVE_FTELLO) && defined(HAVE_FSEEKO)\n/* Using off_t */\ntypedef off_t zip_off_t;\n#if SIZEOF_OFF_T == 8\n#define ZIP_OFF_MAX ZIP_INT64_MAX\n#define ZIP_OFF_MIN ZIP_INT64_MIN\n#elif SIZEOF_OFF_T == 4\n#define ZIP_OFF_MAX ZIP_INT32_MAX\n#define ZIP_OFF_MIN ZIP_INT32_MIN\n#elif SIZEOF_OFF_T == 2\n#define ZIP_OFF_MAX ZIP_INT16_MAX\n#define ZIP_OFF_MIN ZIP_INT16_MIN\n#else\n#error unsupported size of off_t\n#endif\n\n#define ZIP_FSEEK_MAX ZIP_OFF_MAX\n#define ZIP_FSEEK_MIN ZIP_OFF_MIN\n\n#define zip_os_fseek fseeko\n#define zip_os_ftell ftello\n#else\n\n/* Using long */\ntypedef long zip_off_t;\n#include <limits.h>\n#define ZIP_FSEEK_MAX LONG_MAX\n#define ZIP_FSEEK_MIN LONG_MIN\n\n#define zip_os_fseek fseek\n#define zip_os_ftell ftell\n#endif\n\n#endif\n\n#ifndef HAVE_FTELLO\n#define ftello(s) ((long)ftell((s)))\n#endif\n\n\n#ifdef HAVE_LOCALTIME_S\n#ifdef _WIN32\n/* Windows is incompatible to the C11 standard, hurray! */\n#define zip_localtime(t, tm) (localtime_s((tm), (t)) == 0 ? tm : NULL)\n#else\n#define zip_localtime localtime_s\n#endif\n#else\n#ifdef HAVE_LOCALTIME_R\n#define zip_localtime localtime_r\n#else\n#define zip_localtime(t, tm) (localtime(t))\n#endif\n#endif\n\n#ifndef HAVE_MEMCPY_S\n#define memcpy_s(dest, destsz, src, count) (memcpy((dest), (src), (count)) == NULL)\n#endif\n\n#ifndef HAVE_SNPRINTF_S\n#ifdef HAVE__SNPRINTF_S\n#define snprintf_s(buf, bufsz, fmt, ...) (_snprintf_s((buf), (bufsz), (bufsz), (fmt), __VA_ARGS__))\n#else\n#define snprintf_s snprintf\n#endif\n#endif\n\n#if !defined(HAVE_STRCASECMP)\n#if defined(HAVE__STRICMP)\n#define strcasecmp _stricmp\n#elif defined(HAVE_STRICMP)\n#define strcasecmp stricmp\n#endif\n#endif\n\n#ifndef HAVE_STRNCPY_S\n#define strncpy_s(dest, destsz, src, count) (strncpy((dest), (src), (count)), 0)\n#endif\n\n#ifndef HAVE_STRERROR_S\n#define strerrorlen_s(errnum) (strlen(strerror(errnum)))\n#define strerror_s(buf, bufsz, errnum) ((void)strncpy_s((buf), (bufsz), strerror(errnum), (bufsz)), (buf)[(bufsz)-1] = '\\0', strerrorlen_s(errnum) >= (bufsz))\n#else\n#ifndef HAVE_STRERRORLEN_S\n#define strerrorlen_s(errnum)   8192\n#endif\n#endif\n\n\n#ifndef SIZE_MAX\n#if SIZEOF_SIZE_T == 8\n#define SIZE_MAX ZIP_INT64_MAX\n#elif SIZEOF_SIZE_T == 4\n#define SIZE_MAX ZIP_INT32_MAX\n#elif SIZEOF_SIZE_T == 2\n#define SIZE_MAX ZIP_INT16_MAX\n#else\n#error unsupported size of size_t\n#endif\n#endif\n\n#ifndef PRId64\n#ifdef _MSC_VER\n#define PRId64 \"I64d\"\n#else\n#define PRId64 \"lld\"\n#endif\n#endif\n\n#ifndef PRIu64\n#ifdef _MSC_VER\n#define PRIu64 \"I64u\"\n#else\n#define PRIu64 \"llu\"\n#endif\n#endif\n\n#ifndef S_ISDIR\n#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)\n#endif\n\n#ifndef S_ISREG\n#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)\n#endif\n\n#endif /* compat.h */\n"
  },
  {
    "path": "external/libzip/lib/zip.h",
    "content": "#ifndef _HAD_ZIP_H\n#define _HAD_ZIP_H\n\n/*\n  zip.h -- exported declarations.\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#if defined(__has_feature)\n  #if !__has_feature(nullability)\n    #define _Nullable\n    #define _Nonnull\n  #endif\n#else\n  #define _Nullable\n  #define _Nonnull\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#if 0\n} /* fix autoindent */\n#endif\n#endif\n\n#include <zipconf.h>\n\n#ifndef ZIP_EXTERN\n#ifndef ZIP_STATIC\n#ifdef _WIN32\n#define ZIP_EXTERN __declspec(dllimport)\n#elif defined(__GNUC__) && __GNUC__ >= 4\n#define ZIP_EXTERN __attribute__((visibility(\"default\")))\n#else\n#define ZIP_EXTERN\n#endif\n#else\n#define ZIP_EXTERN\n#endif\n#endif\n\n#ifndef ZIP_DEPRECATED\n#if defined(__GNUC__) || defined(__clang__)\n#define ZIP_DEPRECATED(x) __attribute__((deprecated(x)))\n#elif defined(_MSC_VER)\n#define ZIP_DEPRECATED(x) __declspec(deprecated(x))\n#else\n#define ZIP_DEPRECATED(x)\n#endif\n#endif\n\n#include <stdio.h>\n#include <sys/types.h>\n#include <time.h>\n\n/* flags for zip_open */\n\n#define ZIP_CREATE 1\n#define ZIP_EXCL 2\n#define ZIP_CHECKCONS 4\n#define ZIP_TRUNCATE 8\n#define ZIP_RDONLY 16\n\n\n/* flags for zip_name_locate, zip_fopen, zip_stat, ... */\n\n#define ZIP_FL_NOCASE 1u       /* ignore case on name lookup */\n#define ZIP_FL_NODIR 2u        /* ignore directory component */\n#define ZIP_FL_COMPRESSED 4u   /* read compressed data */\n#define ZIP_FL_UNCHANGED 8u    /* use original data, ignoring changes */\n/* 16u was ZIP_FL_RECOMPRESS, which is deprecated */\n#define ZIP_FL_ENCRYPTED 32u   /* read encrypted data (implies ZIP_FL_COMPRESSED) */\n#define ZIP_FL_ENC_GUESS 0u    /* guess string encoding (is default) */\n#define ZIP_FL_ENC_RAW 64u     /* get unmodified string */\n#define ZIP_FL_ENC_STRICT 128u /* follow specification strictly */\n#define ZIP_FL_LOCAL 256u      /* in local header */\n#define ZIP_FL_CENTRAL 512u    /* in central directory */\n/*                           1024u    reserved for internal use */\n#define ZIP_FL_ENC_UTF_8 2048u /* string is UTF-8 encoded */\n#define ZIP_FL_ENC_CP437 4096u /* string is CP437 encoded */\n#define ZIP_FL_OVERWRITE 8192u /* zip_file_add: if file with name exists, overwrite (replace) it */\n\n/* archive global flags flags */\n\n#define ZIP_AFL_RDONLY  2u /* read only -- cannot be cleared */\n#define ZIP_AFL_IS_TORRENTZIP\t4u /* current archive is torrentzipped */\n#define ZIP_AFL_WANT_TORRENTZIP\t8u /* write archive in torrentzip format */\n#define ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE 16u /* don't remove file if archive is empty */\n\n\n/* create a new extra field */\n\n#define ZIP_EXTRA_FIELD_ALL ZIP_UINT16_MAX\n#define ZIP_EXTRA_FIELD_NEW ZIP_UINT16_MAX\n\n/* length parameter to various functions */\n\n#define ZIP_LENGTH_TO_END 0\n#define ZIP_LENGTH_UNCHECKED (-2) /* only supported by zip_source_file and its variants */\n\n/* libzip error codes */\n\n#define ZIP_ER_OK 0               /* N No error */\n#define ZIP_ER_MULTIDISK 1        /* N Multi-disk zip archives not supported */\n#define ZIP_ER_RENAME 2           /* S Renaming temporary file failed */\n#define ZIP_ER_CLOSE 3            /* S Closing zip archive failed */\n#define ZIP_ER_SEEK 4             /* S Seek error */\n#define ZIP_ER_READ 5             /* S Read error */\n#define ZIP_ER_WRITE 6            /* S Write error */\n#define ZIP_ER_CRC 7              /* N CRC error */\n#define ZIP_ER_ZIPCLOSED 8        /* N Containing zip archive was closed */\n#define ZIP_ER_NOENT 9            /* N No such file */\n#define ZIP_ER_EXISTS 10          /* N File already exists */\n#define ZIP_ER_OPEN 11            /* S Can't open file */\n#define ZIP_ER_TMPOPEN 12         /* S Failure to create temporary file */\n#define ZIP_ER_ZLIB 13            /* Z Zlib error */\n#define ZIP_ER_MEMORY 14          /* N Malloc failure */\n#define ZIP_ER_CHANGED 15         /* N Entry has been changed */\n#define ZIP_ER_COMPNOTSUPP 16     /* N Compression method not supported */\n#define ZIP_ER_EOF 17             /* N Premature end of file */\n#define ZIP_ER_INVAL 18           /* N Invalid argument */\n#define ZIP_ER_NOZIP 19           /* N Not a zip archive */\n#define ZIP_ER_INTERNAL 20        /* N Internal error */\n#define ZIP_ER_INCONS 21          /* L Zip archive inconsistent */\n#define ZIP_ER_REMOVE 22          /* S Can't remove file */\n#define ZIP_ER_DELETED 23         /* N Entry has been deleted */\n#define ZIP_ER_ENCRNOTSUPP 24     /* N Encryption method not supported */\n#define ZIP_ER_RDONLY 25          /* N Read-only archive */\n#define ZIP_ER_NOPASSWD 26        /* N No password provided */\n#define ZIP_ER_WRONGPASSWD 27     /* N Wrong password provided */\n#define ZIP_ER_OPNOTSUPP 28       /* N Operation not supported */\n#define ZIP_ER_INUSE 29           /* N Resource still in use */\n#define ZIP_ER_TELL 30            /* S Tell error */\n#define ZIP_ER_COMPRESSED_DATA 31 /* N Compressed data invalid */\n#define ZIP_ER_CANCELLED 32       /* N Operation cancelled */\n#define ZIP_ER_DATA_LENGTH 33     /* N Unexpected length of data */\n#define ZIP_ER_NOT_ALLOWED 34     /* N Not allowed in torrentzip */\n#define ZIP_ER_TRUNCATED_ZIP 35   /* N Possibly truncated or corrupted zip archive */\n\n/* type of system error value */\n\n#define ZIP_ET_NONE 0   /* sys_err unused */\n#define ZIP_ET_SYS 1    /* sys_err is errno */\n#define ZIP_ET_ZLIB 2   /* sys_err is zlib error code */\n#define ZIP_ET_LIBZIP 3 /* sys_err is libzip error code */\n\n/* compression methods */\n\n#define ZIP_CM_DEFAULT -1 /* better of deflate or store */\n#define ZIP_CM_STORE 0    /* stored (uncompressed) */\n#define ZIP_CM_SHRINK 1   /* shrunk */\n#define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */\n#define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */\n#define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */\n#define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */\n#define ZIP_CM_IMPLODE 6  /* imploded */\n/* 7 - Reserved for Tokenizing compression algorithm */\n#define ZIP_CM_DEFLATE 8         /* deflated */\n#define ZIP_CM_DEFLATE64 9       /* deflate64 */\n#define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */\n/* 11 - Reserved by PKWARE */\n#define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */\n/* 13 - Reserved by PKWARE */\n#define ZIP_CM_LZMA 14 /* LZMA (EFS) */\n/* 15-17 - Reserved by PKWARE */\n#define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */\n#define ZIP_CM_LZ77 19  /* IBM LZ77 z Architecture (PFS) */\n/* 20 - old value for Zstandard */\n#define ZIP_CM_LZMA2 33\n#define ZIP_CM_ZSTD 93    /* Zstandard compressed data */\n#define ZIP_CM_XZ 95      /* XZ compressed data */\n#define ZIP_CM_JPEG 96    /* Compressed Jpeg data */\n#define ZIP_CM_WAVPACK 97 /* WavPack compressed data */\n#define ZIP_CM_PPMD 98    /* PPMd version I, Rev 1 */\n\n/* encryption methods */\n\n#define ZIP_EM_NONE 0         /* not encrypted */\n#define ZIP_EM_TRAD_PKWARE 1  /* traditional PKWARE encryption */\n#if 0                         /* Strong Encryption Header not parsed yet */\n#define ZIP_EM_DES 0x6601     /* strong encryption: DES */\n#define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */\n#define ZIP_EM_3DES_168 0x6603\n#define ZIP_EM_3DES_112 0x6609\n#define ZIP_EM_PKZIP_AES_128 0x660e\n#define ZIP_EM_PKZIP_AES_192 0x660f\n#define ZIP_EM_PKZIP_AES_256 0x6610\n#define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */\n#define ZIP_EM_RC4 0x6801\n#endif\n#define ZIP_EM_AES_128 0x0101 /* Winzip AES encryption */\n#define ZIP_EM_AES_192 0x0102\n#define ZIP_EM_AES_256 0x0103\n#define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */\n\n#define ZIP_OPSYS_DOS 0x00u\n#define ZIP_OPSYS_AMIGA 0x01u\n#define ZIP_OPSYS_OPENVMS 0x02u\n#define ZIP_OPSYS_UNIX 0x03u\n#define ZIP_OPSYS_VM_CMS 0x04u\n#define ZIP_OPSYS_ATARI_ST 0x05u\n#define ZIP_OPSYS_OS_2 0x06u\n#define ZIP_OPSYS_MACINTOSH 0x07u\n#define ZIP_OPSYS_Z_SYSTEM 0x08u\n#define ZIP_OPSYS_CPM 0x09u\n#define ZIP_OPSYS_WINDOWS_NTFS 0x0au\n#define ZIP_OPSYS_MVS 0x0bu\n#define ZIP_OPSYS_VSE 0x0cu\n#define ZIP_OPSYS_ACORN_RISC 0x0du\n#define ZIP_OPSYS_VFAT 0x0eu\n#define ZIP_OPSYS_ALTERNATE_MVS 0x0fu\n#define ZIP_OPSYS_BEOS 0x10u\n#define ZIP_OPSYS_TANDEM 0x11u\n#define ZIP_OPSYS_OS_400 0x12u\n#define ZIP_OPSYS_OS_X 0x13u\n\n#define ZIP_OPSYS_DEFAULT ZIP_OPSYS_UNIX\n\n\nenum zip_source_cmd {\n    ZIP_SOURCE_OPEN,                /* prepare for reading */\n    ZIP_SOURCE_READ,                /* read data */\n    ZIP_SOURCE_CLOSE,               /* reading is done */\n    ZIP_SOURCE_STAT,                /* get meta information */\n    ZIP_SOURCE_ERROR,               /* get error information */\n    ZIP_SOURCE_FREE,                /* cleanup and free resources */\n    ZIP_SOURCE_SEEK,                /* set position for reading */\n    ZIP_SOURCE_TELL,                /* get read position */\n    ZIP_SOURCE_BEGIN_WRITE,         /* prepare for writing */\n    ZIP_SOURCE_COMMIT_WRITE,        /* writing is done */\n    ZIP_SOURCE_ROLLBACK_WRITE,      /* discard written changes */\n    ZIP_SOURCE_WRITE,               /* write data */\n    ZIP_SOURCE_SEEK_WRITE,          /* set position for writing */\n    ZIP_SOURCE_TELL_WRITE,          /* get write position */\n    ZIP_SOURCE_SUPPORTS,            /* check whether source supports command */\n    ZIP_SOURCE_REMOVE,              /* remove file */\n    ZIP_SOURCE_RESERVED_1,          /* previously used internally */\n    ZIP_SOURCE_BEGIN_WRITE_CLONING, /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */\n    ZIP_SOURCE_ACCEPT_EMPTY,        /* whether empty files are valid archives */\n    ZIP_SOURCE_GET_FILE_ATTRIBUTES, /* get additional file attributes */\n    ZIP_SOURCE_SUPPORTS_REOPEN,     /* allow reading from changed entry */\n    ZIP_SOURCE_GET_DOS_TIME         /* get last modification time in DOS format */\n};\ntypedef enum zip_source_cmd zip_source_cmd_t;\n\n#define ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd) (((zip_int64_t)1) << (cmd))\n\n#define ZIP_SOURCE_CHECK_SUPPORTED(supported, cmd)  (((supported) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd)) != 0)\n\n/* clang-format off */\n\n#define ZIP_SOURCE_SUPPORTS_READABLE\t(ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_OPEN) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_READ) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_CLOSE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_STAT) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ERROR) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_FREE))\n\n#define ZIP_SOURCE_SUPPORTS_SEEKABLE\t(ZIP_SOURCE_SUPPORTS_READABLE \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS))\n\n#define ZIP_SOURCE_SUPPORTS_WRITABLE    (ZIP_SOURCE_SUPPORTS_SEEKABLE \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_COMMIT_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ROLLBACK_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL_WRITE) \\\n                                         | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_REMOVE))\n\n/* clang-format on */\n\n/* for use by sources */\nstruct zip_source_args_seek {\n    zip_int64_t offset;\n    int whence;\n};\n\ntypedef struct zip_source_args_seek zip_source_args_seek_t;\n#define ZIP_SOURCE_GET_ARGS(type, data, len, error) ((len) < sizeof(type) ? zip_error_set((error), ZIP_ER_INVAL, 0), (type *)NULL : (type *)(data))\n\n\n/* error information */\n/* use zip_error_*() to access */\nstruct zip_error {\n    int zip_err;         /* libzip error code (ZIP_ER_*) */\n    int sys_err;         /* copy of errno (E*) or zlib error code */\n    char *_Nullable str; /* string representation or NULL */\n};\n\n#define ZIP_STAT_NAME 0x0001u\n#define ZIP_STAT_INDEX 0x0002u\n#define ZIP_STAT_SIZE 0x0004u\n#define ZIP_STAT_COMP_SIZE 0x0008u\n#define ZIP_STAT_MTIME 0x0010u\n#define ZIP_STAT_CRC 0x0020u\n#define ZIP_STAT_COMP_METHOD 0x0040u\n#define ZIP_STAT_ENCRYPTION_METHOD 0x0080u\n#define ZIP_STAT_FLAGS 0x0100u\n\nstruct zip_stat {\n    zip_uint64_t valid;             /* which fields have valid values */\n    const char *_Nullable name;     /* name of the file */\n    zip_uint64_t index;             /* index within archive */\n    zip_uint64_t size;              /* size of file (uncompressed) */\n    zip_uint64_t comp_size;         /* size of file (compressed) */\n    time_t mtime;                   /* modification time */\n    zip_uint32_t crc;               /* crc of file data */\n    zip_uint16_t comp_method;       /* compression method used */\n    zip_uint16_t encryption_method; /* encryption method used */\n    zip_uint32_t flags;             /* reserved for future use */\n};\n\nstruct zip_buffer_fragment {\n    zip_uint8_t *_Nonnull data;\n    zip_uint64_t length;\n};\n\nstruct zip_file_attributes {\n    zip_uint64_t valid;                     /* which fields have valid values */\n    zip_uint8_t version;                    /* version of this struct, currently 1 */\n    zip_uint8_t host_system;                /* host system on which file was created */\n    zip_uint8_t ascii;                      /* flag whether file is ASCII text */\n    zip_uint8_t version_needed;             /* minimum version needed to extract file */\n    zip_uint32_t external_file_attributes;  /* external file attributes (host-system specific) */\n    zip_uint16_t general_purpose_bit_flags; /* general purpose big flags, only some bits are honored */\n    zip_uint16_t general_purpose_bit_mask;  /* which bits in general_purpose_bit_flags are valid */\n};\n\n#define ZIP_FILE_ATTRIBUTES_HOST_SYSTEM 0x0001u\n#define ZIP_FILE_ATTRIBUTES_ASCII 0x0002u\n#define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED 0x0004u\n#define ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES 0x0008u\n#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS 0x0010u\n\nstruct zip;\nstruct zip_file;\nstruct zip_source;\n\ntypedef struct zip zip_t;\ntypedef struct zip_error zip_error_t;\ntypedef struct zip_file zip_file_t;\ntypedef struct zip_file_attributes zip_file_attributes_t;\ntypedef struct zip_source zip_source_t;\ntypedef struct zip_stat zip_stat_t;\ntypedef struct zip_buffer_fragment zip_buffer_fragment_t;\n\ntypedef zip_uint32_t zip_flags_t;\n\ntypedef zip_int64_t (*zip_source_callback)(void *_Nullable, void *_Nullable, zip_uint64_t, zip_source_cmd_t);\ntypedef zip_int64_t (*zip_source_layered_callback)(zip_source_t *_Nonnull, void *_Nullable, void *_Nullable, zip_uint64_t, enum zip_source_cmd);\ntypedef void (*zip_progress_callback)(zip_t *_Nonnull, double, void *_Nullable);\ntypedef int (*zip_cancel_callback)(zip_t *_Nonnull, void *_Nullable);\n\n#ifndef ZIP_DISABLE_DEPRECATED\n#define ZIP_FL_RECOMPRESS 16u  /* force recompression of data */\n\ntypedef void (*zip_progress_callback_t)(double);\nZIP_DEPRECATED(\"use 'zip_register_progress_callback_with_state' instead\") ZIP_EXTERN void zip_register_progress_callback(zip_t *_Nonnull, zip_progress_callback_t _Nullable);\n\nZIP_DEPRECATED(\"use 'zip_file_add' instead\") ZIP_EXTERN zip_int64_t zip_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull);\nZIP_DEPRECATED(\"use 'zip_dir_add' instead\") ZIP_EXTERN zip_int64_t zip_add_dir(zip_t *_Nonnull, const char *_Nonnull);\nZIP_DEPRECATED(\"use 'zip_file_get_comment' instead\") ZIP_EXTERN const char *_Nullable zip_get_file_comment(zip_t *_Nonnull, zip_uint64_t, int *_Nullable, int);\nZIP_DEPRECATED(\"use 'zip_get_num_entries' instead\") ZIP_EXTERN int zip_get_num_files(zip_t *_Nonnull);\nZIP_DEPRECATED(\"use 'zip_file_rename' instead\") ZIP_EXTERN int zip_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull);\nZIP_DEPRECATED(\"use 'zip_file_replace' instead\") ZIP_EXTERN int zip_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull);\nZIP_DEPRECATED(\"use 'zip_file_set_comment' instead\") ZIP_EXTERN int zip_set_file_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, int);\nZIP_DEPRECATED(\"use 'zip_error_init_with_code' and 'zip_error_system_type' instead\") ZIP_EXTERN int zip_error_get_sys_type(int);\nZIP_DEPRECATED(\"use 'zip_get_error' instead\") ZIP_EXTERN void zip_error_get(zip_t *_Nonnull, int *_Nullable, int *_Nullable);\nZIP_DEPRECATED(\"use 'zip_error_strerror' instead\") ZIP_EXTERN int zip_error_to_str(char *_Nonnull, zip_uint64_t, int, int);\nZIP_DEPRECATED(\"use 'zip_file_get_error' instead\") ZIP_EXTERN void zip_file_error_get(zip_file_t *_Nonnull, int *_Nullable, int *_Nullable);\nZIP_DEPRECATED(\"use 'zip_source_zip_file' instead\") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t);\nZIP_DEPRECATED(\"use 'zip_source_zip_file_create' instead\") ZIP_EXTERN zip_source_t *_Nullable zip_source_zip_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\n#endif\n\nZIP_EXTERN int zip_close(zip_t *_Nonnull);\nZIP_EXTERN int zip_delete(zip_t *_Nonnull, zip_uint64_t);\nZIP_EXTERN zip_int64_t zip_dir_add(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);\nZIP_EXTERN void zip_discard(zip_t *_Nonnull);\n\nZIP_EXTERN zip_error_t *_Nonnull zip_get_error(zip_t *_Nonnull);\nZIP_EXTERN void zip_error_clear(zip_t *_Nonnull);\nZIP_EXTERN int zip_error_code_zip(const zip_error_t *_Nonnull);\nZIP_EXTERN int zip_error_code_system(const zip_error_t *_Nonnull);\nZIP_EXTERN void zip_error_fini(zip_error_t *_Nonnull);\nZIP_EXTERN void zip_error_init(zip_error_t *_Nonnull);\nZIP_EXTERN void zip_error_init_with_code(zip_error_t *_Nonnull, int);\nZIP_EXTERN void zip_error_set(zip_error_t *_Nullable, int, int);\nZIP_EXTERN void zip_error_set_from_source(zip_error_t *_Nonnull, zip_source_t *_Nullable);\nZIP_EXTERN const char *_Nonnull zip_error_strerror(zip_error_t *_Nonnull);\nZIP_EXTERN int zip_error_system_type(const zip_error_t *_Nonnull);\nZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *_Nonnull, void *_Nonnull, zip_uint64_t);\n\nZIP_EXTERN int zip_fclose(zip_file_t *_Nonnull);\nZIP_EXTERN zip_t *_Nullable zip_fdopen(int, int, int *_Nullable);\nZIP_EXTERN zip_int64_t zip_file_add(zip_t *_Nonnull, const char *_Nonnull, zip_source_t *_Nonnull, zip_flags_t);\nZIP_EXTERN void zip_file_attributes_init(zip_file_attributes_t *_Nonnull);\nZIP_EXTERN void zip_file_error_clear(zip_file_t *_Nonnull);\nZIP_EXTERN int zip_file_extra_field_delete(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);\nZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);\nZIP_EXTERN int zip_file_extra_field_set(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *_Nullable, zip_uint16_t, zip_flags_t);\nZIP_EXTERN zip_int16_t zip_file_extra_fields_count(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);\nZIP_EXTERN zip_int16_t zip_file_extra_fields_count_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_flags_t);\nZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_uint16_t *_Nullable, zip_flags_t);\nZIP_EXTERN const zip_uint8_t *_Nullable zip_file_extra_field_get_by_id(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *_Nullable, zip_flags_t);\nZIP_EXTERN const char *_Nullable zip_file_get_comment(zip_t *_Nonnull, zip_uint64_t, zip_uint32_t *_Nullable, zip_flags_t);\nZIP_EXTERN zip_error_t *_Nonnull zip_file_get_error(zip_file_t *_Nonnull);\nZIP_EXTERN int zip_file_get_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t *_Nullable, zip_uint32_t *_Nullable);\nZIP_EXTERN int zip_file_is_seekable(zip_file_t *_Nonnull);\nZIP_EXTERN int zip_file_rename(zip_t *_Nonnull, zip_uint64_t, const char *_Nonnull, zip_flags_t);\nZIP_EXTERN int zip_file_replace(zip_t *_Nonnull, zip_uint64_t, zip_source_t *_Nonnull, zip_flags_t);\nZIP_EXTERN int zip_file_set_comment(zip_t *_Nonnull, zip_uint64_t, const char *_Nullable, zip_uint16_t, zip_flags_t);\nZIP_EXTERN int zip_file_set_dostime(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);\nZIP_EXTERN int zip_file_set_encryption(zip_t *_Nonnull, zip_uint64_t, zip_uint16_t, const char *_Nullable);\nZIP_EXTERN int zip_file_set_external_attributes(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);\nZIP_EXTERN int zip_file_set_mtime(zip_t *_Nonnull, zip_uint64_t, time_t, zip_flags_t);\nZIP_EXTERN const char *_Nonnull zip_file_strerror(zip_file_t *_Nonnull);\nZIP_EXTERN zip_file_t *_Nullable zip_fopen(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);\nZIP_EXTERN zip_file_t *_Nullable zip_fopen_encrypted(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, const char *_Nullable);\nZIP_EXTERN zip_file_t *_Nullable zip_fopen_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);\nZIP_EXTERN zip_file_t *_Nullable zip_fopen_index_encrypted(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, const char *_Nullable);\nZIP_EXTERN zip_int64_t zip_fread(zip_file_t *_Nonnull, void *_Nonnull, zip_uint64_t);\nZIP_EXTERN zip_int8_t zip_fseek(zip_file_t *_Nonnull, zip_int64_t, int);\nZIP_EXTERN zip_int64_t zip_ftell(zip_file_t *_Nonnull);\nZIP_EXTERN const char *_Nullable zip_get_archive_comment(zip_t *_Nonnull, int *_Nullable, zip_flags_t);\nZIP_EXTERN int zip_get_archive_flag(zip_t *_Nonnull, zip_flags_t, zip_flags_t);\nZIP_EXTERN const char *_Nullable zip_get_name(zip_t *_Nonnull, zip_uint64_t, zip_flags_t);\nZIP_EXTERN zip_int64_t zip_get_num_entries(zip_t *_Nonnull, zip_flags_t);\nZIP_EXTERN const char *_Nonnull zip_libzip_version(void);\nZIP_EXTERN zip_int64_t zip_name_locate(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t);\nZIP_EXTERN zip_t *_Nullable zip_open(const char *_Nonnull, int, int *_Nullable);\nZIP_EXTERN zip_t *_Nullable zip_open_from_source(zip_source_t *_Nonnull, int, zip_error_t *_Nullable);\nZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *_Nonnull, double, zip_progress_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable);\nZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t *_Nonnull, zip_cancel_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable);\nZIP_EXTERN int zip_set_archive_comment(zip_t *_Nonnull, const char *_Nullable, zip_uint16_t);\nZIP_EXTERN int zip_set_archive_flag(zip_t *_Nonnull, zip_flags_t, int);\nZIP_EXTERN int zip_set_default_password(zip_t *_Nonnull, const char *_Nullable);\nZIP_EXTERN int zip_set_file_compression(zip_t *_Nonnull, zip_uint64_t, zip_int32_t, zip_uint32_t);\nZIP_EXTERN int zip_source_begin_write(zip_source_t *_Nonnull);\nZIP_EXTERN int zip_source_begin_write_cloning(zip_source_t *_Nonnull, zip_uint64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_buffer(zip_t *_Nonnull, const void *_Nullable, zip_uint64_t, int);\nZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_create(const void *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment(zip_t *_Nonnull, const zip_buffer_fragment_t *_Nonnull, zip_uint64_t, int);\nZIP_EXTERN zip_source_t *_Nullable zip_source_buffer_fragment_create(const zip_buffer_fragment_t *_Nullable, zip_uint64_t, int, zip_error_t *_Nullable);\nZIP_EXTERN int zip_source_close(zip_source_t *_Nonnull);\nZIP_EXTERN int zip_source_commit_write(zip_source_t *_Nonnull);\nZIP_EXTERN zip_error_t *_Nonnull zip_source_error(zip_source_t *_Nonnull);\nZIP_EXTERN zip_source_t *_Nullable zip_source_file(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_file_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_filep(zip_t *_Nonnull, FILE *_Nonnull, zip_uint64_t, zip_int64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_filep_create(FILE *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\nZIP_EXTERN void zip_source_free(zip_source_t *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_function(zip_t *_Nonnull, zip_source_callback _Nonnull, void *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_function_create(zip_source_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable);\nZIP_EXTERN int zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull);\nZIP_EXTERN int zip_source_is_deleted(zip_source_t *_Nonnull);\nZIP_EXTERN int zip_source_is_seekable(zip_source_t *_Nonnull);\nZIP_EXTERN void zip_source_keep(zip_source_t *_Nonnull);\nZIP_EXTERN zip_source_t *_Nullable zip_source_layered(zip_t *_Nullable, zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_layered_create(zip_source_t *_Nonnull, zip_source_layered_callback _Nonnull, void *_Nullable, zip_error_t *_Nullable);\nZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t, ...);\nZIP_EXTERN int zip_source_open(zip_source_t *_Nonnull);\nZIP_EXTERN zip_int64_t zip_source_pass_to_lower_layer(zip_source_t *_Nonnull, void *_Nullable, zip_uint64_t, zip_source_cmd_t);\nZIP_EXTERN zip_int64_t zip_source_read(zip_source_t *_Nonnull, void *_Nonnull, zip_uint64_t);\nZIP_EXTERN void zip_source_rollback_write(zip_source_t *_Nonnull);\nZIP_EXTERN int zip_source_seek(zip_source_t *_Nonnull, zip_int64_t, int);\nZIP_EXTERN zip_int64_t zip_source_seek_compute_offset(zip_uint64_t, zip_uint64_t, void *_Nonnull, zip_uint64_t, zip_error_t *_Nullable);\nZIP_EXTERN int zip_source_seek_write(zip_source_t *_Nonnull, zip_int64_t, int);\nZIP_EXTERN int zip_source_stat(zip_source_t *_Nonnull, zip_stat_t *_Nonnull);\nZIP_EXTERN zip_int64_t zip_source_tell(zip_source_t *_Nonnull);\nZIP_EXTERN zip_int64_t zip_source_tell_write(zip_source_t *_Nonnull);\n#ifdef _WIN32\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32a(zip_t *_Nonnull, const char *_Nonnull, zip_uint64_t, zip_int64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32a_create(const char *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32handle(zip_t *_Nonnull, void *_Nonnull, zip_uint64_t, zip_int64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32handle_create(void *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32w(zip_t *_Nonnull, const wchar_t *_Nonnull, zip_uint64_t, zip_int64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_win32w_create(const wchar_t *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\n#endif\nZIP_EXTERN zip_source_t *_Nullable zip_source_window_create(zip_source_t *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);\nZIP_EXTERN zip_int64_t zip_source_write(zip_source_t *_Nonnull, const void *_Nullable, zip_uint64_t);\nZIP_EXTERN zip_source_t *_Nullable zip_source_zip_file(zip_t *_Nonnull, zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable);\nZIP_EXTERN zip_source_t *_Nullable zip_source_zip_file_create(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_int64_t, const char *_Nullable, zip_error_t *_Nullable);\nZIP_EXTERN int zip_stat(zip_t *_Nonnull, const char *_Nonnull, zip_flags_t, zip_stat_t *_Nonnull);\nZIP_EXTERN int zip_stat_index(zip_t *_Nonnull, zip_uint64_t, zip_flags_t, zip_stat_t *_Nonnull);\nZIP_EXTERN void zip_stat_init(zip_stat_t *_Nonnull);\nZIP_EXTERN const char *_Nonnull zip_strerror(zip_t *_Nonnull);\nZIP_EXTERN int zip_unchange(zip_t *_Nonnull, zip_uint64_t);\nZIP_EXTERN int zip_unchange_all(zip_t *_Nonnull);\nZIP_EXTERN int zip_unchange_archive(zip_t *_Nonnull);\nZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress);\nZIP_EXTERN int zip_encryption_method_supported(zip_uint16_t method, int encode);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _HAD_ZIP_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_add.c",
    "content": "/*\n  zip_add.c -- add file via callback function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\n/*\n  NOTE: Return type is signed so we can return -1 on error.\n        The index can not be larger than ZIP_INT64_MAX since the size\n        of the central directory cannot be larger than\n        ZIP_UINT64_MAX, and each entry is larger than 2 bytes.\n*/\n\nZIP_EXTERN zip_int64_t\nzip_add(zip_t *za, const char *name, zip_source_t *source) {\n    return zip_file_add(za, name, source, 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_add_dir.c",
    "content": "/*\n  zip_add_dir.c -- add directory\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\n/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */\n\nZIP_EXTERN zip_int64_t\nzip_add_dir(zip_t *za, const char *name) {\n    return zip_dir_add(za, name, 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_add_entry.c",
    "content": "/*\n  zip_add_entry.c -- create and init struct zip_entry\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\n/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */\n\nzip_int64_t\n_zip_add_entry(zip_t *za) {\n    zip_uint64_t idx;\n\n    if (za->nentry + 1 >= za->nentry_alloc) {\n        zip_uint64_t additional_entries = 2 * za->nentry_alloc;\n\n        if (additional_entries < 16) {\n            additional_entries = 16;\n        }\n        else if (additional_entries > 1024) {\n            additional_entries = 1024;\n        }\n\n        if (!ZIP_REALLOC(za->entry, za->nentry_alloc, additional_entries, &za->error)) {\n            return -1;\n        }\n    }\n\n    idx = za->nentry++;\n\n    _zip_entry_init(za->entry + idx);\n\n    return (zip_int64_t)idx;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_algorithm_bzip2.c",
    "content": "/*\n  zip_algorithm_bzip2.c -- bzip2 (de)compression routines\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include <bzlib.h>\n#include <limits.h>\n#include <stdlib.h>\n\nstruct ctx {\n    zip_error_t *error;\n    bool compress;\n    int compression_flags;\n    bool end_of_input;\n    bz_stream zstr;\n};\n\n\nstatic zip_uint64_t\nmaximum_compressed_size(zip_uint64_t uncompressed_size) {\n    zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.006);\n\n    if (compressed_size < uncompressed_size) {\n        return ZIP_UINT64_MAX;\n    }\n    return compressed_size;\n}\n\n\nstatic void *\nallocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) {\n    struct ctx *ctx;\n\n    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {\n        return NULL;\n    }\n\n    ctx->error = error;\n    ctx->compress = compress;\n    if (compression_flags >= 1 && compression_flags <= 9) {\n        ctx->compression_flags = (int)compression_flags;\n    }\n    else {\n        ctx->compression_flags = 9;\n    }\n    ctx->end_of_input = false;\n\n    ctx->zstr.bzalloc = NULL;\n    ctx->zstr.bzfree = NULL;\n    ctx->zstr.opaque = NULL;\n\n    return ctx;\n}\n\n\nstatic void *\ncompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(true, compression_flags, error);\n}\n\n\nstatic void *\ndecompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(false, compression_flags, error);\n}\n\n\nstatic void\ndeallocate(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    free(ctx);\n}\n\n\nstatic zip_uint16_t\ngeneral_purpose_bit_flags(void *ud) {\n    (void)ud;\n    return 0;\n}\n\n\nstatic int\nmap_error(int ret) {\n    switch (ret) {\n    case BZ_FINISH_OK:\n    case BZ_FLUSH_OK:\n    case BZ_OK:\n    case BZ_RUN_OK:\n    case BZ_STREAM_END:\n        return ZIP_ER_OK;\n\n    case BZ_DATA_ERROR:\n    case BZ_DATA_ERROR_MAGIC:\n    case BZ_UNEXPECTED_EOF:\n        return ZIP_ER_COMPRESSED_DATA;\n\n    case BZ_MEM_ERROR:\n        return ZIP_ER_MEMORY;\n\n    case BZ_PARAM_ERROR:\n        return ZIP_ER_INVAL;\n\n    case BZ_CONFIG_ERROR: /* actually, bzip2 miscompiled */\n    case BZ_IO_ERROR:\n    case BZ_OUTBUFF_FULL:\n    case BZ_SEQUENCE_ERROR:\n    default:\n        return ZIP_ER_INTERNAL;\n    }\n}\n\nstatic bool\nstart(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {\n    struct ctx *ctx = (struct ctx *)ud;\n    int ret;\n\n    (void)st;\n    (void)attributes;\n\n    ctx->zstr.avail_in = 0;\n    ctx->zstr.next_in = NULL;\n    ctx->zstr.avail_out = 0;\n    ctx->zstr.next_out = NULL;\n\n    if (ctx->compress) {\n        ret = BZ2_bzCompressInit(&ctx->zstr, ctx->compression_flags, 0, 30);\n    }\n    else {\n        ret = BZ2_bzDecompressInit(&ctx->zstr, 0, 0);\n    }\n\n    if (ret != BZ_OK) {\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic bool\nend(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n    int err;\n\n    if (ctx->compress) {\n        err = BZ2_bzCompressEnd(&ctx->zstr);\n    }\n    else {\n        err = BZ2_bzDecompressEnd(&ctx->zstr);\n    }\n\n    if (err != BZ_OK) {\n        zip_error_set(ctx->error, map_error(err), 0);\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic bool\ninput(void *ud, zip_uint8_t *data, zip_uint64_t length) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {\n        zip_error_set(ctx->error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n\n    ctx->zstr.avail_in = (unsigned int)length;\n    ctx->zstr.next_in = (char *)data;\n\n    return true;\n}\n\n\nstatic bool end_of_input(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    ctx->end_of_input = true;\n    return ctx->zstr.avail_in != 0;\n}\n\n\nstatic zip_compression_status_t\nprocess(void *ud, zip_uint8_t *data, zip_uint64_t *length) {\n    struct ctx *ctx = (struct ctx *)ud;\n    unsigned int avail_out;\n\n    int ret;\n\n    if (ctx->zstr.avail_in == 0 && !ctx->end_of_input) {\n        *length = 0;\n        return ZIP_COMPRESSION_NEED_DATA;\n    }\n\n    avail_out = (unsigned int)ZIP_MIN(UINT_MAX, *length);\n    ctx->zstr.avail_out = avail_out;\n    ctx->zstr.next_out = (char *)data;\n\n    if (ctx->compress) {\n        ret = BZ2_bzCompress(&ctx->zstr, ctx->end_of_input ? BZ_FINISH : BZ_RUN);\n    }\n    else {\n        ret = BZ2_bzDecompress(&ctx->zstr);\n    }\n\n    *length = avail_out - ctx->zstr.avail_out;\n\n    switch (ret) {\n    case BZ_FINISH_OK: /* compression */\n        return ZIP_COMPRESSION_OK;\n\n    case BZ_OK:     /* decompression */\n    case BZ_RUN_OK: /* compression */\n        if (ctx->zstr.avail_in == 0) {\n            return ZIP_COMPRESSION_NEED_DATA;\n        }\n        return ZIP_COMPRESSION_OK;\n\n    case BZ_STREAM_END:\n        return ZIP_COMPRESSION_END;\n\n    default:\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return ZIP_COMPRESSION_ERROR;\n    }\n}\n\n/* clang-format off */\n\nzip_compression_algorithm_t zip_algorithm_bzip2_compress = {\n    maximum_compressed_size,\n    compress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    46,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n\nzip_compression_algorithm_t zip_algorithm_bzip2_decompress = {\n    maximum_compressed_size,\n    decompress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    46,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n/* clang-format on */\n"
  },
  {
    "path": "external/libzip/lib/zip_algorithm_deflate.c",
    "content": "/*\n  zip_algorithm_deflate.c -- deflate (de)compression routines\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include <limits.h>\n#include <stdlib.h>\n#include <zlib.h>\n\nstruct ctx {\n    zip_error_t *error;\n    bool compress;\n    int level;\n    int mem_level;\n    bool end_of_input;\n    z_stream zstr;\n};\n\n\nstatic zip_uint64_t\nmaximum_compressed_size(zip_uint64_t uncompressed_size) {\n    /* max deflate size increase: size + ceil(size/16k)*5+6 */\n\n    zip_uint64_t compressed_size = uncompressed_size + (uncompressed_size + 16383) / 16384 * 5 + 6;\n\n    if (compressed_size < uncompressed_size) {\n        return ZIP_UINT64_MAX;\n    }\n    return compressed_size;\n}\n\n\nstatic void *\nallocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) {\n    struct ctx *ctx;\n\n    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ET_SYS, errno);\n        return NULL;\n    }\n\n    ctx->error = error;\n    ctx->compress = compress;\n    if (compression_flags >= 1 && compression_flags <= 9) {\n        ctx->level = (int)compression_flags;\n    }\n    else {\n        ctx->level = Z_BEST_COMPRESSION;\n    }\n    ctx->mem_level = compression_flags == TORRENTZIP_COMPRESSION_FLAGS ? TORRENTZIP_MEM_LEVEL : MAX_MEM_LEVEL;\n    ctx->end_of_input = false;\n\n    ctx->zstr.zalloc = Z_NULL;\n    ctx->zstr.zfree = Z_NULL;\n    ctx->zstr.opaque = NULL;\n\n    return ctx;\n}\n\n\nstatic void *\ncompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(true, compression_flags, error);\n}\n\n\nstatic void *\ndecompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(false, compression_flags, error);\n}\n\n\nstatic void\ndeallocate(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    free(ctx);\n}\n\n\nstatic zip_uint16_t\ngeneral_purpose_bit_flags(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    if (!ctx->compress) {\n        return 0;\n    }\n\n    if (ctx->level < 3) {\n        return 2 << 1;\n    }\n    else if (ctx->level > 7) {\n        return 1 << 1;\n    }\n    return 0;\n}\n\n\nstatic bool\nstart(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {\n    struct ctx *ctx = (struct ctx *)ud;\n    int ret;\n\n    (void)st;\n    (void)attributes;\n\n    ctx->zstr.avail_in = 0;\n    ctx->zstr.next_in = NULL;\n    ctx->zstr.avail_out = 0;\n    ctx->zstr.next_out = NULL;\n\n    if (ctx->compress) {\n        /* negative value to tell zlib not to write a header */\n        ret = deflateInit2(&ctx->zstr, ctx->level, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY);\n    }\n    else {\n        ret = inflateInit2(&ctx->zstr, -MAX_WBITS);\n    }\n\n    if (ret != Z_OK) {\n        zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);\n        return false;\n    }\n\n\n    return true;\n}\n\n\nstatic bool\nend(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n    int err;\n\n    if (ctx->compress) {\n        err = deflateEnd(&ctx->zstr);\n    }\n    else {\n        err = inflateEnd(&ctx->zstr);\n    }\n\n    if (err != Z_OK) {\n        zip_error_set(ctx->error, ZIP_ER_ZLIB, err);\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic bool\ninput(void *ud, zip_uint8_t *data, zip_uint64_t length) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {\n        zip_error_set(ctx->error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n\n    ctx->zstr.avail_in = (uInt)length;\n    ctx->zstr.next_in = (Bytef *)data;\n\n    return true;\n}\n\n\nstatic bool end_of_input(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    ctx->end_of_input = true;\n    return ctx->zstr.avail_in != 0;\n}\n\n\nstatic zip_compression_status_t\nprocess(void *ud, zip_uint8_t *data, zip_uint64_t *length) {\n    struct ctx *ctx = (struct ctx *)ud;\n    uInt avail_out;\n\n    int ret;\n\n    avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);\n    ctx->zstr.avail_out = avail_out;\n    ctx->zstr.next_out = (Bytef *)data;\n\n    if (ctx->compress) {\n        ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0);\n    }\n    else {\n        ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);\n    }\n\n    *length = avail_out - ctx->zstr.avail_out;\n\n    switch (ret) {\n    case Z_OK:\n        return ZIP_COMPRESSION_OK;\n\n    case Z_STREAM_END:\n        return ZIP_COMPRESSION_END;\n\n    case Z_BUF_ERROR:\n        if (ctx->zstr.avail_in == 0) {\n            return ZIP_COMPRESSION_NEED_DATA;\n        }\n\n        /* fallthrough */\n\n    default:\n        zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);\n        return ZIP_COMPRESSION_ERROR;\n    }\n}\n\n/* clang-format off */\n\nzip_compression_algorithm_t zip_algorithm_deflate_compress = {\n    maximum_compressed_size,\n    compress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n\nzip_compression_algorithm_t zip_algorithm_deflate_decompress = {\n    maximum_compressed_size,\n    decompress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n/* clang-format on */\n"
  },
  {
    "path": "external/libzip/lib/zip_algorithm_xz.c",
    "content": "/*\n  zip_algorithm_xz.c -- LZMA/XZ (de)compression routines\n  Bazed on zip_algorithm_deflate.c -- deflate (de)compression routines\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include <limits.h>\n#include <lzma.h>\n#include <stdlib.h>\n#include <zlib.h>\n\nenum header_state { INCOMPLETE, OUTPUT, DONE };\n\n#define HEADER_BYTES_ZIP 9\n#define HEADER_MAGIC_LENGTH 4\n#define HEADER_MAGIC1_OFFSET 0\n#define HEADER_MAGIC2_OFFSET 2\n#define HEADER_SIZE_OFFSET 9\n#define HEADER_SIZE_LENGTH 8\n#define HEADER_PARAMETERS_LENGTH 5\n#define HEADER_LZMA_ALONE_LENGTH (HEADER_PARAMETERS_LENGTH + HEADER_SIZE_LENGTH)\n\nstruct ctx {\n    zip_error_t *error;\n    bool compress;\n    zip_uint32_t compression_flags;\n    bool end_of_input;\n    lzma_stream zstr;\n    zip_uint16_t method;\n    /* header member is used for converting from zip to \"lzma alone\"\n     * format\n     *\n     * \"lzma alone\" file format starts with:\n     * 5 bytes lzma parameters\n     * 8 bytes uncompressed size\n     * compressed data\n     *\n     * zip archive on-disk format starts with\n     * 4 bytes magic (first two bytes vary, e.g. 0x0914 or 0x1002, next bytes are 0x0500)\n     * 5 bytes lzma parameters\n     * compressed data\n     *\n     * we read the data into a header of the form\n     * 4 bytes magic\n     * 5 bytes lzma parameters\n     * 8 bytes uncompressed size\n     */\n    zip_uint8_t header[HEADER_MAGIC_LENGTH + HEADER_LZMA_ALONE_LENGTH];\n    zip_uint8_t header_bytes_offset;\n    enum header_state header_state;\n    zip_uint64_t uncompresssed_size;\n};\n\n\nstatic zip_uint64_t\nmaximum_compressed_size(zip_uint64_t uncompressed_size) {\n    /*\n     According to https://sourceforge.net/p/sevenzip/discussion/45797/thread/b6bd62f8/\n\n     1) you can use\n     outSize = 1.10 * originalSize + 64 KB.\n     in most cases outSize is less then 1.02 from originalSize.\n     2) You can try LZMA2, where\n     outSize can be = 1.001 * originalSize + 1 KB.\n     */\n    /* 13 bytes added for lzma alone header */\n    zip_uint64_t compressed_size = (zip_uint64_t)((double)uncompressed_size * 1.1) + 64 * 1024 + 13;\n\n    if (compressed_size < uncompressed_size) {\n        return ZIP_UINT64_MAX;\n    }\n    return compressed_size;\n}\n\n\nstatic void *\nallocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error, zip_uint16_t method) {\n    struct ctx *ctx;\n\n    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    ctx->error = error;\n    ctx->compress = compress;\n    if (compression_flags <= 9) {\n        ctx->compression_flags = compression_flags;\n    } else {\n        ctx->compression_flags = 6; /* default value */\n    }\n    ctx->compression_flags |= LZMA_PRESET_EXTREME;\n    ctx->end_of_input = false;\n    memset(ctx->header, 0, sizeof(ctx->header));\n    ctx->header_bytes_offset = 0;\n    if (method == ZIP_CM_LZMA) {\n        ctx->header_state = INCOMPLETE;\n    }\n    else {\n        ctx->header_state = DONE;\n    }\n    memset(&ctx->zstr, 0, sizeof(ctx->zstr));\n    ctx->method = method;\n    return ctx;\n}\n\n\nstatic void *\ncompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    return allocate(true, compression_flags, error, method);\n}\n\n\nstatic void *\ndecompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    return allocate(false, compression_flags, error, method);\n}\n\n\nstatic void\ndeallocate(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n    free(ctx);\n}\n\n\nstatic zip_uint16_t\ngeneral_purpose_bit_flags(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    if (!ctx->compress) {\n        return 0;\n    }\n\n    if (ctx->method == ZIP_CM_LZMA) {\n        /* liblzma always returns an EOS/EOPM marker, see\n\t * https://sourceforge.net/p/lzmautils/discussion/708858/thread/84c5dbb9/#a5e4/3764 */\n\treturn 1 << 1;\n    }\n    return 0;\n}\n\nstatic int\nmap_error(lzma_ret ret) {\n    switch (ret) {\n    case LZMA_DATA_ERROR:\n    case LZMA_UNSUPPORTED_CHECK:\n        return ZIP_ER_COMPRESSED_DATA;\n\n    case LZMA_MEM_ERROR:\n        return ZIP_ER_MEMORY;\n\n    case LZMA_OPTIONS_ERROR:\n        return ZIP_ER_INVAL;\n\n    default:\n        return ZIP_ER_INTERNAL;\n    }\n}\n\n\nstatic bool\nstart(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {\n    struct ctx *ctx = (struct ctx *)ud;\n    lzma_ret ret;\n\n    lzma_options_lzma opt_lzma;\n    lzma_lzma_preset(&opt_lzma, ctx->compression_flags);\n    lzma_filter filters[] = {\n        {.id = (ctx->method == ZIP_CM_LZMA ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2), .options = &opt_lzma},\n        {.id = LZMA_VLI_UNKNOWN, .options = NULL},\n    };\n\n    ctx->zstr.avail_in = 0;\n    ctx->zstr.next_in = NULL;\n    ctx->zstr.avail_out = 0;\n    ctx->zstr.next_out = NULL;\n\n    if (ctx->compress) {\n        if (ctx->method == ZIP_CM_LZMA)\n            ret = lzma_alone_encoder(&ctx->zstr, filters[0].options);\n        else\n            ret = lzma_stream_encoder(&ctx->zstr, filters, LZMA_CHECK_CRC64);\n    }\n    else {\n        if (ctx->method == ZIP_CM_LZMA)\n            ret = lzma_alone_decoder(&ctx->zstr, UINT64_MAX);\n        else\n            ret = lzma_stream_decoder(&ctx->zstr, UINT64_MAX, LZMA_CONCATENATED);\n    }\n\n    if (ret != LZMA_OK) {\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return false;\n    }\n\n    /* If general purpose bits 1 & 2 are both zero, write real uncompressed size in header. */\n    if ((attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) && (attributes->general_purpose_bit_mask & 0x6) == 0x6 && (attributes->general_purpose_bit_flags & 0x06) == 0 && (st->valid & ZIP_STAT_SIZE)) {\n        ctx->uncompresssed_size = st->size;\n    }\n    else {\n        ctx->uncompresssed_size = ZIP_UINT64_MAX;\n    }\n\n    return true;\n}\n\n\nstatic bool\nend(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    lzma_end(&ctx->zstr);\n    return true;\n}\n\n\nstatic bool\ninput(void *ud, zip_uint8_t *data, zip_uint64_t length) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    if (length > UINT_MAX || ctx->zstr.avail_in > 0) {\n        zip_error_set(ctx->error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n\n    /* For decompression of LZMA1: Have we read the full \"lzma alone\" header yet? */\n    if (ctx->method == ZIP_CM_LZMA && !ctx->compress && ctx->header_state == INCOMPLETE) {\n        /* if not, get more of the data */\n        zip_uint8_t got = (zip_uint8_t)ZIP_MIN(HEADER_BYTES_ZIP - ctx->header_bytes_offset, length);\n        (void)memcpy_s(ctx->header + ctx->header_bytes_offset, sizeof(ctx->header) - ctx->header_bytes_offset, data, got);\n        ctx->header_bytes_offset += got;\n        length -= got;\n        data += got;\n        /* Do we have a complete header now? */\n        if (ctx->header_bytes_offset == HEADER_BYTES_ZIP) {\n            Bytef empty_buffer[1];\n            zip_buffer_t *buffer;\n            /* check magic */\n            if (ctx->header[HEADER_MAGIC2_OFFSET] != 0x05 || ctx->header[HEADER_MAGIC2_OFFSET + 1] != 0x00) {\n                /* magic does not match */\n                zip_error_set(ctx->error, ZIP_ER_COMPRESSED_DATA, 0);\n                return false;\n            }\n            /* set size of uncompressed data in \"lzma alone\" header to \"unknown\" */\n            if ((buffer = _zip_buffer_new(ctx->header + HEADER_SIZE_OFFSET, HEADER_SIZE_LENGTH)) == NULL) {\n                zip_error_set(ctx->error, ZIP_ER_MEMORY, 0);\n                return false;\n            }\n            _zip_buffer_put_64(buffer, ctx->uncompresssed_size);\n            _zip_buffer_free(buffer);\n            /* Feed header into \"lzma alone\" decoder, for\n             * initialization; this should not produce output. */\n            ctx->zstr.next_in = (void *)(ctx->header + HEADER_MAGIC_LENGTH);\n            ctx->zstr.avail_in = HEADER_LZMA_ALONE_LENGTH;\n            ctx->zstr.total_in = 0;\n            ctx->zstr.next_out = empty_buffer;\n            ctx->zstr.avail_out = sizeof(*empty_buffer);\n            ctx->zstr.total_out = 0;\n            /* this just initializes the decoder and does not produce output, so it consumes the complete header */\n            if (lzma_code(&ctx->zstr, LZMA_RUN) != LZMA_OK || ctx->zstr.total_out > 0) {\n                zip_error_set(ctx->error, ZIP_ER_COMPRESSED_DATA, 0);\n                return false;\n            }\n            ctx->header_state = DONE;\n        }\n    }\n    ctx->zstr.avail_in = (uInt)length;\n    ctx->zstr.next_in = (Bytef *)data;\n\n    return true;\n}\n\n\nstatic bool end_of_input(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    ctx->end_of_input = true;\n    return ctx->zstr.avail_in != 0;\n}\n\n\nstatic zip_compression_status_t\nprocess(void *ud, zip_uint8_t *data, zip_uint64_t *length) {\n    struct ctx *ctx = (struct ctx *)ud;\n    uInt avail_out;\n    lzma_ret ret;\n    /* for compression of LZMA1 */\n    if (ctx->method == ZIP_CM_LZMA && ctx->compress) {\n        if (ctx->header_state == INCOMPLETE) {\n            /* write magic to output buffer */\n            ctx->header[0] = 0x09;\n            ctx->header[1] = 0x14;\n            ctx->header[2] = 0x05;\n            ctx->header[3] = 0x00;\n            /* generate lzma parameters into output buffer */\n            ctx->zstr.avail_out = HEADER_LZMA_ALONE_LENGTH;\n            ctx->zstr.next_out = ctx->header + HEADER_MAGIC_LENGTH;\n            ret = lzma_code(&ctx->zstr, LZMA_RUN);\n            if (ret != LZMA_OK || ctx->zstr.avail_out != 0) {\n                /* assume that the whole header will be provided with the first call to lzma_code */\n                return ZIP_COMPRESSION_ERROR;\n            }\n            ctx->header_state = OUTPUT;\n        }\n        if (ctx->header_state == OUTPUT) {\n            /* write header */\n            zip_uint8_t write_len = (zip_uint8_t)ZIP_MIN(HEADER_BYTES_ZIP - ctx->header_bytes_offset, *length);\n            (void)memcpy_s(data, *length, ctx->header + ctx->header_bytes_offset, write_len);\n            ctx->header_bytes_offset += write_len;\n            *length = write_len;\n            if (ctx->header_bytes_offset == HEADER_BYTES_ZIP) {\n                ctx->header_state = DONE;\n            }\n            return ZIP_COMPRESSION_OK;\n        }\n    }\n\n    avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);\n    ctx->zstr.avail_out = avail_out;\n    ctx->zstr.next_out = (Bytef *)data;\n\n    ret = lzma_code(&ctx->zstr, ctx->end_of_input ? LZMA_FINISH : LZMA_RUN);\n    *length = avail_out - ctx->zstr.avail_out;\n\n    switch (ret) {\n    case LZMA_OK:\n        return ZIP_COMPRESSION_OK;\n\n    case LZMA_STREAM_END:\n        return ZIP_COMPRESSION_END;\n\n    case LZMA_BUF_ERROR:\n        if (ctx->zstr.avail_in == 0) {\n            return ZIP_COMPRESSION_NEED_DATA;\n        }\n\n        /* fallthrough */\n    default:\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return ZIP_COMPRESSION_ERROR;\n    }\n}\n\n/* Version Required should be set to 63 (6.3) because this compression\n   method was only defined in appnote.txt version 6.3.8, but Winzip\n   does not unpack it if the value is not 20. */\n\n/* clang-format off */\n\nzip_compression_algorithm_t zip_algorithm_xz_compress = {\n    maximum_compressed_size,\n    compress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n\nzip_compression_algorithm_t zip_algorithm_xz_decompress = {\n    maximum_compressed_size,\n    decompress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n/* clang-format on */\n"
  },
  {
    "path": "external/libzip/lib/zip_algorithm_zstd.c",
    "content": "/*\n  zip_algorithm_zstd.c -- zstd (de)compression routines\n  Copyright (C) 2020-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include <stdlib.h>\n#include <zstd.h>\n#include <zstd_errors.h>\n\nstruct ctx {\n    zip_error_t *error;\n    bool compress;\n    int compression_flags;\n    bool end_of_input;\n    ZSTD_DStream *zdstream;\n    ZSTD_CStream *zcstream;\n    ZSTD_outBuffer out;\n    ZSTD_inBuffer in;\n};\n\nstatic zip_uint64_t\nmaximum_compressed_size(zip_uint64_t uncompressed_size) {\n    return ZSTD_compressBound(uncompressed_size);\n}\n\n\nstatic void *\nallocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) {\n    struct ctx *ctx;\n\n    if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {\n        return NULL;\n    }\n\n    ctx->compression_flags = (zip_int32_t)compression_flags;\n    if (ctx->compression_flags < ZSTD_minCLevel() || ctx->compression_flags > ZSTD_maxCLevel()) {\n        ctx->compression_flags = 0; /* let zstd choose */\n    }\n\n    ctx->error = error;\n    ctx->compress = compress;\n    ctx->end_of_input = false;\n\n    ctx->zdstream = NULL;\n    ctx->zcstream = NULL;\n    ctx->in.src = NULL;\n    ctx->in.pos = 0;\n    ctx->in.size = 0;\n    ctx->out.dst = NULL;\n    ctx->out.pos = 0;\n    ctx->out.size = 0;\n\n    return ctx;\n}\n\n\nstatic void *\ncompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(true, compression_flags, error);\n}\n\n\nstatic void *\ndecompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) {\n    (void)method;\n    return allocate(false, compression_flags, error);\n}\n\n\nstatic void\ndeallocate(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n    free(ctx);\n}\n\n\nstatic zip_uint16_t\ngeneral_purpose_bit_flags(void *ud) {\n    (void)ud;\n    return 0;\n}\n\nstatic int\nmap_error(size_t ret) {\n    switch (ret) {\n    case ZSTD_error_no_error:\n        return ZIP_ER_OK;\n\n    case ZSTD_error_corruption_detected:\n    case ZSTD_error_checksum_wrong:\n    case ZSTD_error_dictionary_corrupted:\n    case ZSTD_error_dictionary_wrong:\n        return ZIP_ER_COMPRESSED_DATA;\n\n    case ZSTD_error_memory_allocation:\n        return ZIP_ER_MEMORY;\n\n    case ZSTD_error_parameter_unsupported:\n    case ZSTD_error_parameter_outOfBound:\n        return ZIP_ER_INVAL;\n\n    default:\n        return ZIP_ER_INTERNAL;\n    }\n}\n\n\nstatic bool\nstart(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    (void)st;\n    (void)attributes;\n\n    ctx->in.src = NULL;\n    ctx->in.pos = 0;\n    ctx->in.size = 0;\n    ctx->out.dst = NULL;\n    ctx->out.pos = 0;\n    ctx->out.size = 0;\n    if (ctx->compress) {\n        size_t ret;\n        ctx->zcstream = ZSTD_createCStream();\n        if (ctx->zcstream == NULL) {\n            zip_error_set(ctx->error, ZIP_ER_MEMORY, 0);\n            return false;\n        }\n        ret = ZSTD_initCStream(ctx->zcstream, ctx->compression_flags);\n        if (ZSTD_isError(ret)) {\n            zip_error_set(ctx->error, ZIP_ER_ZLIB, map_error(ret));\n            return false;\n        }\n    }\n    else {\n        ctx->zdstream = ZSTD_createDStream();\n        if (ctx->zdstream == NULL) {\n            zip_error_set(ctx->error, ZIP_ER_MEMORY, 0);\n            return false;\n        }\n    }\n\n    return true;\n}\n\n\nstatic bool\nend(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n    size_t ret;\n\n    if (ctx->compress) {\n        ret = ZSTD_freeCStream(ctx->zcstream);\n        ctx->zcstream = NULL;\n    }\n    else {\n        ret = ZSTD_freeDStream(ctx->zdstream);\n        ctx->zdstream = NULL;\n    }\n\n    if (ZSTD_isError(ret)) {\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic bool\ninput(void *ud, zip_uint8_t *data, zip_uint64_t length) {\n    struct ctx *ctx = (struct ctx *)ud;\n    if (length > SIZE_MAX || ctx->in.pos != ctx->in.size) {\n        zip_error_set(ctx->error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n    ctx->in.src = (const void *)data;\n    ctx->in.size = (size_t)length;\n    ctx->in.pos = 0;\n    return true;\n}\n\n\nstatic bool end_of_input(void *ud) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    ctx->end_of_input = true;\n    return ctx->in.pos != ctx->in.size;\n}\n\n\nstatic zip_compression_status_t\nprocess(void *ud, zip_uint8_t *data, zip_uint64_t *length) {\n    struct ctx *ctx = (struct ctx *)ud;\n\n    size_t ret;\n\n    if (ctx->in.pos == ctx->in.size && !ctx->end_of_input) {\n        *length = 0;\n        return ZIP_COMPRESSION_NEED_DATA;\n    }\n\n    ctx->out.dst = data;\n    ctx->out.pos = 0;\n    ctx->out.size = ZIP_MIN(SIZE_MAX, *length);\n\n    if (ctx->compress) {\n        if (ctx->in.pos == ctx->in.size && ctx->end_of_input) {\n            ret = ZSTD_endStream(ctx->zcstream, &ctx->out);\n            if (ret == 0) {\n                *length = ctx->out.pos;\n                return ZIP_COMPRESSION_END;\n            }\n        }\n        else {\n            ret = ZSTD_compressStream(ctx->zcstream, &ctx->out, &ctx->in);\n        }\n    }\n    else {\n        ret = ZSTD_decompressStream(ctx->zdstream, &ctx->out, &ctx->in);\n    }\n    if (ZSTD_isError(ret)) {\n        zip_error_set(ctx->error, map_error(ret), 0);\n        return ZIP_COMPRESSION_ERROR;\n    }\n\n    *length = ctx->out.pos;\n    if (ctx->in.pos == ctx->in.size) {\n        return ZIP_COMPRESSION_NEED_DATA;\n    }\n\n    return ZIP_COMPRESSION_OK;\n}\n\n/* Version Required should be set to 63 (6.3) because this compression\n   method was only defined in appnote.txt version 6.3.7, but Winzip\n   does not unpack it if the value is not 20. */\n\n/* clang-format off */\n\nzip_compression_algorithm_t zip_algorithm_zstd_compress = {\n    maximum_compressed_size,\n    compress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n\nzip_compression_algorithm_t zip_algorithm_zstd_decompress = {\n    maximum_compressed_size,\n    decompress_allocate,\n    deallocate,\n    general_purpose_bit_flags,\n    20,\n    start,\n    end,\n    input,\n    end_of_input,\n    process\n};\n\n/* clang-format on */\n"
  },
  {
    "path": "external/libzip/lib/zip_buffer.c",
    "content": "/*\n zip_buffer.c -- bounds checked access to memory buffer\n Copyright (C) 2014-2024 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\nzip_uint8_t *\n_zip_buffer_data(zip_buffer_t *buffer) {\n    return buffer->data;\n}\n\n\nvoid\n_zip_buffer_free(zip_buffer_t *buffer) {\n    if (buffer == NULL) {\n        return;\n    }\n\n    if (buffer->free_data) {\n        free(buffer->data);\n    }\n\n    free(buffer);\n}\n\n\nbool\n_zip_buffer_eof(zip_buffer_t *buffer) {\n    return buffer->ok && buffer->offset == buffer->size;\n}\n\n\nzip_uint8_t *\n_zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length) {\n    zip_uint8_t *data;\n\n    data = _zip_buffer_peek(buffer, length);\n\n    if (data != NULL) {\n        buffer->offset += length;\n    }\n\n    return data;\n}\n\n\nzip_uint16_t\n_zip_buffer_get_16(zip_buffer_t *buffer) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 2);\n\n    if (data == NULL) {\n        return 0;\n    }\n\n    return (zip_uint16_t)(data[0] + (data[1] << 8));\n}\n\n\nzip_uint32_t\n_zip_buffer_get_32(zip_buffer_t *buffer) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 4);\n\n    if (data == NULL) {\n        return 0;\n    }\n\n    return ((((((zip_uint32_t)data[3] << 8) + data[2]) << 8) + data[1]) << 8) + data[0];\n}\n\n\nzip_uint64_t\n_zip_buffer_get_64(zip_buffer_t *buffer) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 8);\n\n    if (data == NULL) {\n        return 0;\n    }\n\n    return ((zip_uint64_t)data[7] << 56) + ((zip_uint64_t)data[6] << 48) + ((zip_uint64_t)data[5] << 40) + ((zip_uint64_t)data[4] << 32) + ((zip_uint64_t)data[3] << 24) + ((zip_uint64_t)data[2] << 16) + ((zip_uint64_t)data[1] << 8) + (zip_uint64_t)data[0];\n}\n\n\nzip_uint8_t\n_zip_buffer_get_8(zip_buffer_t *buffer) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 1);\n\n    if (data == NULL) {\n        return 0;\n    }\n\n    return data[0];\n}\n\n\nzip_uint64_t\n_zip_buffer_left(zip_buffer_t *buffer) {\n    return buffer->ok ? buffer->size - buffer->offset : 0;\n}\n\n\nzip_uint64_t\n_zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) {\n    zip_uint64_t copied;\n\n    if (_zip_buffer_left(buffer) < length) {\n        length = _zip_buffer_left(buffer);\n    }\n\n    copied = 0;\n    while (copied < length) {\n        size_t n = ZIP_MIN(length - copied, SIZE_MAX);\n        (void)memcpy_s(data + copied, n, _zip_buffer_get(buffer, n), n);\n        copied += n;\n    }\n\n    return copied;\n}\n\n\nzip_buffer_t *\n_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size) {\n    bool free_data = (data == NULL);\n    zip_buffer_t *buffer;\n\n#if ZIP_UINT64_MAX > SIZE_MAX\n    if (size > SIZE_MAX) {\n        return NULL;\n    }\n#endif\n\n    if (data == NULL) {\n        if ((data = (zip_uint8_t *)malloc((size_t)size)) == NULL) {\n            return NULL;\n        }\n    }\n\n    if ((buffer = (zip_buffer_t *)malloc(sizeof(*buffer))) == NULL) {\n        if (free_data) {\n            free(data);\n        }\n        return NULL;\n    }\n\n    buffer->ok = true;\n    buffer->data = data;\n    buffer->size = size;\n    buffer->offset = 0;\n    buffer->free_data = free_data;\n\n    return buffer;\n}\n\n\nzip_buffer_t *\n_zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error) {\n    zip_buffer_t *buffer;\n\n    if ((buffer = _zip_buffer_new(buf, size)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (_zip_read(src, buffer->data, size, error) < 0) {\n        _zip_buffer_free(buffer);\n        return NULL;\n    }\n\n    return buffer;\n}\n\n\nzip_uint64_t\n_zip_buffer_offset(zip_buffer_t *buffer) {\n    return buffer->ok ? buffer->offset : 0;\n}\n\n\nbool\n_zip_buffer_ok(zip_buffer_t *buffer) {\n    return buffer->ok;\n}\n\n\nzip_uint8_t *\n_zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length) {\n    zip_uint8_t *data;\n\n    if (!buffer->ok || buffer->offset + length < length || buffer->offset + length > buffer->size) {\n        buffer->ok = false;\n        return NULL;\n    }\n\n    data = buffer->data + buffer->offset;\n    return data;\n}\n\nint\n_zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length) {\n    zip_uint8_t *dst = _zip_buffer_get(buffer, length);\n\n    if (dst == NULL) {\n        return -1;\n    }\n\n    (void)memcpy_s(dst, length, src, length);\n    return 0;\n}\n\n\nint\n_zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 2);\n\n    if (data == NULL) {\n        return -1;\n    }\n\n    data[0] = (zip_uint8_t)(i & 0xff);\n    data[1] = (zip_uint8_t)((i >> 8) & 0xff);\n\n    return 0;\n}\n\n\nint\n_zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 4);\n\n    if (data == NULL) {\n        return -1;\n    }\n\n    data[0] = (zip_uint8_t)(i & 0xff);\n    data[1] = (zip_uint8_t)((i >> 8) & 0xff);\n    data[2] = (zip_uint8_t)((i >> 16) & 0xff);\n    data[3] = (zip_uint8_t)((i >> 24) & 0xff);\n\n    return 0;\n}\n\n\nint\n_zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 8);\n\n    if (data == NULL) {\n        return -1;\n    }\n\n    data[0] = (zip_uint8_t)(i & 0xff);\n    data[1] = (zip_uint8_t)((i >> 8) & 0xff);\n    data[2] = (zip_uint8_t)((i >> 16) & 0xff);\n    data[3] = (zip_uint8_t)((i >> 24) & 0xff);\n    data[4] = (zip_uint8_t)((i >> 32) & 0xff);\n    data[5] = (zip_uint8_t)((i >> 40) & 0xff);\n    data[6] = (zip_uint8_t)((i >> 48) & 0xff);\n    data[7] = (zip_uint8_t)((i >> 56) & 0xff);\n\n    return 0;\n}\n\n\nint\n_zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i) {\n    zip_uint8_t *data = _zip_buffer_get(buffer, 1);\n\n    if (data == NULL) {\n        return -1;\n    }\n\n    data[0] = i;\n\n    return 0;\n}\n\n\nint _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset) {\n    if (offset > buffer->size) {\n        buffer->ok = false;\n        return -1;\n    }\n\n    buffer->ok = true;\n    buffer->offset = offset;\n\n    return 0;\n}\n\n\nint\n_zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length) {\n    zip_uint64_t offset = buffer->offset + length;\n\n    if (offset < buffer->offset) {\n        buffer->ok = false;\n        return -1;\n    }\n    return _zip_buffer_set_offset(buffer, offset);\n}\n\nzip_uint64_t\n_zip_buffer_size(zip_buffer_t *buffer) {\n    return buffer->size;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_close.c",
    "content": "/*\n  zip_close.c -- close zip archive and update changes\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#ifdef _WIN32\n#include <fcntl.h>\n#include <io.h>\n#endif\n\n\nstatic int add_data(zip_t *, zip_source_t *, zip_dirent_t *);\nstatic int copy_data(zip_t *, zip_uint64_t);\nstatic int copy_source(zip_t *, zip_source_t *, zip_source_t *, zip_int64_t);\nstatic int torrentzip_compare_names(const void *a, const void *b);\nstatic int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);\nstatic int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64);\n\nZIP_EXTERN int\nzip_close(zip_t *za) {\n    zip_uint64_t i, j, survivors, unchanged_offset;\n    zip_int64_t off;\n    int error;\n    zip_filelist_t *filelist;\n    int changed;\n\n    if (za == NULL)\n        return -1;\n\n    changed = _zip_changed(za, &survivors);\n\n    if (survivors == 0 && !(za->ch_flags & ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE)) {\n        /* don't create zip files with no entries */\n        if ((za->open_flags & ZIP_TRUNCATE) || changed) {\n            if (zip_source_remove(za->src) < 0) {\n                if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) {\n                    zip_error_set_from_source(&za->error, za->src);\n                    return -1;\n                }\n            }\n        }\n        zip_discard(za);\n        return 0;\n    }\n\n    /* Always write empty archive if we are told to keep it, otherwise it wouldn't be created if the file doesn't already exist. */\n    if (!changed && survivors > 0) {\n        zip_discard(za);\n        return 0;\n    }\n\n    if (survivors > za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL)\n        return -1;\n\n    unchanged_offset = ZIP_UINT64_MAX;\n    /* create list of files with index into original archive  */\n    for (i = j = 0; i < za->nentry; i++) {\n        if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {\n            unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset);\n        }\n        if (za->entry[i].deleted) {\n            continue;\n        }\n\n        if (j >= survivors) {\n            free(filelist);\n            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n\n        filelist[j].idx = i;\n        filelist[j].name = zip_get_name(za, i, 0);\n        j++;\n    }\n    if (j < survivors) {\n        free(filelist);\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names);\n    }\n\n    if (ZIP_WANT_TORRENTZIP(za) || (zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) {\n        unchanged_offset = 0;\n    }\n    else {\n        if (unchanged_offset == ZIP_UINT64_MAX) {\n            /* we're keeping all file data, find the end of the last one */\n            zip_uint64_t last_index = ZIP_UINT64_MAX;\n            unchanged_offset = 0;\n\n            for (i = 0; i < za->nentry; i++) {\n                if (za->entry[i].orig != NULL) {\n                    if (za->entry[i].orig->offset >= unchanged_offset) {\n                        unchanged_offset = za->entry[i].orig->offset;\n                        last_index = i;\n                    }\n                }\n            }\n            if (last_index != ZIP_UINT64_MAX) {\n                if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) {\n                    free(filelist);\n                    return -1;\n                }\n            }\n        }\n        if (unchanged_offset > 0) {\n            if (zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) {\n                /* cloning not supported, need to copy everything */\n                unchanged_offset = 0;\n            }\n        }\n    }\n    if (unchanged_offset == 0) {\n        if (zip_source_begin_write(za->src) < 0) {\n            zip_error_set_from_source(&za->error, za->src);\n            free(filelist);\n            return -1;\n        }\n    }\n\n    if (_zip_progress_start(za->progress) != 0) {\n        zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);\n        zip_source_rollback_write(za->src);\n        free(filelist);\n        return -1;\n    }\n    error = 0;\n    for (j = 0; j < survivors; j++) {\n        int new_data;\n        zip_entry_t *entry;\n        zip_dirent_t *de;\n\n        if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) {\n            zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);\n            error = 1;\n            break;\n        }\n\n        i = filelist[j].idx;\n        entry = za->entry + i;\n\n        if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {\n            /* already implicitly copied by cloning */\n            continue;\n        }\n\n        new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)) || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za));\n\n        /* create new local directory entry */\n        if (entry->changes == NULL) {\n            if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) {\n                zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n                error = 1;\n                break;\n            }\n        }\n        else if (entry->orig != NULL) {\n            if (!_zip_dirent_merge(entry->changes, entry->orig, ZIP_ENTRY_DATA_CHANGED(entry), &za->error)) {\n                error = 1;\n                break;\n            }\n        }\n        de = entry->changes;\n\n        if (_zip_read_local_ef(za, i) < 0) {\n            error = 1;\n            break;\n        }\n\n        if (ZIP_WANT_TORRENTZIP(za)) {\n            zip_dirent_torrentzip_normalize(entry->changes);\n        }\n\n        if ((off = zip_source_tell_write(za->src)) < 0) {\n            zip_error_set_from_source(&za->error, za->src);\n            error = 1;\n            break;\n        }\n        de->offset = (zip_uint64_t)off;\n\n        if (new_data) {\n            zip_source_t *zs;\n\n            zs = NULL;\n            if (!ZIP_ENTRY_DATA_CHANGED(entry)) {\n                if ((zs = zip_source_zip_file_create(za, i, ZIP_FL_UNCHANGED, 0, -1, NULL, &za->error)) == NULL) {\n                    error = 1;\n                    break;\n                }\n            }\n\n            /* add_data writes dirent */\n            if (add_data(za, zs ? zs : entry->source, de) < 0) {\n                error = 1;\n                if (zs)\n                    zip_source_free(zs);\n                break;\n            }\n            if (zs)\n                zip_source_free(zs);\n        }\n        else {\n            zip_uint64_t offset;\n\n            if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {\n                /* when copying data, all sizes are known -> no data descriptor needed */\n                /* except for PKWare encryption, where removing the data descriptor breaks password validation */\n                de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;\n            }\n            if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {\n                error = 1;\n                break;\n            }\n            if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) {\n                error = 1;\n                break;\n            }\n            if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {\n                zip_error_set_from_source(&za->error, za->src);\n                error = 1;\n                break;\n            }\n            if (copy_data(za, de->comp_size) < 0) {\n                error = 1;\n                break;\n            }\n\n            if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {\n                if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) {\n                    error = 1;\n                    break;\n                }\n            }\n        }\n    }\n\n    if (!error) {\n        if (write_cdir(za, filelist, survivors) < 0)\n            error = 1;\n    }\n\n    free(filelist);\n\n    if (!error) {\n        if (zip_source_commit_write(za->src) != 0) {\n            zip_error_set_from_source(&za->error, za->src);\n            error = 1;\n        }\n        _zip_progress_end(za->progress);\n    }\n\n    if (error) {\n        zip_source_rollback_write(za->src);\n        return -1;\n    }\n\n    zip_discard(za);\n\n    return 0;\n}\n\n\nstatic int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {\n    zip_int64_t offstart, offdata, offend, data_length;\n    zip_stat_t st;\n    zip_file_attributes_t attributes;\n    zip_source_t *src_final, *src_tmp;\n    int ret;\n    int is_zip64;\n    zip_flags_t flags;\n    bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;\n    bool dirent_changed;\n    bool have_dos_time = false;\n    time_t mtime_before_copy;\n\n    if (zip_source_stat(src, &st) < 0) {\n        zip_error_set_from_source(&za->error, src);\n        return -1;\n    }\n\n    de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;\n\n    if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {\n        st.valid |= ZIP_STAT_COMP_METHOD;\n        st.comp_method = ZIP_CM_STORE;\n    }\n\n    if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) {\n        de->comp_method = st.comp_method;\n    }\n    else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {\n        st.valid |= ZIP_STAT_COMP_SIZE;\n        st.comp_size = st.size;\n    }\n    else {\n        /* we'll recompress */\n        st.valid &= ~ZIP_STAT_COMP_SIZE;\n    }\n\n    if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) {\n        st.valid |= ZIP_STAT_ENCRYPTION_METHOD;\n        st.encryption_method = ZIP_EM_NONE;\n    }\n\n    flags = ZIP_EF_LOCAL;\n\n    if ((st.valid & ZIP_STAT_SIZE) == 0) {\n        /* TODO: not valid for torrentzip */\n        flags |= ZIP_FL_FORCE_ZIP64;\n        data_length = -1;\n    }\n    else {\n        de->uncomp_size = st.size;\n        /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */\n        data_length = (zip_int64_t)st.size;\n\n        if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {\n            zip_uint64_t max_compressed_size;\n            zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method);\n\n            if (compression_method == ZIP_CM_STORE) {\n                max_compressed_size = st.size;\n            }\n            else {\n                zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);\n                if (algorithm == NULL) {\n                    max_compressed_size = ZIP_UINT64_MAX;\n                }\n                else {\n                    max_compressed_size = algorithm->maximum_compressed_size(st.size);\n                }\n            }\n\n            if (max_compressed_size > 0xffffffffu) {\n                /* TODO: not valid for torrentzip */\n                flags |= ZIP_FL_FORCE_ZIP64;\n            }\n        }\n        else {\n            de->comp_size = st.comp_size;\n            data_length = (zip_int64_t)st.comp_size;\n        }\n    }\n\n    if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {\n        int ret2 = zip_source_get_dos_time(src, &de->last_mod);\n        if (ret2 < 0) {\n            zip_error_set_from_source(&za->error, src);\n            return -1;\n        }\n        if (ret2 == 1) {\n            have_dos_time = true;\n        }\n        else {\n            if (st.valid & ZIP_STAT_MTIME) {\n                mtime_before_copy = st.mtime;\n            }\n            else {\n                time(&mtime_before_copy);\n            }\n            if (_zip_u2d_time(mtime_before_copy, &de->last_mod, &za->error) < 0) {\n                return -1;\n            }\n        }\n    }\n\n    if ((offstart = zip_source_tell_write(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n\n    needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method);\n    needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);\n    /* in these cases we can compute the CRC ourselves, so we do */\n    needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;\n    needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);\n\n    needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);\n    needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);\n    needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);\n\n    src_final = src;\n    zip_source_keep(src_final);\n\n    if (!needs_decrypt && st.encryption_method == ZIP_EM_TRAD_PKWARE && (de->changed & ZIP_DIRENT_LAST_MOD)) {\n        /* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */\n         de->changed &= ~ZIP_DIRENT_LAST_MOD;\n    }\n\n    if (needs_decrypt) {\n        zip_encryption_implementation impl;\n\n        if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n            zip_source_free(src_final);\n            return -1;\n        }\n        if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) {\n            /* error set by impl */\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        src_final = src_tmp;\n    }\n\n    if (needs_decompress) {\n        if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        src_final = src_tmp;\n    }\n\n    if (needs_crc) {\n        if ((src_tmp = zip_source_crc_create(src_final, 0, &za->error)) == NULL) {\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        src_final = src_tmp;\n    }\n\n    if (needs_compress) {\n        if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        src_final = src_tmp;\n    }\n\n\n    if (needs_encrypt) {\n        zip_encryption_implementation impl;\n        const char *password = NULL;\n\n        if (de->password) {\n            password = de->password;\n        }\n        else if (za->default_password) {\n            password = za->default_password;\n        }\n\n        if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {\n            de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;\n\n            /* PKWare encryption uses last_mod, make sure it gets the right value. */\n            if (de->changed & ZIP_DIRENT_LAST_MOD) {\n                if ((src_tmp = _zip_source_window_new(src_final, 0, -1, NULL, 0, NULL, &de->last_mod, NULL, 0, true, &za->error)) == NULL) {\n                    zip_source_free(src_final);\n                    return -1;\n                }\n                src_final = src_tmp;\n            }\n        }\n\n        if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) {\n            /* error set by impl */\n            zip_source_free(src_final);\n            return -1;\n        }\n\n        src_final = src_tmp;\n    }\n\n    if (!ZIP_WANT_TORRENTZIP(za)) {\n        if (zip_source_get_file_attributes(src_final, &attributes) != 0) {\n            zip_error_set_from_source(&za->error, src_final);\n            zip_source_free(src_final);\n            return -1;\n        }\n        _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);\n    }\n\n    /* as long as we don't support non-seekable output, clear data descriptor bit */\n    if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) {\n        zip_source_free(src_final);\n        return -1;\n    }\n\n    if ((offdata = zip_source_tell_write(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        zip_source_free(src_final);\n        return -1;\n    }\n\n    ret = copy_source(za, src_final, src, data_length);\n\n    if (zip_source_stat(src_final, &st) < 0) {\n        zip_error_set_from_source(&za->error, src_final);\n        ret = -1;\n    }\n\n    if (!ZIP_WANT_TORRENTZIP(za)) {\n        if (zip_source_get_file_attributes(src_final, &attributes) != 0) {\n            zip_error_set_from_source(&za->error, src_final);\n            ret = -1;\n        }\n    }\n\n    zip_source_free(src_final);\n\n    if (ret < 0) {\n        return -1;\n    }\n\n    if ((offend = zip_source_tell_write(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n\n    if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) {\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    dirent_changed = ZIP_CM_ACTUAL(de->comp_method) != st.comp_method || de->crc != st.crc || de->uncomp_size != st.size || de->comp_size != (zip_uint64_t)(offend - offdata);\n    de->comp_method = st.comp_method;\n    de->crc = st.crc;\n    de->uncomp_size = st.size;\n    de->comp_size = (zip_uint64_t)(offend - offdata);\n\n    if (!ZIP_WANT_TORRENTZIP(za)) {\n        dirent_changed |= _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);\n\n        if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0 && !have_dos_time) {\n            if (st.valid & ZIP_STAT_MTIME) {\n                if (st.mtime != mtime_before_copy) {\n                    if (_zip_u2d_time(st.mtime, &de->last_mod, &za->error) < 0) {\n                        return -1;\n                    }\n                    dirent_changed = true;\n                }\n            }\n        }\n    }\n\n    if (dirent_changed) {\n        if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {\n            zip_error_set_from_source(&za->error, za->src);\n            return -1;\n        }\n\n        if ((ret = _zip_dirent_write(za, de, flags)) < 0)\n            return -1;\n\n        if (is_zip64 != ret) {\n            /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */\n            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n\n        if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {\n            zip_error_set_from_source(&za->error, za->src);\n            return -1;\n        }\n    }\n\n    if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {\n        if (write_data_descriptor(za, de, is_zip64) < 0) {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n\nstatic int\ncopy_data(zip_t *za, zip_uint64_t len) {\n    DEFINE_BYTE_ARRAY(buf, BUFSIZE);\n    double total = (double)len;\n\n    if (!byte_array_init(buf, BUFSIZE)) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    while (len > 0) {\n        zip_uint64_t n = ZIP_MIN(len, BUFSIZE);\n\n        if (_zip_read(za->src, buf, n, &za->error) < 0) {\n            byte_array_fini(buf);\n            return -1;\n        }\n\n        if (_zip_write(za, buf, n) < 0) {\n            byte_array_fini(buf);\n            return -1;\n        }\n\n        len -= n;\n\n        if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {\n            zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);\n            return -1;\n        }\n    }\n\n    byte_array_fini(buf);\n    return 0;\n}\n\n\nstatic int\ncopy_source(zip_t *za, zip_source_t *src, zip_source_t *src_for_length, zip_int64_t data_length) {\n    DEFINE_BYTE_ARRAY(buf, BUFSIZE);\n    zip_int64_t n, current;\n    int ret;\n\n    if (zip_source_open(src) < 0) {\n        zip_error_set_from_source(&za->error, src);\n        return -1;\n    }\n\n    if (!byte_array_init(buf, BUFSIZE)) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    ret = 0;\n    current = 0;\n    while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {\n        if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {\n            ret = -1;\n            break;\n        }\n        if (n == BUFSIZE && za->progress && data_length > 0) {\n            zip_int64_t t;\n            t = zip_source_tell(src_for_length);\n            if (t >= 0) {\n                current = t;\n            } else {\n                current += n;\n            }\n            if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {\n                zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);\n                ret = -1;\n                break;\n            }\n        }\n    }\n\n    if (n < 0) {\n        zip_error_set_from_source(&za->error, src);\n        ret = -1;\n    }\n\n    byte_array_fini(buf);\n\n    zip_source_close(src);\n\n    return ret;\n}\n\nstatic int\nwrite_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {\n    if (zip_source_tell_write(za->src) < 0) {\n        return -1;\n    }\n\n    if (_zip_cdir_write(za, filelist, survivors) < 0) {\n        return -1;\n    }\n\n    if (zip_source_tell_write(za->src) < 0) {\n        return -1;\n    }\n\n    return 0;\n}\n\n\nint\n_zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {\n    int changed;\n    zip_uint64_t i, survivors;\n\n    changed = 0;\n    survivors = 0;\n\n    if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) {\n        changed = 1;\n    }\n\n    for (i = 0; i < za->nentry; i++) {\n        if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {\n            changed = 1;\n        }\n        if (!za->entry[i].deleted) {\n            survivors++;\n        }\n    }\n\n    if (survivorsp) {\n        *survivorsp = survivors;\n    }\n\n    return changed;\n}\n\nstatic int\nwrite_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {\n    zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);\n    int ret = 0;\n\n    if (buffer == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    _zip_buffer_put(buffer, DATADES_MAGIC, 4);\n    _zip_buffer_put_32(buffer, de->crc);\n    if (is_zip64) {\n        _zip_buffer_put_64(buffer, de->comp_size);\n        _zip_buffer_put_64(buffer, de->uncomp_size);\n    }\n    else {\n        _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);\n        _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);\n    }\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        ret = -1;\n    }\n    else {\n        ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));\n    }\n\n    _zip_buffer_free(buffer);\n\n    return ret;\n}\n\n\nstatic int torrentzip_compare_names(const void *a, const void *b) {\n    const char *aname = ((const zip_filelist_t *)a)->name;\n    const char *bname = ((const zip_filelist_t *)b)->name;\n\n    if (aname == NULL) {\n        return (bname != NULL) * -1;\n    }\n    else if (bname == NULL) {\n        return 1;\n    }\n\n    return strcasecmp(aname, bname);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto.h",
    "content": "/*\n  zip_crypto.h -- crypto definitions\n  Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_H\n#define HAD_ZIP_CRYPTO_H\n\n#define ZIP_CRYPTO_SHA1_LENGTH 20\n#define ZIP_CRYPTO_AES_BLOCK_LENGTH 16\n\n#if defined(HAVE_WINDOWS_CRYPTO)\n#include \"zip_crypto_win.h\"\n#elif defined(HAVE_COMMONCRYPTO)\n#include \"zip_crypto_commoncrypto.h\"\n#elif defined(HAVE_GNUTLS)\n#include \"zip_crypto_gnutls.h\"\n#elif defined(HAVE_OPENSSL)\n#include \"zip_crypto_openssl.h\"\n#elif defined(HAVE_MBEDTLS)\n#include \"zip_crypto_mbedtls.h\"\n#else\n#error \"no crypto backend found\"\n#endif\n\n#endif /*  HAD_ZIP_CRYPTO_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_commoncrypto.c",
    "content": "/*\n  zip_crypto_commoncrypto.c -- CommonCrypto wrapper.\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n#include <fcntl.h>\n#include <unistd.h>\n\nvoid\n_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {\n    if (aes == NULL) {\n        return;\n    }\n\n    CCCryptorRelease(aes);\n}\n\n\nbool\n_zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) {\n    size_t len;\n    CCCryptorUpdate(aes, in, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, ZIP_CRYPTO_AES_BLOCK_LENGTH, &len);\n    return true;\n}\n\n\n_zip_crypto_aes_t *\n_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {\n    _zip_crypto_aes_t *aes;\n    CCCryptorStatus ret;\n\n    ret = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode, key, key_size / 8, NULL, &aes);\n\n    switch (ret) {\n    case kCCSuccess:\n        return aes;\n\n    case kCCMemoryFailure:\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n\n    case kCCParamError:\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n\n    default:\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n}\n\n\nvoid\n_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {\n    if (hmac == NULL) {\n        return;\n    }\n\n    _zip_crypto_clear(hmac, sizeof(*hmac));\n    free(hmac);\n}\n\n\n_zip_crypto_hmac_t *\n_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {\n    _zip_crypto_hmac_t *hmac;\n\n    if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    CCHmacInit(hmac, kCCHmacAlgSHA1, secret, secret_length);\n\n    return hmac;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_commoncrypto.h",
    "content": "/*\n  zip_crypto_commoncrypto.h -- definitions for CommonCrypto wrapper.\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_COMMONCRYPTO_H\n#define HAD_ZIP_CRYPTO_COMMONCRYPTO_H\n\n#include <CommonCrypto/CommonCrypto.h>\n\n#define _zip_crypto_aes_t struct _CCCryptor\n#define _zip_crypto_hmac_t CCHmacContext\n\nvoid _zip_crypto_aes_free(_zip_crypto_aes_t *aes);\nbool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out);\n_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);\n\n#define _zip_crypto_hmac(hmac, data, length) (CCHmacUpdate((hmac), (data), (length)), true)\nvoid _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);\n_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);\n#define _zip_crypto_hmac_output(hmac, data) (CCHmacFinal((hmac), (data)), true)\n\n#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)(key), (key_length), (salt), (salt_length), kCCPRFHmacAlgSHA1, (iterations), (output), (output_length)) == kCCSuccess)\n\n#endif /* HAD_ZIP_CRYPTO_COMMONCRYPTO_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_gnutls.c",
    "content": "/*\n  zip_crypto_gnutls.c -- GnuTLS wrapper.\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n_zip_crypto_aes_t *\n_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {\n    _zip_crypto_aes_t *aes;\n\n    if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    aes->key_size = key_size;\n\n    switch (aes->key_size) {\n    case 128:\n        nettle_aes128_set_encrypt_key(&aes->ctx.ctx_128, key);\n        break;\n    case 192:\n        nettle_aes192_set_encrypt_key(&aes->ctx.ctx_192, key);\n        break;\n    case 256:\n        nettle_aes256_set_encrypt_key(&aes->ctx.ctx_256, key);\n        break;\n    default:\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        free(aes);\n        return NULL;\n    }\n\n    return aes;\n}\n\nbool\n_zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) {\n    switch (aes->key_size) {\n    case 128:\n        nettle_aes128_encrypt(&aes->ctx.ctx_128, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in);\n        break;\n    case 192:\n        nettle_aes192_encrypt(&aes->ctx.ctx_192, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in);\n        break;\n    case 256:\n        nettle_aes256_encrypt(&aes->ctx.ctx_256, ZIP_CRYPTO_AES_BLOCK_LENGTH, out, in);\n        break;\n    }\n\n    return true;\n}\n\nvoid\n_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {\n    if (aes == NULL) {\n        return;\n    }\n\n    _zip_crypto_clear(aes, sizeof(*aes));\n    free(aes);\n}\n\n\n_zip_crypto_hmac_t *\n_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {\n    _zip_crypto_hmac_t *hmac;\n\n    if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (gnutls_hmac_init(hmac, GNUTLS_MAC_SHA1, secret, secret_length) < 0) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        free(hmac);\n        return NULL;\n    }\n\n    return hmac;\n}\n\n\nvoid\n_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {\n    zip_uint8_t buf[ZIP_CRYPTO_SHA1_LENGTH];\n\n    if (hmac == NULL) {\n        return;\n    }\n\n    gnutls_hmac_deinit(*hmac, buf);\n    _zip_crypto_clear(hmac, sizeof(*hmac));\n    free(hmac);\n}\n\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    return gnutls_rnd(GNUTLS_RND_KEY, buffer, length) == 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_gnutls.h",
    "content": "/*\n  zip_crypto_gnutls.h -- definitions for GnuTLS wrapper.\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_GNUTLS_H\n#define HAD_ZIP_CRYPTO_GNUTLS_H\n\n#define HAVE_SECURE_RANDOM\n\n#include <nettle/aes.h>\n#include <nettle/pbkdf2.h>\n\n#include <gnutls/gnutls.h>\n\n#include <gnutls/crypto.h>\n\ntypedef struct {\n    union {\n        struct aes128_ctx ctx_128;\n        struct aes192_ctx ctx_192;\n        struct aes256_ctx ctx_256;\n    } ctx;\n    zip_uint16_t key_size;\n} _zip_crypto_aes_t;\n\n#define _zip_crypto_hmac_t gnutls_hmac_hd_t\n\nvoid _zip_crypto_aes_free(_zip_crypto_aes_t *aes);\nbool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out);\n_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);\n\n#define _zip_crypto_hmac(hmac, data, length) (gnutls_hmac(*(hmac), (data), (length)) == 0)\nvoid _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);\n_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);\n#define _zip_crypto_hmac_output(hmac, data) (gnutls_hmac_output(*(hmac), (data)), true)\n\n#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (pbkdf2_hmac_sha1((key_length), (key), (iterations), (salt_length), (salt), (output_length), (output)), true)\n\n#endif /*  HAD_ZIP_CRYPTO_GNUTLS_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_mbedtls.c",
    "content": "/*\n  zip_crypto_mbedtls.c -- mbed TLS wrapper\n  Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n#include <mbedtls/ctr_drbg.h>\n#include <mbedtls/entropy.h>\n#include <mbedtls/pkcs5.h>\n\n#include <limits.h>\n\n_zip_crypto_aes_t *\n_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {\n    _zip_crypto_aes_t *aes;\n\n    if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    mbedtls_aes_init(aes);\n    mbedtls_aes_setkey_enc(aes, (const unsigned char *)key, (unsigned int)key_size);\n\n    return aes;\n}\n\nvoid\n_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {\n    if (aes == NULL) {\n        return;\n    }\n\n    mbedtls_aes_free(aes);\n    free(aes);\n}\n\n\n_zip_crypto_hmac_t *\n_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {\n    _zip_crypto_hmac_t *hmac;\n\n    if (secret_length > INT_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    mbedtls_md_init(hmac);\n\n    if (mbedtls_md_setup(hmac, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        free(hmac);\n        return NULL;\n    }\n\n    if (mbedtls_md_hmac_starts(hmac, (const unsigned char *)secret, (size_t)secret_length) != 0) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        free(hmac);\n        return NULL;\n    }\n\n    return hmac;\n}\n\n\nvoid\n_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {\n    if (hmac == NULL) {\n        return;\n    }\n\n    mbedtls_md_free(hmac);\n    free(hmac);\n}\n\n\nbool\n_zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length) {\n    mbedtls_md_context_t sha1_ctx;\n    bool ok = true;\n\n#if MBEDTLS_VERSION_NUMBER < 0x03030000\n\n    mbedtls_md_init(&sha1_ctx);\n\n    if (mbedtls_md_setup(&sha1_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) {\n        ok = false;\n    }\n\n    if (ok && mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, (const unsigned char *)key, (size_t)key_length, (const unsigned char *)salt, (size_t)salt_length, (unsigned int)iterations, (uint32_t)output_length, (unsigned char *)output) != 0) {\n        ok = false;\n    }\n\n    mbedtls_md_free(&sha1_ctx);\n\n#else\n\n    ok = mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, (const unsigned char *)key, (size_t)key_length, (const unsigned char *)salt, (size_t)salt_length, (unsigned int)iterations, (uint32_t)output_length, (unsigned char *)output) == 0;\n\n#endif // !defined(MBEDTLS_DEPRECATED_REMOVED) || MBEDTLS_VERSION_NUMBER < 0x03030000\n\n    return ok;\n}\n\n\ntypedef struct {\n    mbedtls_entropy_context entropy;\n    mbedtls_ctr_drbg_context ctr_drbg;\n} zip_random_context_t;\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    static zip_random_context_t *ctx = NULL;\n    const unsigned char *pers = \"zip_crypto_mbedtls\";\n\n    if (!ctx) {\n        ctx = (zip_random_context_t *)malloc(sizeof(zip_random_context_t));\n        if (!ctx) {\n            return false;\n        }\n        mbedtls_entropy_init(&ctx->entropy);\n        mbedtls_ctr_drbg_init(&ctx->ctr_drbg);\n        if (mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy, pers, strlen(pers)) != 0) {\n            mbedtls_ctr_drbg_free(&ctx->ctr_drbg);\n            mbedtls_entropy_free(&ctx->entropy);\n            free(ctx);\n            ctx = NULL;\n            return false;\n        }\n    }\n\n    return mbedtls_ctr_drbg_random(&ctx->ctr_drbg, (unsigned char *)buffer, (size_t)length) == 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_mbedtls.h",
    "content": "/*\n  zip_crypto_mbedtls.h -- definitions for mbedtls wrapper\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_MBEDTLS_H\n#define HAD_ZIP_CRYPTO_MBEDTLS_H\n\n#define HAVE_SECURE_RANDOM\n\n#include <mbedtls/aes.h>\n#include <mbedtls/md.h>\n\n#define _zip_crypto_aes_t mbedtls_aes_context\n#define _zip_crypto_hmac_t mbedtls_md_context_t\n\n_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);\n#define _zip_crypto_aes_encrypt_block(aes, in, out) (mbedtls_aes_crypt_ecb((aes), MBEDTLS_AES_ENCRYPT, (in), (out)) == 0)\nvoid _zip_crypto_aes_free(_zip_crypto_aes_t *aes);\n\n_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);\n#define _zip_crypto_hmac(hmac, data, length) (mbedtls_md_hmac_update((hmac), (data), (length)) == 0)\n#define _zip_crypto_hmac_output(hmac, data) (mbedtls_md_hmac_finish((hmac), (data)) == 0)\nvoid _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);\n\nbool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length);\n\n#endif /*  HAD_ZIP_CRYPTO_MBEDTLS_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_openssl.c",
    "content": "/*\n  zip_crypto_openssl.c -- OpenSSL wrapper.\n  Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n#include <limits.h>\n#include <openssl/rand.h>\n\n#ifdef USE_OPENSSL_3_API\nstatic _zip_crypto_hmac_t* hmac_new() {\n    _zip_crypto_hmac_t *hmac = (_zip_crypto_hmac_t*)malloc(sizeof(*hmac));\n    if (hmac != NULL) {\n        hmac->mac = NULL;\n        hmac->ctx = NULL;\n    }\n    return hmac;\n}\nstatic void hmac_free(_zip_crypto_hmac_t* hmac) {\n    if (hmac != NULL) {\n        if (hmac->ctx != NULL) {\n            EVP_MAC_CTX_free(hmac->ctx);\n        }\n        if (hmac->mac != NULL) {\n            EVP_MAC_free(hmac->mac);\n        }\n        free(hmac);\n    }\n}\n#endif\n\n_zip_crypto_aes_t *\n_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {\n    _zip_crypto_aes_t *aes;\n    const EVP_CIPHER* cipher_type;\n\n    switch (key_size) {\n    case 128:\n        cipher_type = EVP_aes_128_ecb();\n        break;\n    case 192:\n        cipher_type = EVP_aes_192_ecb();\n        break;\n    case 256:\n        cipher_type = EVP_aes_256_ecb();\n        break;\n    default:\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n\n#ifdef USE_OPENSSL_1_0_API\n    if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n    memset(aes, 0, sizeof(*aes));\n#else\n    if ((aes = EVP_CIPHER_CTX_new()) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n#endif\n\n    if (EVP_EncryptInit_ex(aes, cipher_type, NULL, key, NULL) != 1) {\n#ifdef USE_OPENSSL_1_0_API\n        free(aes);\n#else\n        EVP_CIPHER_CTX_free(aes);\n#endif\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n\n    return aes;\n}\n\nvoid\n_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {\n    if (aes == NULL) {\n        return;\n    }\n\n#ifdef USE_OPENSSL_1_0_API\n    EVP_CIPHER_CTX_cleanup(aes);\n    _zip_crypto_clear(aes, sizeof(*aes));\n    free(aes);\n#else\n    EVP_CIPHER_CTX_free(aes);\n#endif\n}\n\n\nbool\n_zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) {\n    int len = 0;\n    if (EVP_EncryptUpdate(aes, out, &len, in, ZIP_CRYPTO_AES_BLOCK_LENGTH) != 1\n        || len != ZIP_CRYPTO_AES_BLOCK_LENGTH) {\n        return false;\n    }\n    return true;\n}\n\n\n_zip_crypto_hmac_t *\n_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {\n    _zip_crypto_hmac_t *hmac;\n\n    if (secret_length > INT_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n#ifdef USE_OPENSSL_3_API\n    if ((hmac = hmac_new()) == NULL\n        || (hmac->mac = EVP_MAC_fetch(NULL, \"HMAC\", \"provider=default\")) == NULL\n        || (hmac->ctx = EVP_MAC_CTX_new(hmac->mac)) == NULL) {\n        hmac_free(hmac);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    {\n        OSSL_PARAM params[2];\n        params[0] = OSSL_PARAM_construct_utf8_string(\"digest\", \"SHA1\", 0);\n        params[1] = OSSL_PARAM_construct_end();\n\n        if (!EVP_MAC_init(hmac->ctx, (const unsigned char *)secret, secret_length, params)) {\n            zip_error_set(error, ZIP_ER_INTERNAL, 0);\n            hmac_free(hmac);\n            return NULL;\n        }\n    }\n#else\n#ifdef USE_OPENSSL_1_0_API\n    if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n        HMAC_CTX_init(hmac);\n#else\n    if ((hmac = HMAC_CTX_new()) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n#endif\n\n    if (HMAC_Init_ex(hmac, secret, (int)secret_length, EVP_sha1(), NULL) != 1) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n#ifdef USE_OPENSSL_1_0_API\n        free(hmac);\n#else\n        HMAC_CTX_free(hmac);\n#endif\n        return NULL;\n    }\n#endif\n\n    return hmac;\n}\n\n\nvoid\n_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {\n    if (hmac == NULL) {\n        return;\n    }\n\n#if defined(USE_OPENSSL_3_API)\n    hmac_free(hmac);\n#elif defined(USE_OPENSSL_1_0_API)\n    HMAC_CTX_cleanup(hmac);\n    _zip_crypto_clear(hmac, sizeof(*hmac));\n    free(hmac);\n#else\n    HMAC_CTX_free(hmac);\n#endif\n}\n\n\nbool\n_zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data) {\n#ifdef USE_OPENSSL_3_API\n    size_t length = 0;\n    return EVP_MAC_final(hmac->ctx, data, &length, ZIP_CRYPTO_SHA1_LENGTH) == 1 && length == ZIP_CRYPTO_SHA1_LENGTH;\n#else\n    unsigned int length = 0;\n    return HMAC_Final(hmac, data, &length) == 1 && length == ZIP_CRYPTO_SHA1_LENGTH;\n#endif\n}\n\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    return RAND_bytes(buffer, length) == 1;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_openssl.h",
    "content": "/*\n  zip_crypto_openssl.h -- definitions for OpenSSL wrapper.\n  Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_OPENSSL_H\n#define HAD_ZIP_CRYPTO_OPENSSL_H\n\n#define HAVE_SECURE_RANDOM\n\n#include <openssl/evp.h>\n#include <openssl/hmac.h>\n\n#if OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)\n#define USE_OPENSSL_1_0_API\n#elif OPENSSL_VERSION_NUMBER < 0x3000000fL\n#define USE_OPENSSL_1_1_API\n#else\n#define USE_OPENSSL_3_API\n#endif\n\n#define _zip_crypto_aes_t EVP_CIPHER_CTX\n#ifdef USE_OPENSSL_3_API\nstruct _zip_crypto_hmac_t {\n    EVP_MAC *mac;\n    EVP_MAC_CTX *ctx;\n};\ntypedef struct _zip_crypto_hmac_t _zip_crypto_hmac_t;\n#define _zip_crypto_hmac(hmac, data, length) (EVP_MAC_update((hmac->ctx), (data), (length)) == 1)\n#else\n#define _zip_crypto_hmac_t HMAC_CTX\n#define _zip_crypto_hmac(hmac, data, length) (HMAC_Update((hmac), (data), (length)) == 1)\n#endif\n\nvoid _zip_crypto_aes_free(_zip_crypto_aes_t *aes);\nbool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out);\n_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);\n\nvoid _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);\n_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);\nbool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data);\n\n#define _zip_crypto_pbkdf2(key, key_length, salt, salt_length, iterations, output, output_length) (PKCS5_PBKDF2_HMAC_SHA1((const char *)(key), (key_length), (salt), (salt_length), (iterations), (output_length), (output)))\n\n#endif /*  HAD_ZIP_CRYPTO_OPENSSL_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_win.c",
    "content": "/*\n  zip_crypto_win.c -- Windows Crypto API wrapper.\n  Copyright (C) 2018-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n#include <stdlib.h>\n#include <limits.h>\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n#include <windows.h>\n\n#include <bcrypt.h>\n\n#pragma comment(lib, \"bcrypt.lib\")\n\n/*\n\nThis code is using the Cryptography API: Next Generation (CNG)\nhttps://docs.microsoft.com/en-us/windows/desktop/seccng/cng-portal\n\nThis API is supported on\n - Windows Vista or later (client OS)\n - Windows Server 2008 (server OS)\n - Windows Embedded Compact 2013 (don't know about Windows Embedded Compact 7)\n\nThe code was developed for Windows Embedded Compact 2013 (WEC2013),\nbut should be working for all of the above mentioned OSes.\n\nThere are 2 restrictions for WEC2013, Windows Vista and Windows Server 2008:\n\n1.) The function \"BCryptDeriveKeyPBKDF2\" is not available\n\nI found some code which is implementing this function using the deprecated Crypto API here:\nhttps://www.idrix.fr/Root/content/view/37/54/\n\nI took this code and converted it to the newer CNG API. The original code was more\nflexible, but this is not needed here so i refactored it a bit and just kept what is needed.\n\nThe define \"HAS_BCRYPTDERIVEKEYPBKDF2\" controls whether \"BCryptDeriveKeyPBKDF2\"\nof the CNG API is used or not. This define must not be set if you are compiling for WEC2013 or Windows Vista.\n\n\n2.) \"BCryptCreateHash\" can't manage the memory needed for the hash object internally\n\nOn Windows 7 or later it is possible to pass NULL for the hash object buffer.\nThis is not supported on WEC2013, so we have to handle the memory allocation/deallocation ourselves.\nThere is no #ifdef to control that, because this is working for all supported OSes.\n\n*/\n\n#if !defined(WINCE) && !defined(__MINGW32__)\n#define HAS_BCRYPTDERIVEKEYPBKDF2\n#endif\n\n#ifdef HAS_BCRYPTDERIVEKEYPBKDF2\n\nbool\n_zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) {\n    BCRYPT_ALG_HANDLE hAlgorithm = NULL;\n    bool result;\n\n    if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG))) {\n        return false;\n    }\n\n    result = BCRYPT_SUCCESS(BCryptDeriveKeyPBKDF2(hAlgorithm, (PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length, 0));\n\n    BCryptCloseAlgorithmProvider(hAlgorithm, 0);\n\n    return result;\n}\n\n#else\n\n#include <math.h>\n\n#define DIGEST_SIZE 20\n#define BLOCK_SIZE 64\n\ntypedef struct {\n    BCRYPT_ALG_HANDLE hAlgorithm;\n    BCRYPT_HASH_HANDLE hInnerHash;\n    BCRYPT_HASH_HANDLE hOuterHash;\n    ULONG cbHashObject;\n    PUCHAR pbInnerHash;\n    PUCHAR pbOuterHash;\n} PRF_CTX;\n\nstatic void\nhmacFree(PRF_CTX *pContext) {\n    if (pContext->hOuterHash)\n        BCryptDestroyHash(pContext->hOuterHash);\n    if (pContext->hInnerHash)\n        BCryptDestroyHash(pContext->hInnerHash);\n    free(pContext->pbOuterHash);\n    free(pContext->pbInnerHash);\n    if (pContext->hAlgorithm)\n        BCryptCloseAlgorithmProvider(pContext->hAlgorithm, 0);\n}\n\nstatic BOOL\nhmacPrecomputeDigest(BCRYPT_HASH_HANDLE hHash, PUCHAR pbPassword, DWORD cbPassword, BYTE mask) {\n    BYTE buffer[BLOCK_SIZE];\n    DWORD i;\n\n    if (cbPassword > BLOCK_SIZE) {\n        return FALSE;\n    }\n\n    memset(buffer, mask, sizeof(buffer));\n\n    for (i = 0; i < cbPassword; ++i) {\n        buffer[i] = (char)(pbPassword[i] ^ mask);\n    }\n\n    return BCRYPT_SUCCESS(BCryptHashData(hHash, buffer, sizeof(buffer), 0));\n}\n\nstatic BOOL\nhmacInit(PRF_CTX *pContext, PUCHAR pbPassword, DWORD cbPassword) {\n    BOOL bStatus = FALSE;\n    ULONG cbResult;\n    BYTE key[DIGEST_SIZE];\n\n    if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&pContext->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, 0)) || !BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&pContext->cbHashObject, sizeof(pContext->cbHashObject), &cbResult, 0)) || ((pContext->pbInnerHash = malloc(pContext->cbHashObject)) == NULL) || ((pContext->pbOuterHash = malloc(pContext->cbHashObject)) == NULL) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hInnerHash, pContext->pbInnerHash, pContext->cbHashObject, NULL, 0, 0)) || !BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &pContext->hOuterHash, pContext->pbOuterHash, pContext->cbHashObject, NULL, 0, 0))) {\n        goto hmacInit_end;\n    }\n\n    if (cbPassword > BLOCK_SIZE) {\n        BCRYPT_HASH_HANDLE hHash = NULL;\n        PUCHAR pbHashObject = malloc(pContext->cbHashObject);\n        if (pbHashObject == NULL) {\n            goto hmacInit_end;\n        }\n\n        bStatus = BCRYPT_SUCCESS(BCryptCreateHash(pContext->hAlgorithm, &hHash, pbHashObject, pContext->cbHashObject, NULL, 0, 0)) && BCRYPT_SUCCESS(BCryptHashData(hHash, pbPassword, cbPassword, 0)) && BCRYPT_SUCCESS(BCryptGetProperty(hHash, BCRYPT_HASH_LENGTH, (PUCHAR)&cbPassword, sizeof(cbPassword), &cbResult, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, key, cbPassword, 0));\n\n        if (hHash)\n            BCryptDestroyHash(hHash);\n        free(pbHashObject);\n\n        if (!bStatus) {\n            goto hmacInit_end;\n        }\n\n        pbPassword = key;\n    }\n\n    bStatus = hmacPrecomputeDigest(pContext->hInnerHash, pbPassword, cbPassword, 0x36) && hmacPrecomputeDigest(pContext->hOuterHash, pbPassword, cbPassword, 0x5C);\n\nhmacInit_end:\n\n    if (bStatus == FALSE)\n        hmacFree(pContext);\n\n    return bStatus;\n}\n\nstatic BOOL\nhmacCalculateInternal(BCRYPT_HASH_HANDLE hHashTemplate, PUCHAR pbData, DWORD cbData, PUCHAR pbOutput, DWORD cbOutput, DWORD cbHashObject) {\n    BOOL success = FALSE;\n    BCRYPT_HASH_HANDLE hHash = NULL;\n    PUCHAR pbHashObject = malloc(cbHashObject);\n\n    if (pbHashObject == NULL) {\n        return FALSE;\n    }\n\n    if (BCRYPT_SUCCESS(BCryptDuplicateHash(hHashTemplate, &hHash, pbHashObject, cbHashObject, 0))) {\n        success = BCRYPT_SUCCESS(BCryptHashData(hHash, pbData, cbData, 0)) && BCRYPT_SUCCESS(BCryptFinishHash(hHash, pbOutput, cbOutput, 0));\n\n        BCryptDestroyHash(hHash);\n    }\n\n    free(pbHashObject);\n\n    return success;\n}\n\nstatic BOOL\nhmacCalculate(PRF_CTX *pContext, PUCHAR pbData, DWORD cbData, PUCHAR pbDigest) {\n    DWORD cbResult;\n    DWORD cbHashObject;\n\n    return BCRYPT_SUCCESS(BCryptGetProperty(pContext->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&cbHashObject, sizeof(cbHashObject), &cbResult, 0)) && hmacCalculateInternal(pContext->hInnerHash, pbData, cbData, pbDigest, DIGEST_SIZE, cbHashObject) && hmacCalculateInternal(pContext->hOuterHash, pbDigest, DIGEST_SIZE, pbDigest, DIGEST_SIZE, cbHashObject);\n}\n\nstatic void\nmyxor(LPBYTE ptr1, LPBYTE ptr2, DWORD dwLen) {\n    while (dwLen--)\n        *ptr1++ ^= *ptr2++;\n}\n\nBOOL\npbkdf2(PUCHAR pbPassword, ULONG cbPassword, PUCHAR pbSalt, ULONG cbSalt, DWORD cIterations, PUCHAR pbDerivedKey, ULONG cbDerivedKey) {\n    BOOL bStatus = FALSE;\n    DWORD l, r, dwULen, i, j;\n    BYTE Ti[DIGEST_SIZE];\n    BYTE V[DIGEST_SIZE];\n    LPBYTE U = malloc(max((cbSalt + 4), DIGEST_SIZE));\n    PRF_CTX prfCtx = {0};\n\n    if (U == NULL) {\n        return FALSE;\n    }\n\n    if (pbPassword == NULL || cbPassword == 0 || pbSalt == NULL || cbSalt == 0 || cIterations == 0 || pbDerivedKey == NULL || cbDerivedKey == 0) {\n        free(U);\n        return FALSE;\n    }\n\n    if (!hmacInit(&prfCtx, pbPassword, cbPassword)) {\n        goto PBKDF2_end;\n    }\n\n    l = (DWORD)ceil((double)cbDerivedKey / (double)DIGEST_SIZE);\n    r = cbDerivedKey - (l - 1) * DIGEST_SIZE;\n\n    for (i = 1; i <= l; i++) {\n        ZeroMemory(Ti, DIGEST_SIZE);\n        for (j = 0; j < cIterations; j++) {\n            if (j == 0) {\n                /* construct first input for PRF */\n                (void)memcpy_s(U, cbSalt, pbSalt, cbSalt);\n                U[cbSalt] = (BYTE)((i & 0xFF000000) >> 24);\n                U[cbSalt + 1] = (BYTE)((i & 0x00FF0000) >> 16);\n                U[cbSalt + 2] = (BYTE)((i & 0x0000FF00) >> 8);\n                U[cbSalt + 3] = (BYTE)((i & 0x000000FF));\n                dwULen = cbSalt + 4;\n            }\n            else {\n                (void)memcpy_s(U, DIGEST_SIZE, V, DIGEST_SIZE);\n                dwULen = DIGEST_SIZE;\n            }\n\n            if (!hmacCalculate(&prfCtx, U, dwULen, V)) {\n                goto PBKDF2_end;\n            }\n\n            myxor(Ti, V, DIGEST_SIZE);\n        }\n\n        if (i != l) {\n            (void)memcpy_s(&pbDerivedKey[(i - 1) * DIGEST_SIZE], cbDerivedKey - (i - 1) * DIGEST_SIZE, Ti, DIGEST_SIZE);\n        }\n        else {\n            /* Take only the first r bytes */\n            (void)memcpy_s(&pbDerivedKey[(i - 1) * DIGEST_SIZE], cbDerivedKey - (i - 1) * DIGEST_SIZE, Ti, r);\n        }\n    }\n\n    bStatus = TRUE;\n\nPBKDF2_end:\n\n    hmacFree(&prfCtx);\n    free(U);\n    return bStatus;\n}\n\nbool\n_zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length) {\n    return (key_length <= ZIP_UINT32_MAX) && pbkdf2((PUCHAR)key, (ULONG)key_length, (PUCHAR)salt, salt_length, iterations, output, output_length);\n}\n\n#endif\n\n\nstruct _zip_crypto_aes_s {\n    BCRYPT_ALG_HANDLE hAlgorithm;\n    BCRYPT_KEY_HANDLE hKey;\n    ULONG cbKeyObject;\n    PUCHAR pbKeyObject;\n};\n\n_zip_crypto_aes_t *\n_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {\n    _zip_crypto_aes_t *aes = (_zip_crypto_aes_t *)calloc(1, sizeof(*aes));\n\n    ULONG cbResult;\n    ULONG key_length = key_size / 8;\n\n    if (aes == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&aes->hAlgorithm, BCRYPT_AES_ALGORITHM, NULL, 0))) {\n        _zip_crypto_aes_free(aes);\n        return NULL;\n    }\n\n    if (!BCRYPT_SUCCESS(BCryptSetProperty(aes->hAlgorithm, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0))) {\n        _zip_crypto_aes_free(aes);\n        return NULL;\n    }\n\n    if (!BCRYPT_SUCCESS(BCryptGetProperty(aes->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&aes->cbKeyObject, sizeof(aes->cbKeyObject), &cbResult, 0))) {\n        _zip_crypto_aes_free(aes);\n        return NULL;\n    }\n\n    aes->pbKeyObject = malloc(aes->cbKeyObject);\n    if (aes->pbKeyObject == NULL) {\n        _zip_crypto_aes_free(aes);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (!BCRYPT_SUCCESS(BCryptGenerateSymmetricKey(aes->hAlgorithm, &aes->hKey, aes->pbKeyObject, aes->cbKeyObject, (PUCHAR)key, key_length, 0))) {\n        _zip_crypto_aes_free(aes);\n        return NULL;\n    }\n\n    return aes;\n}\n\nvoid\n_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {\n    if (aes == NULL) {\n        return;\n    }\n\n    if (aes->hKey != NULL) {\n        BCryptDestroyKey(aes->hKey);\n    }\n\n    if (aes->pbKeyObject != NULL) {\n        free(aes->pbKeyObject);\n    }\n\n    if (aes->hAlgorithm != NULL) {\n        BCryptCloseAlgorithmProvider(aes->hAlgorithm, 0);\n    }\n\n    free(aes);\n}\n\nbool\n_zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out) {\n    ULONG cbResult;\n    NTSTATUS status = BCryptEncrypt(aes->hKey, (PUCHAR)in, ZIP_CRYPTO_AES_BLOCK_LENGTH, NULL, NULL, 0, (PUCHAR)out, ZIP_CRYPTO_AES_BLOCK_LENGTH, &cbResult, 0);\n    return BCRYPT_SUCCESS(status);\n}\n\nstruct _zip_crypto_hmac_s {\n    BCRYPT_ALG_HANDLE hAlgorithm;\n    BCRYPT_HASH_HANDLE hHash;\n    DWORD cbHashObject;\n    PUCHAR pbHashObject;\n    DWORD cbHash;\n    PUCHAR pbHash;\n};\n\n/* https://code.msdn.microsoft.com/windowsdesktop/Hmac-Computation-Sample-11fe8ec1/sourcecode?fileId=42820&pathId=283874677 */\n\n_zip_crypto_hmac_t *\n_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {\n    NTSTATUS status;\n    ULONG cbResult;\n    _zip_crypto_hmac_t *hmac;\n\n    if (secret_length > INT_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    hmac = (_zip_crypto_hmac_t *)calloc(1, sizeof(*hmac));\n\n    if (hmac == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    status = BCryptOpenAlgorithmProvider(&hmac->hAlgorithm, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);\n    if (!BCRYPT_SUCCESS(status)) {\n        _zip_crypto_hmac_free(hmac);\n        return NULL;\n    }\n\n    status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hmac->cbHashObject, sizeof(hmac->cbHashObject), &cbResult, 0);\n    if (!BCRYPT_SUCCESS(status)) {\n        _zip_crypto_hmac_free(hmac);\n        return NULL;\n    }\n\n    hmac->pbHashObject = malloc(hmac->cbHashObject);\n    if (hmac->pbHashObject == NULL) {\n        _zip_crypto_hmac_free(hmac);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    status = BCryptGetProperty(hmac->hAlgorithm, BCRYPT_HASH_LENGTH, (PUCHAR)&hmac->cbHash, sizeof(hmac->cbHash), &cbResult, 0);\n    if (!BCRYPT_SUCCESS(status)) {\n        _zip_crypto_hmac_free(hmac);\n        return NULL;\n    }\n\n    hmac->pbHash = malloc(hmac->cbHash);\n    if (hmac->pbHash == NULL) {\n        _zip_crypto_hmac_free(hmac);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    status = BCryptCreateHash(hmac->hAlgorithm, &hmac->hHash, hmac->pbHashObject, hmac->cbHashObject, (PUCHAR)secret, (ULONG)secret_length, 0);\n    if (!BCRYPT_SUCCESS(status)) {\n        _zip_crypto_hmac_free(hmac);\n        return NULL;\n    }\n\n    return hmac;\n}\n\nvoid\n_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {\n    if (hmac == NULL) {\n        return;\n    }\n\n    if (hmac->hHash != NULL) {\n        BCryptDestroyHash(hmac->hHash);\n    }\n\n    if (hmac->pbHash != NULL) {\n        free(hmac->pbHash);\n    }\n\n    if (hmac->pbHashObject != NULL) {\n        free(hmac->pbHashObject);\n    }\n\n    if (hmac->hAlgorithm) {\n        BCryptCloseAlgorithmProvider(hmac->hAlgorithm, 0);\n    }\n\n    free(hmac);\n}\n\nbool\n_zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length) {\n    if (hmac == NULL || length > ULONG_MAX) {\n        return false;\n    }\n\n    return BCRYPT_SUCCESS(BCryptHashData(hmac->hHash, data, (ULONG)length, 0));\n}\n\nbool\n_zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data) {\n    if (hmac == NULL) {\n        return false;\n    }\n\n    return BCRYPT_SUCCESS(BCryptFinishHash(hmac->hHash, data, hmac->cbHash, 0));\n}\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    return BCRYPT_SUCCESS(BCryptGenRandom(NULL, buffer, length, BCRYPT_USE_SYSTEM_PREFERRED_RNG));\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_crypto_win.h",
    "content": "/*\n  zip_crypto_win.h -- Windows Crypto API wrapper.\n  Copyright (C) 2018-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef HAD_ZIP_CRYPTO_WIN_H\n#define HAD_ZIP_CRYPTO_WIN_H\n\n#define HAVE_SECURE_RANDOM\n\ntypedef struct _zip_crypto_aes_s _zip_crypto_aes_t;\ntypedef struct _zip_crypto_hmac_s _zip_crypto_hmac_t;\n\nvoid _zip_crypto_aes_free(_zip_crypto_aes_t *aes);\n_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);\nbool _zip_crypto_aes_encrypt_block(_zip_crypto_aes_t *aes, const zip_uint8_t *in, zip_uint8_t *out);\n\nbool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, zip_uint16_t iterations, zip_uint8_t *output, zip_uint16_t output_length);\n\n_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);\nvoid _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);\nbool _zip_crypto_hmac(_zip_crypto_hmac_t *hmac, zip_uint8_t *data, zip_uint64_t length);\nbool _zip_crypto_hmac_output(_zip_crypto_hmac_t *hmac, zip_uint8_t *data);\n\n#endif /*  HAD_ZIP_CRYPTO_WIN_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_delete.c",
    "content": "/*\n  zip_delete.c -- delete file from zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_delete(zip_t *za, zip_uint64_t idx) {\n    const char *name;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if ((name = _zip_get_name(za, idx, 0, &za->error)) == NULL) {\n        return -1;\n    }\n\n    if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) {\n        return -1;\n    }\n\n    /* allow duplicate file names, because the file will\n     * be removed directly afterwards */\n    if (_zip_unchange(za, idx, 1) != 0)\n        return -1;\n\n    za->entry[idx].deleted = 1;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_dir_add.c",
    "content": "/*\n  zip_dir_add.c -- add directory\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\n/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */\n\nZIP_EXTERN zip_int64_t\nzip_dir_add(zip_t *za, const char *name, zip_flags_t flags) {\n    size_t len;\n    zip_int64_t idx;\n    char *s;\n    zip_source_t *source;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if (name == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    s = NULL;\n    len = strlen(name);\n\n    if (name[len - 1] != '/') {\n        if (len > SIZE_MAX - 2 || (s = (char *)malloc(len + 2)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n        (void)strncpy_s(s, len + 2, name, len);\n        s[len] = '/';\n        s[len + 1] = '\\0';\n    }\n\n    if ((source = zip_source_buffer(za, NULL, 0, 0)) == NULL) {\n        free(s);\n        return -1;\n    }\n\n    idx = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags);\n\n    free(s);\n\n    if (idx < 0)\n        zip_source_free(source);\n    else {\n        if (zip_file_set_external_attributes(za, (zip_uint64_t)idx, 0, ZIP_OPSYS_DEFAULT, ZIP_EXT_ATTRIB_DEFAULT_DIR) < 0) {\n            zip_delete(za, (zip_uint64_t)idx);\n            return -1;\n        }\n    }\n\n    return idx;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_dirent.c",
    "content": "/*\n  zip_dirent.c -- read directory entry (local or central), clean dirent\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n#include <time.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\nstatic zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str, bool check_consistency);\nstatic zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *);\nstatic bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error);\n\n\nvoid\n_zip_cdir_free(zip_cdir_t *cd) {\n    zip_uint64_t i;\n\n    if (cd == NULL) {\n        return;\n    }\n\n    for (i = 0; i < cd->nentry; i++)\n        _zip_entry_finalize(cd->entry + i);\n    free(cd->entry);\n    _zip_string_free(cd->comment);\n    free(cd);\n}\n\n\nzip_cdir_t *\n_zip_cdir_new(zip_error_t *error) {\n    zip_cdir_t *cd;\n\n    if ((cd = (zip_cdir_t *)malloc(sizeof(*cd))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    cd->entry = NULL;\n    cd->nentry = cd->nentry_alloc = 0;\n    cd->size = cd->offset = 0;\n    cd->comment = NULL;\n    cd->is_zip64 = false;\n\n    return cd;\n}\n\n\nbool\n_zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) {\n    zip_uint64_t i;\n\n    if (additional_entries == 0) {\n        return true;\n    }\n\n    if (!ZIP_REALLOC(cd->entry, cd->nentry_alloc, additional_entries, error)) {\n        return false;\n    }\n\n    for (i = cd->nentry; i < cd->nentry_alloc; i++) {\n        _zip_entry_init(cd->entry + i);\n    }\n\n    cd->nentry = cd->nentry_alloc;\n\n    return true;\n}\n\n\nzip_int64_t\n_zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {\n    zip_uint64_t offset, size;\n    zip_string_t *comment;\n    zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN];\n    zip_buffer_t *buffer;\n    zip_int64_t off;\n    zip_uint64_t i;\n    zip_uint32_t cdir_crc;\n\n    if ((off = zip_source_tell_write(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n    offset = (zip_uint64_t)off;\n\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        cdir_crc = (zip_uint32_t)crc32(0, NULL, 0);\n        za->write_crc = &cdir_crc;\n    }\n\n    for (i = 0; i < survivors; i++) {\n        zip_entry_t *entry = za->entry + filelist[i].idx;\n\n        if (_zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL) < 0) {\n            za->write_crc = NULL;\n            return -1;\n        }\n    }\n\n    za->write_crc = NULL;\n\n    if ((off = zip_source_tell_write(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n    size = (zip_uint64_t)off - offset;\n\n    if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    if (survivors > ZIP_UINT16_MAX || offset > ZIP_UINT32_MAX || size > ZIP_UINT32_MAX) {\n        _zip_buffer_put(buffer, EOCD64_MAGIC, 4);\n        _zip_buffer_put_64(buffer, EOCD64LEN - 12);\n        _zip_buffer_put_16(buffer, 45);\n        _zip_buffer_put_16(buffer, 45);\n        _zip_buffer_put_32(buffer, 0);\n        _zip_buffer_put_32(buffer, 0);\n        _zip_buffer_put_64(buffer, survivors);\n        _zip_buffer_put_64(buffer, survivors);\n        _zip_buffer_put_64(buffer, size);\n        _zip_buffer_put_64(buffer, offset);\n        _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4);\n        _zip_buffer_put_32(buffer, 0);\n        _zip_buffer_put_64(buffer, offset + size);\n        _zip_buffer_put_32(buffer, 1);\n    }\n\n    _zip_buffer_put(buffer, EOCD_MAGIC, 4);\n    _zip_buffer_put_32(buffer, 0);\n    _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));\n    _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));\n    _zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size);\n    _zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset);\n\n    comment = za->comment_changed ? za->comment_changes : za->comment_orig;\n\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        _zip_buffer_put_16(buffer, TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH);\n    }\n    else {\n        _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0));\n    }\n\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        _zip_buffer_free(buffer);\n        return -1;\n    }\n\n    if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) {\n        _zip_buffer_free(buffer);\n        return -1;\n    }\n\n    _zip_buffer_free(buffer);\n\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        char torrentzip_comment[TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH + 1];\n        snprintf(torrentzip_comment, sizeof(torrentzip_comment), TORRENTZIP_SIGNATURE \"%08X\", cdir_crc);\n\n        if (_zip_write(za, torrentzip_comment, strlen(torrentzip_comment)) < 0) {\n            return -1;\n        }\n    }\n    else if (comment != NULL) {\n        if (_zip_write(za, comment->raw, comment->length) < 0) {\n            return -1;\n        }\n    }\n\n    return (zip_int64_t)size;\n}\n\n\nzip_dirent_t *\n_zip_dirent_clone(const zip_dirent_t *sde) {\n    zip_dirent_t *tde;\n\n    if ((tde = (zip_dirent_t *)malloc(sizeof(*tde))) == NULL)\n        return NULL;\n\n    if (sde)\n        (void)memcpy_s(tde, sizeof(*tde), sde, sizeof(*sde));\n    else\n        _zip_dirent_init(tde);\n\n    tde->changed = 0;\n    tde->cloned = 1;\n\n    return tde;\n}\n\n\nvoid\n_zip_dirent_finalize(zip_dirent_t *zde) {\n    if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) {\n        _zip_string_free(zde->filename);\n        zde->filename = NULL;\n    }\n    if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) {\n        _zip_ef_free(zde->extra_fields);\n        zde->extra_fields = NULL;\n    }\n    if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) {\n        _zip_string_free(zde->comment);\n        zde->comment = NULL;\n    }\n    if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) {\n        if (zde->password) {\n            _zip_crypto_clear(zde->password, strlen(zde->password));\n        }\n        free(zde->password);\n        zde->password = NULL;\n    }\n}\n\n\nvoid\n_zip_dirent_free(zip_dirent_t *zde) {\n    if (zde == NULL)\n        return;\n\n    _zip_dirent_finalize(zde);\n    free(zde);\n}\n\n\nbool\n_zip_dirent_merge(zip_dirent_t *de, zip_dirent_t *de_orig, bool replacing_data, zip_error_t *error) {\n    if (!de->cloned) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return false;\n    }\n\n    if (!(de->changed & ZIP_DIRENT_ATTRIBUTES)) {\n        de->ext_attrib = de_orig->ext_attrib;\n        de->int_attrib = de_orig->int_attrib;\n    }\n    if (!(de->changed & ZIP_DIRENT_COMMENT)) {\n        de->comment = de_orig->comment;\n    }\n    if (!(de->changed & ZIP_DIRENT_COMP_METHOD)) {\n        if (replacing_data) {\n            de->comp_method = ZIP_CM_DEFAULT;\n            de->compression_level = 0;\n        }\n        else {\n            de->comp_method = de_orig->comp_method;\n            de->compression_level = de_orig->compression_level;\n        }\n    }\n    if (!(de->changed & ZIP_DIRENT_ENCRYPTION_METHOD)) {\n        if (replacing_data) {\n            de->encryption_method = ZIP_EM_NONE;\n        }\n        else {\n            de->encryption_method = de_orig->encryption_method;\n        }\n    }\n    if (!(de->changed & ZIP_DIRENT_EXTRA_FIELD)) {\n        de->extra_fields = de_orig->extra_fields;\n    }\n    if (!(de->changed & ZIP_DIRENT_FILENAME)) {\n        de->filename = de_orig->filename;\n    }\n    if (!(de->changed & ZIP_DIRENT_LAST_MOD)) {\n        de->last_mod = de_orig->last_mod;\n    }\n    if (!(de->changed & ZIP_DIRENT_PASSWORD)) {\n        de->password = de_orig->password;\n    }\n\n    return true;\n}\n\n\nvoid\n_zip_dirent_init(zip_dirent_t *de) {\n    de->changed = 0;\n    de->local_extra_fields_read = 0;\n    de->cloned = 0;\n\n    de->crc_valid = true;\n    de->last_mod_mtime_valid = false;\n    de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8);\n    de->version_needed = 10; /* 1.0 */\n    de->bitflags = 0;\n    de->comp_method = ZIP_CM_DEFAULT;\n    de->last_mod.date = 0;\n    de->last_mod.time = 0;\n    de->crc = 0;\n    de->comp_size = 0;\n    de->uncomp_size = 0;\n    de->filename = NULL;\n    de->extra_fields = NULL;\n    de->comment = NULL;\n    de->disk_number = 0;\n    de->int_attrib = 0;\n    de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;\n    de->offset = 0;\n    de->compression_level = 0;\n    de->encryption_method = ZIP_EM_NONE;\n    de->password = NULL;\n}\n\n\nbool\n_zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) {\n    if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX))\n        return true;\n\n    return false;\n}\n\n\nzip_dirent_t *\n_zip_dirent_new(void) {\n    zip_dirent_t *de;\n\n    if ((de = (zip_dirent_t *)malloc(sizeof(*de))) == NULL)\n        return NULL;\n\n    _zip_dirent_init(de);\n    return de;\n}\n\n\n/*\n   Fills the zip directory entry zde.\n\n   If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed.\n\n   If local is true, it reads a local header instead of a central directory entry.\n\n   Returns size of dirent read if successful. On error, error is filled in and -1 is returned.\n*/\n\nzip_int64_t\n_zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_uint64_t central_compressed_size, bool check_consistency, zip_error_t *error) {\n    zip_uint8_t buf[CDENTRYSIZE];\n    zip_uint32_t size, variable_size;\n    zip_uint16_t filename_len, comment_len, ef_len;\n    zip_string_t *utf8_string;\n    bool is_zip64 = false;\n\n    bool from_buffer = (buffer != NULL);\n\n    size = local ? LENTRYSIZE : CDENTRYSIZE;\n\n    if (buffer) {\n        if (_zip_buffer_left(buffer) < size) {\n            zip_error_set(error, ZIP_ER_NOZIP, 0);\n            return -1;\n        }\n    }\n    else {\n        if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) {\n            return -1;\n        }\n    }\n\n    if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {\n        zip_error_set(error, ZIP_ER_NOZIP, 0);\n        if (!from_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return -1;\n    }\n\n    /* convert buffercontents to zip_dirent */\n\n    _zip_dirent_init(zde);\n    if (!local)\n        zde->version_madeby = _zip_buffer_get_16(buffer);\n    else\n        zde->version_madeby = 0;\n    zde->version_needed = _zip_buffer_get_16(buffer);\n    zde->bitflags = _zip_buffer_get_16(buffer);\n    zde->comp_method = _zip_buffer_get_16(buffer);\n\n    /* convert to time_t */\n    zde->last_mod.time = _zip_buffer_get_16(buffer);\n    zde->last_mod.date = _zip_buffer_get_16(buffer);\n\n    zde->crc = _zip_buffer_get_32(buffer);\n    zde->comp_size = _zip_buffer_get_32(buffer);\n    zde->uncomp_size = _zip_buffer_get_32(buffer);\n\n    filename_len = _zip_buffer_get_16(buffer);\n    ef_len = _zip_buffer_get_16(buffer);\n\n    if (local) {\n        comment_len = 0;\n        zde->disk_number = 0;\n        zde->int_attrib = 0;\n        zde->ext_attrib = 0;\n        zde->offset = 0;\n    }\n    else {\n        comment_len = _zip_buffer_get_16(buffer);\n        zde->disk_number = _zip_buffer_get_16(buffer);\n        zde->int_attrib = _zip_buffer_get_16(buffer);\n        zde->ext_attrib = _zip_buffer_get_32(buffer);\n        zde->offset = _zip_buffer_get_32(buffer);\n    }\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        if (!from_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return -1;\n    }\n\n    if (zde->bitflags & ZIP_GPBF_ENCRYPTED) {\n        if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) {\n            /* TODO */\n            zde->encryption_method = ZIP_EM_UNKNOWN;\n        }\n        else {\n            zde->encryption_method = ZIP_EM_TRAD_PKWARE;\n        }\n    }\n    else {\n        zde->encryption_method = ZIP_EM_NONE;\n    }\n\n    zde->filename = NULL;\n    zde->extra_fields = NULL;\n    zde->comment = NULL;\n\n    variable_size = (zip_uint32_t)filename_len + (zip_uint32_t)ef_len + (zip_uint32_t)comment_len;\n\n    if (from_buffer) {\n        if (_zip_buffer_left(buffer) < variable_size) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW);\n            return -1;\n        }\n    }\n    else {\n        _zip_buffer_free(buffer);\n\n        if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) {\n            return -1;\n        }\n    }\n\n    if (filename_len) {\n        zde->filename = _zip_read_string(buffer, src, filename_len, 1, error);\n        if (zde->filename == NULL) {\n            if (zip_error_code_zip(error) == ZIP_ER_EOF) {\n                zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW);\n            }\n            if (!from_buffer) {\n                _zip_buffer_free(buffer);\n            }\n            return -1;\n        }\n\n        if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {\n            if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {\n                zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME);\n                if (!from_buffer) {\n                    _zip_buffer_free(buffer);\n                }\n                return -1;\n            }\n        }\n    }\n\n    if (ef_len) {\n        zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error);\n\n        if (ef == NULL) {\n            if (!from_buffer) {\n                _zip_buffer_free(buffer);\n            }\n            return -1;\n        }\n        if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) {\n            free(ef);\n            if (!from_buffer) {\n                _zip_buffer_free(buffer);\n            }\n            return -1;\n        }\n        free(ef);\n        if (local)\n            zde->local_extra_fields_read = 1;\n    }\n\n    if (comment_len) {\n        zde->comment = _zip_read_string(buffer, src, comment_len, 0, error);\n        if (zde->comment == NULL) {\n            if (!from_buffer) {\n                _zip_buffer_free(buffer);\n            }\n            return -1;\n        }\n        if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {\n            if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {\n                zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT);\n                if (!from_buffer) {\n                    _zip_buffer_free(buffer);\n                }\n                return -1;\n            }\n        }\n    }\n\n    if ((utf8_string = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename, check_consistency)) == NULL && zde->filename != NULL) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_UTF8_FILENAME_MISMATCH);\n        if (!from_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return -1;\n    }\n    zde->filename = utf8_string;\n    if (!local) {\n        if ((utf8_string = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment, check_consistency)) == NULL && zde->comment != NULL) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_UTF8_COMMENT_MISMATCH);\n            if (!from_buffer) {\n                _zip_buffer_free(buffer);\n            }\n            return -1;\n        }\n        zde->comment = utf8_string;\n    }\n\n    /* Zip64 */\n\n    if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) {\n        zip_uint16_t got_len;\n        const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &got_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error);\n        if (ef != NULL) {\n            if (!zip_dirent_process_ef_zip64(zde, ef, got_len, local, error)) {\n                if (!from_buffer) {\n                    _zip_buffer_free(buffer);\n                }\n                return -1;\n            }\n        }\n        is_zip64 = true;\n    }\n\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        if (!from_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return -1;\n    }\n\n    if (!from_buffer) {\n        _zip_buffer_free(buffer);\n    }\n\n    if (local && zde->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {\n        zip_uint32_t df_crc;\n        zip_uint64_t df_comp_size, df_uncomp_size;\n        if (zip_source_seek(src, central_compressed_size, SEEK_CUR) != 0 || (buffer = _zip_buffer_new_from_source(src, MAX_DATA_DESCRIPTOR_LENGTH, buf, error)) == NULL) {\n            return -1;\n        }\n        if (memcmp(_zip_buffer_peek(buffer, MAGIC_LEN), DATADES_MAGIC, MAGIC_LEN) == 0) {\n            _zip_buffer_skip(buffer, MAGIC_LEN);\n        }\n        df_crc = _zip_buffer_get_32(buffer);\n        df_comp_size = is_zip64 ? _zip_buffer_get_64(buffer) : _zip_buffer_get_32(buffer);\n        df_uncomp_size = is_zip64 ? _zip_buffer_get_64(buffer) : _zip_buffer_get_32(buffer);\n\n        if (!_zip_buffer_ok(buffer)) {\n            zip_error_set(error, ZIP_ER_INTERNAL, 0);\n            _zip_buffer_free(buffer);\n            return -1;\n        }\n        _zip_buffer_free(buffer);\n\n        if ((zde->crc != 0 && zde->crc != df_crc) || (zde->comp_size != 0 && zde->comp_size != df_comp_size) || (zde->uncomp_size != 0 && zde->uncomp_size != df_uncomp_size)) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_DATA_DESCRIPTOR_MISMATCH);\n            return -1;\n        }\n        zde->crc = df_crc;\n        zde->comp_size = df_comp_size;\n        zde->uncomp_size = df_uncomp_size;\n    }\n\n    /* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */\n    if (zde->offset > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return -1;\n    }\n\n    if (!_zip_dirent_process_winzip_aes(zde, error)) {\n        return -1;\n    }\n\n    zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields);\n\n    return (zip_int64_t)size + (zip_int64_t)variable_size;\n}\n\nbool\nzip_dirent_process_ef_zip64(zip_dirent_t *zde, const zip_uint8_t *ef, zip_uint64_t got_len, bool local, zip_error_t *error) {\n    zip_buffer_t *ef_buffer;\n\n    if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return false;\n    }\n\n    if (zde->uncomp_size == ZIP_UINT32_MAX) {\n        zde->uncomp_size = _zip_buffer_get_64(ef_buffer);\n    }\n    else if (local) {\n        /* From appnote.txt: This entry in the Local header MUST\n           include BOTH original and compressed file size fields. */\n        (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */\n    }\n    if (zde->comp_size == ZIP_UINT32_MAX) {\n        zde->comp_size = _zip_buffer_get_64(ef_buffer);\n    }\n    if (!local) {\n        if (zde->offset == ZIP_UINT32_MAX) {\n            zde->offset = _zip_buffer_get_64(ef_buffer);\n        }\n        if (zde->disk_number == ZIP_UINT16_MAX) {\n            zde->disk_number = _zip_buffer_get_32(ef_buffer);\n        }\n    }\n\n    if (!_zip_buffer_eof(ef_buffer)) {\n        /* accept additional fields if values match */\n        bool ok = true;\n        switch (got_len) {\n        case 28:\n            _zip_buffer_set_offset(ef_buffer, 24);\n            if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) {\n                ok = false;\n            }\n            /* fallthrough */\n        case 24:\n            _zip_buffer_set_offset(ef_buffer, 0);\n            if ((zde->uncomp_size != _zip_buffer_get_64(ef_buffer)) || (zde->comp_size != _zip_buffer_get_64(ef_buffer)) || (zde->offset != _zip_buffer_get_64(ef_buffer))) {\n                ok = false;\n            }\n            break;\n\n        default:\n            ok = false;\n        }\n        if (!ok) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_ZIP64_EF);\n            _zip_buffer_free(ef_buffer);\n            return false;\n        }\n    }\n    _zip_buffer_free(ef_buffer);\n\n    return true;\n}\n\n\nstatic zip_string_t *\n_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str, bool check_consistency) {\n    zip_uint16_t ef_len;\n    zip_uint32_t ef_crc;\n    zip_buffer_t *buffer;\n\n    const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL);\n\n    if (ef == NULL || ef_len < 5 || ef[0] != 1) {\n        return str;\n    }\n\n    if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) {\n        return str;\n    }\n\n    _zip_buffer_get_8(buffer);\n    ef_crc = _zip_buffer_get_32(buffer);\n\n    if (_zip_string_crc32(str) == ef_crc) {\n        zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer);\n        zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL);\n\n        if (ef_str != NULL) {\n            if (check_consistency) {\n                if (!_zip_string_equal(str, ef_str) && _zip_string_is_ascii(ef_str)) {\n                    _zip_string_free(ef_str);\n                    _zip_buffer_free(buffer);\n                    return NULL;\n                }\n            }\n\n            _zip_string_free(str);\n            str = ef_str;\n        }\n    }\n\n    _zip_buffer_free(buffer);\n\n    return str;\n}\n\n\nstatic bool\n_zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) {\n    zip_uint16_t ef_len;\n    zip_buffer_t *buffer;\n    const zip_uint8_t *ef;\n    bool crc_valid;\n    zip_uint16_t enc_method;\n\n\n    if (de->comp_method != ZIP_CM_WINZIP_AES) {\n        return true;\n    }\n\n    ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, ZIP_EF_WINZIP_AES, 0, ZIP_EF_BOTH, NULL);\n\n    if (ef == NULL || ef_len < 7) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF);\n        return false;\n    }\n\n    if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return false;\n    }\n\n    /* version */\n\n    crc_valid = true;\n    switch (_zip_buffer_get_16(buffer)) {\n    case 1:\n        break;\n\n    case 2:\n        crc_valid = false;\n        /* TODO: When checking consistency, check that crc is 0. */\n        break;\n\n    default:\n        zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);\n        _zip_buffer_free(buffer);\n        return false;\n    }\n\n    /* vendor */\n    if (memcmp(_zip_buffer_get(buffer, 2), \"AE\", 2) != 0) {\n        zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);\n        _zip_buffer_free(buffer);\n        return false;\n    }\n\n    /* mode */\n    switch (_zip_buffer_get_8(buffer)) {\n    case 1:\n        enc_method = ZIP_EM_AES_128;\n        break;\n    case 2:\n        enc_method = ZIP_EM_AES_192;\n        break;\n    case 3:\n        enc_method = ZIP_EM_AES_256;\n        break;\n    default:\n        zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);\n        _zip_buffer_free(buffer);\n        return false;\n    }\n\n    if (ef_len != 7) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF);\n        _zip_buffer_free(buffer);\n        return false;\n    }\n\n    de->crc_valid = crc_valid;\n    de->encryption_method = enc_method;\n    de->comp_method = _zip_buffer_get_16(buffer);\n\n    _zip_buffer_free(buffer);\n    return true;\n}\n\n\nzip_int32_t\n_zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) {\n    zip_int32_t size;\n    bool local = (flags & ZIP_EF_LOCAL) != 0;\n    int i;\n    zip_uint8_t b[6];\n    zip_buffer_t *buffer;\n\n    size = local ? LENTRYSIZE : CDENTRYSIZE;\n\n    if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) {\n        zip_error_set_from_source(error, src);\n        return -1;\n    }\n\n    if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) {\n        return -1;\n    }\n\n    for (i = 0; i < (local ? 2 : 3); i++) {\n        size += _zip_buffer_get_16(buffer);\n    }\n\n    if (!_zip_buffer_eof(buffer)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        _zip_buffer_free(buffer);\n        return -1;\n    }\n\n    _zip_buffer_free(buffer);\n    return size;\n}\n\n\n/* _zip_dirent_write\n   Writes zip directory entry.\n\n   If flags & ZIP_EF_LOCAL, it writes a local header instead of a central\n   directory entry.  If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed.\n\n   Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is\n   returned.\n*/\n\nint\n_zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) {\n    zip_dostime_t dostime;\n    zip_encoding_type_t com_enc, name_enc;\n    zip_extra_field_t *ef;\n    zip_extra_field_t *ef64;\n    zip_uint32_t ef_total_size;\n    bool is_zip64;\n    bool is_really_zip64;\n    bool is_winzip_aes;\n    zip_uint8_t buf[CDENTRYSIZE];\n    zip_buffer_t *buffer;\n\n    ef = NULL;\n\n    name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);\n    com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);\n\n    if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN))\n        de->bitflags |= ZIP_GPBF_ENCODING_UTF_8;\n    else {\n        de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8;\n        if (name_enc == ZIP_ENCODING_UTF8_KNOWN) {\n            ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error);\n            if (ef == NULL)\n                return -1;\n        }\n        if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN) {\n            zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error);\n            if (ef2 == NULL) {\n                _zip_ef_free(ef);\n                return -1;\n            }\n            ef2->next = ef;\n            ef = ef2;\n        }\n    }\n\n    if (de->encryption_method == ZIP_EM_NONE) {\n        de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED;\n    }\n    else {\n        de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED;\n    }\n\n    is_really_zip64 = _zip_dirent_needs_zip64(de, flags);\n    is_zip64 = (flags & (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64) || is_really_zip64;\n    is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256;\n\n    if (is_zip64) {\n        zip_uint8_t ef_zip64[EFZIP64SIZE];\n        zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64));\n        if (ef_buffer == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            _zip_ef_free(ef);\n            return -1;\n        }\n\n        if (flags & ZIP_FL_LOCAL) {\n            if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) {\n                _zip_buffer_put_64(ef_buffer, de->uncomp_size);\n                _zip_buffer_put_64(ef_buffer, de->comp_size);\n            }\n        }\n        else {\n            if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) {\n                if (de->uncomp_size >= ZIP_UINT32_MAX) {\n                    _zip_buffer_put_64(ef_buffer, de->uncomp_size);\n                }\n                if (de->comp_size >= ZIP_UINT32_MAX) {\n                    _zip_buffer_put_64(ef_buffer, de->comp_size);\n                }\n                if (de->offset >= ZIP_UINT32_MAX) {\n                    _zip_buffer_put_64(ef_buffer, de->offset);\n                }\n            }\n        }\n\n        if (!_zip_buffer_ok(ef_buffer)) {\n            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n            _zip_buffer_free(ef_buffer);\n            _zip_ef_free(ef);\n            return -1;\n        }\n\n        ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH);\n        _zip_buffer_free(ef_buffer);\n        ef64->next = ef;\n        ef = ef64;\n    }\n\n    if (is_winzip_aes) {\n        zip_uint8_t data[EF_WINZIP_AES_SIZE];\n        zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data));\n        zip_extra_field_t *ef_winzip;\n\n        if (ef_buffer == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            _zip_ef_free(ef);\n            return -1;\n        }\n\n        _zip_buffer_put_16(ef_buffer, 2);\n        _zip_buffer_put(ef_buffer, \"AE\", 2);\n        _zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff));\n        _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method);\n\n        if (!_zip_buffer_ok(ef_buffer)) {\n            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n            _zip_buffer_free(ef_buffer);\n            _zip_ef_free(ef);\n            return -1;\n        }\n\n        ef_winzip = _zip_ef_new(ZIP_EF_WINZIP_AES, EF_WINZIP_AES_SIZE, data, ZIP_EF_BOTH);\n        _zip_buffer_free(ef_buffer);\n        ef_winzip->next = ef;\n        ef = ef_winzip;\n    }\n\n    if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        _zip_ef_free(ef);\n        return -1;\n    }\n\n    _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4);\n\n    if ((flags & ZIP_FL_LOCAL) == 0) {\n        _zip_buffer_put_16(buffer, de->version_madeby);\n    }\n    _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed));\n    _zip_buffer_put_16(buffer, de->bitflags);\n    if (is_winzip_aes) {\n        _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);\n    }\n    else {\n        _zip_buffer_put_16(buffer, (zip_uint16_t)ZIP_CM_ACTUAL(de->comp_method));\n    }\n\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        dostime.time = 0xbc00;\n        dostime.date = 0x2198;\n    }\n    else {\n        dostime = de->last_mod;\n    }\n    _zip_buffer_put_16(buffer, dostime.time);\n    _zip_buffer_put_16(buffer, dostime.date);\n\n    if (is_winzip_aes && de->uncomp_size < 20) {\n        _zip_buffer_put_32(buffer, 0);\n    }\n    else {\n        _zip_buffer_put_32(buffer, de->crc);\n    }\n\n    if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) {\n        /* In local headers, if a ZIP64 EF is written, it MUST contain\n         * both compressed and uncompressed sizes (even if one of the\n         * two is smaller than 0xFFFFFFFF); on the other hand, those\n         * may only appear when the corresponding standard entry is\n         * 0xFFFFFFFF.  (appnote.txt 4.5.3) */\n        _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);\n        _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);\n    }\n    else {\n        if (de->comp_size < ZIP_UINT32_MAX) {\n            _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);\n        }\n        else {\n            _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);\n        }\n        if (de->uncomp_size < ZIP_UINT32_MAX) {\n            _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);\n        }\n        else {\n            _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);\n        }\n    }\n\n    _zip_buffer_put_16(buffer, _zip_string_length(de->filename));\n    ef_total_size = (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH);\n    if (!ZIP_WANT_TORRENTZIP(za)) {\n        /* TODO: check for overflow */\n        ef_total_size += (zip_uint32_t)_zip_ef_size(de->extra_fields, flags);\n    }\n    _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size);\n\n    if ((flags & ZIP_FL_LOCAL) == 0) {\n        _zip_buffer_put_16(buffer, ZIP_WANT_TORRENTZIP(za) ? 0 : _zip_string_length(de->comment));\n        _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number);\n        _zip_buffer_put_16(buffer, de->int_attrib);\n        _zip_buffer_put_32(buffer, de->ext_attrib);\n        if (de->offset < ZIP_UINT32_MAX)\n            _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset);\n        else\n            _zip_buffer_put_32(buffer, ZIP_UINT32_MAX);\n    }\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        _zip_buffer_free(buffer);\n        _zip_ef_free(ef);\n        return -1;\n    }\n\n    if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) {\n        _zip_buffer_free(buffer);\n        _zip_ef_free(ef);\n        return -1;\n    }\n\n    _zip_buffer_free(buffer);\n\n    if (de->filename) {\n        if (_zip_string_write(za, de->filename) < 0) {\n            _zip_ef_free(ef);\n            return -1;\n        }\n    }\n\n    if (ef) {\n        if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) {\n            _zip_ef_free(ef);\n            return -1;\n        }\n    }\n    _zip_ef_free(ef);\n    if (de->extra_fields && !ZIP_WANT_TORRENTZIP(za)) {\n        if (_zip_ef_write(za, de->extra_fields, flags) < 0) {\n            return -1;\n        }\n    }\n\n    if ((flags & ZIP_FL_LOCAL) == 0 && !ZIP_WANT_TORRENTZIP(za)) {\n        if (de->comment) {\n            if (_zip_string_write(za, de->comment) < 0) {\n                return -1;\n            }\n        }\n    }\n\n\n    return is_zip64;\n}\n\n\ntime_t\n_zip_d2u_time(const zip_dostime_t *dtime) {\n    struct tm tm;\n\n    memset(&tm, 0, sizeof(tm));\n\n    /* let mktime decide if DST is in effect */\n    tm.tm_isdst = -1;\n\n    tm.tm_year = ((dtime->date >> 9) & 127) + 1980 - 1900;\n    tm.tm_mon = ((dtime->date >> 5) & 15) - 1;\n    tm.tm_mday = dtime->date & 31;\n\n    tm.tm_hour = (dtime->time >> 11) & 31;\n    tm.tm_min = (dtime->time >> 5) & 63;\n    tm.tm_sec = (dtime->time << 1) & 62;\n\n    return mktime(&tm);\n}\n\n\nstatic zip_extra_field_t *\n_zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) {\n    const zip_uint8_t *raw;\n    zip_uint32_t len;\n    zip_buffer_t *buffer;\n    zip_extra_field_t *ef;\n\n    if ((raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) {\n        /* error already set */\n        return NULL;\n    }\n\n    if (len + 5 > ZIP_UINT16_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */\n        return NULL;\n    }\n\n    if ((buffer = _zip_buffer_new(NULL, len + 5)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    _zip_buffer_put_8(buffer, 1);\n    _zip_buffer_put_32(buffer, _zip_string_crc32(str));\n    _zip_buffer_put(buffer, raw, len);\n\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        _zip_buffer_free(buffer);\n        return NULL;\n    }\n\n    ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH);\n    _zip_buffer_free(buffer);\n\n    return ef;\n}\n\n\nzip_dirent_t *\n_zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) {\n    if (error == NULL)\n        error = &za->error;\n\n    if (idx >= za->nentry) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) {\n        if (za->entry[idx].orig == NULL) {\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n        if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) {\n            zip_error_set(error, ZIP_ER_DELETED, 0);\n            return NULL;\n        }\n        return za->entry[idx].orig;\n    }\n    else\n        return za->entry[idx].changes;\n}\n\n\nint\n_zip_u2d_time(time_t intime, zip_dostime_t *dtime, zip_error_t *ze) {\n    struct tm *tpm;\n    struct tm tm;\n    tpm = zip_localtime(&intime, &tm);\n    if (tpm == NULL) {\n        /* if localtime fails, return an arbitrary date (1980-01-01 00:00:00) */\n        dtime->date = (1 << 5) + 1;\n        dtime->time = 0;\n        if (ze) {\n            zip_error_set(ze, ZIP_ER_INVAL, errno);\n        }\n        return -1;\n    }\n    if (tpm->tm_year < 80) {\n        tpm->tm_year = 80;\n    }\n\n    dtime->date = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday);\n    dtime->time = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1));\n\n    return 0;\n}\n\n\nbool\n_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64) {\n    zip_uint16_t length;\n    bool has_changed = false;\n\n    if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {\n        zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;\n        zip_uint16_t bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask);\n        if (de->bitflags != bitflags) {\n            de->bitflags = bitflags;\n            has_changed = true;\n        }\n    }\n    if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) {\n        zip_uint16_t int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0);\n        if (de->int_attrib != int_attrib) {\n            de->int_attrib = int_attrib;\n            has_changed = true;\n        }\n    }\n    /* manually set attributes are preferred over attributes provided by source */\n    if ((de->changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) {\n        if (de->ext_attrib != attributes->external_file_attributes) {\n            de->ext_attrib = attributes->external_file_attributes;\n            has_changed = true;\n        }\n    }\n\n    zip_uint16_t version_needed;\n    if (de->comp_method == ZIP_CM_LZMA) {\n        version_needed = 63;\n    }\n    else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) {\n        version_needed = 51;\n    }\n    else if (de->comp_method == ZIP_CM_BZIP2) {\n        version_needed = 46;\n    }\n    else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {\n        version_needed = 45;\n    }\n    else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {\n        version_needed = 20;\n    }\n    else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') {\n        version_needed = 20;\n    }\n    else {\n        version_needed = 10;\n    }\n\n    if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {\n        version_needed = ZIP_MAX(version_needed, attributes->version_needed);\n    }\n\n    if (de->version_needed != version_needed) {\n        de->version_needed = version_needed;\n        has_changed = true;\n    }\n\n    zip_int16_t version_madeby = 63 | (de->version_madeby & 0xff00);\n    if ((de->changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) {\n        version_madeby = (version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8);\n    }\n    if (de->version_madeby != version_madeby) {\n        de->version_madeby = version_madeby;\n        has_changed = true;\n    }\n\n    return has_changed;\n}\n\n\n/* _zip_dirent_torrent_normalize(de);\n   Set values suitable for torrentzip.\n*/\n\nvoid\nzip_dirent_torrentzip_normalize(zip_dirent_t *de) {\n    de->version_madeby = 0;\n    de->version_needed = 20; /* 2.0 */\n    de->bitflags = 2;        /* maximum compression */\n    de->comp_method = ZIP_CM_DEFLATE;\n    de->compression_level = TORRENTZIP_COMPRESSION_FLAGS;\n    de->disk_number = 0;\n    de->int_attrib = 0;\n    de->ext_attrib = 0;\n\n    /* last_mod, extra_fields, and comment are normalized in zip_dirent_write() directly */\n}\n\nint\nzip_dirent_check_consistency(zip_dirent_t *dirent) {\n    if (dirent->comp_method == ZIP_CM_STORE) {\n        zip_uint64_t header_size = 0;\n        switch (dirent->encryption_method) {\n        case ZIP_EM_NONE:\n            break;\n        case ZIP_EM_TRAD_PKWARE:\n            header_size = 12;\n            break;\n        case ZIP_EM_AES_128:\n            header_size = 20;\n            break;\n        case ZIP_EM_AES_192:\n            header_size = 24;\n            break;\n        case ZIP_EM_AES_256:\n            header_size = 28;\n            break;\n\n        default:\n            return 0;\n        }\n        if (dirent->uncomp_size + header_size < dirent->uncomp_size || dirent->comp_size != dirent->uncomp_size + header_size) {\n            return ZIP_ER_DETAIL_STORED_SIZE_MISMATCH;\n        }\n    }\n    return 0;\n}\n\ntime_t\nzip_dirent_get_last_mod_mtime(zip_dirent_t *de) {\n    if (!de->last_mod_mtime_valid) {\n        de->last_mod_mtime = _zip_d2u_time(&de->last_mod);\n        de->last_mod_mtime_valid = true;\n    }\n\n    return de->last_mod_mtime;\n}"
  },
  {
    "path": "external/libzip/lib/zip_discard.c",
    "content": "/*\n  zip_discard.c -- discard and free struct zip\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\n/* zip_discard:\n   frees the space allocated to a zipfile struct, and closes the\n   corresponding file. */\n\nvoid\nzip_discard(zip_t *za) {\n    zip_uint64_t i;\n\n    if (za == NULL)\n        return;\n\n    if (za->src) {\n        zip_source_close(za->src);\n        zip_source_free(za->src);\n    }\n\n    free(za->default_password);\n    _zip_string_free(za->comment_orig);\n    _zip_string_free(za->comment_changes);\n\n    _zip_hash_free(za->names);\n\n    if (za->entry) {\n        for (i = 0; i < za->nentry; i++)\n            _zip_entry_finalize(za->entry + i);\n        free(za->entry);\n    }\n\n    for (i = 0; i < za->nopen_source; i++) {\n        _zip_source_invalidate(za->open_source[i]);\n    }\n    free(za->open_source);\n\n    _zip_progress_free(za->progress);\n\n    zip_error_fini(&za->error);\n\n    free(za);\n\n    return;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_entry.c",
    "content": "/*\n  zip_entry.c -- struct zip_entry helper functions\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\nvoid\n_zip_entry_finalize(zip_entry_t *e) {\n    _zip_unchange_data(e);\n    _zip_dirent_free(e->orig);\n    _zip_dirent_free(e->changes);\n}\n\n\nvoid\n_zip_entry_init(zip_entry_t *e) {\n    e->orig = NULL;\n    e->changes = NULL;\n    e->source = NULL;\n    e->deleted = 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error.c",
    "content": "/*\n  zip_error.c -- zip_error_t helper functions\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_error_code_system(const zip_error_t *error) {\n    return error->sys_err;\n}\n\n\nZIP_EXTERN int\nzip_error_code_zip(const zip_error_t *error) {\n    return error->zip_err;\n}\n\n\nZIP_EXTERN void\nzip_error_fini(zip_error_t *err) {\n    free(err->str);\n    err->str = NULL;\n}\n\n\nZIP_EXTERN void\nzip_error_init(zip_error_t *err) {\n    err->zip_err = ZIP_ER_OK;\n    err->sys_err = 0;\n    err->str = NULL;\n}\n\nZIP_EXTERN void\nzip_error_init_with_code(zip_error_t *error, int ze) {\n    zip_error_init(error);\n    error->zip_err = ze;\n    switch (zip_error_system_type(error)) {\n        case ZIP_ET_SYS:\n        case ZIP_ET_LIBZIP:\n            error->sys_err = errno;\n            break;\n            \n        default:\n            error->sys_err = 0;\n            break;\n    }\n}\n\n\nZIP_EXTERN int\nzip_error_system_type(const zip_error_t *error) {\n    if (error->zip_err < 0 || error->zip_err >= _zip_err_str_count)\n        return ZIP_ET_NONE;\n\n    return _zip_err_str[error->zip_err].type;\n}\n\n\nvoid\n_zip_error_clear(zip_error_t *err) {\n    if (err == NULL)\n        return;\n\n    err->zip_err = ZIP_ER_OK;\n    err->sys_err = 0;\n}\n\n\nvoid\n_zip_error_copy(zip_error_t *dst, const zip_error_t *src) {\n    if (dst == NULL) {\n        return;\n    }\n\n    dst->zip_err = src->zip_err;\n    dst->sys_err = src->sys_err;\n}\n\n\nvoid\n_zip_error_get(const zip_error_t *err, int *zep, int *sep) {\n    if (zep)\n        *zep = err->zip_err;\n    if (sep) {\n        if (zip_error_system_type(err) != ZIP_ET_NONE)\n            *sep = err->sys_err;\n        else\n            *sep = 0;\n    }\n}\n\n\nvoid\nzip_error_set(zip_error_t *err, int ze, int se) {\n    if (err) {\n        err->zip_err = ze;\n        err->sys_err = se;\n    }\n}\n\n\nvoid\nzip_error_set_from_source(zip_error_t *err, zip_source_t *src) {\n    if (src == NULL) {\n        zip_error_set(err, ZIP_ER_INVAL, 0);\n        return;\n    }\n\n    _zip_error_copy(err, zip_source_error(src));\n}\n\n\nzip_int64_t\nzip_error_to_data(const zip_error_t *error, void *data, zip_uint64_t length) {\n    int *e = (int *)data;\n\n    if (length < sizeof(int) * 2) {\n        return -1;\n    }\n\n    e[0] = zip_error_code_zip(error);\n    e[1] = zip_error_code_system(error);\n    return sizeof(int) * 2;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error_clear.c",
    "content": "/*\n  zip_error_clear.c -- clear zip error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_error_clear(zip_t *za) {\n    if (za == NULL)\n        return;\n\n    _zip_error_clear(&za->error);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error_get.c",
    "content": "/*\n  zip_error_get.c -- get zip error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_error_get(zip_t *za, int *zep, int *sep) {\n    _zip_error_get(&za->error, zep, sep);\n}\n\n\nZIP_EXTERN zip_error_t *\nzip_get_error(zip_t *za) {\n    return &za->error;\n}\n\n\nZIP_EXTERN zip_error_t *\nzip_file_get_error(zip_file_t *f) {\n    return &f->error;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error_get_sys_type.c",
    "content": "/*\n  zip_error_get_sys_type.c -- return type of system error code\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_error_get_sys_type(int ze) {\n    if (ze < 0 || ze >= _zip_err_str_count) {\n        return 0;\n    }\n\n    return _zip_err_str[ze].type;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error_strerror.c",
    "content": "/*\n  zip_error_sterror.c -- get string representation of struct zip_error\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\nZIP_EXTERN const char *\nzip_error_strerror(zip_error_t *err) {\n    const char *zip_error_string, *system_error_string;\n    char *s;\n    char *system_error_buffer = NULL;\n\n    zip_error_fini(err);\n\n    if (err->zip_err < 0 || err->zip_err >= _zip_err_str_count) {\n        system_error_buffer = (char *)malloc(128);\n        if (system_error_buffer == NULL) {\n            return _zip_err_str[ZIP_ER_MEMORY].description;\n        }\n        snprintf_s(system_error_buffer, 128, \"Unknown error %d\", err->zip_err);\n        system_error_buffer[128 - 1] = '\\0'; /* make sure string is NUL-terminated */\n        zip_error_string = NULL;\n        system_error_string = system_error_buffer;\n    }\n    else {\n        zip_error_string = _zip_err_str[err->zip_err].description;\n\n        switch (_zip_err_str[err->zip_err].type) {\n            case ZIP_ET_SYS: {\n                size_t len = strerrorlen_s(err->sys_err) + 1;\n                system_error_buffer = malloc(len);\n                if (system_error_buffer == NULL) {\n                    return _zip_err_str[ZIP_ER_MEMORY].description;\n                }\n                strerror_s(system_error_buffer, len, err->sys_err);\n                system_error_string = system_error_buffer;\n                break;\n            }\n                \n            case ZIP_ET_ZLIB:\n                system_error_string = zError(err->sys_err);\n                break;\n                \n            case ZIP_ET_LIBZIP: {\n                zip_uint8_t error = GET_ERROR_FROM_DETAIL(err->sys_err);\n                int index = GET_INDEX_FROM_DETAIL(err->sys_err);\n                \n                if (error == 0) {\n                    system_error_string = NULL;\n                }\n                else if (error >= _zip_err_details_count) {\n                    system_error_buffer = (char *)malloc(128);\n                    if (system_error_buffer == NULL) {\n                        return _zip_err_str[ZIP_ER_MEMORY].description;\n                    }\n                    snprintf_s(system_error_buffer, 128, \"invalid detail error %u\", error);\n                    system_error_buffer[128 - 1] = '\\0'; /* make sure string is NUL-terminated */\n                    system_error_string = system_error_buffer;\n                }\n                else if (_zip_err_details[error].type == ZIP_DETAIL_ET_ENTRY && index < MAX_DETAIL_INDEX) {\n                    system_error_buffer = (char *)malloc(128);\n                    if (system_error_buffer == NULL) {\n                        return _zip_err_str[ZIP_ER_MEMORY].description;\n                    }\n                    snprintf_s(system_error_buffer, 128, \"entry %d: %s\", index, _zip_err_details[error].description);\n                    system_error_buffer[128 - 1] = '\\0'; /* make sure string is NUL-terminated */\n                    system_error_string = system_error_buffer;\n                }\n                else {\n                    system_error_string = _zip_err_details[error].description;\n                }\n                break;\n            }\n                \n            default:\n                system_error_string = NULL;\n        }\n    }\n\n    if (system_error_string == NULL) {\n        free(system_error_buffer);\n        return zip_error_string;\n    }\n    else {\n        size_t length = strlen(system_error_string);\n        if (zip_error_string) {\n            size_t length_error = strlen(zip_error_string);\n            if (length + length_error + 2 < length) {\n                free(system_error_buffer);\n                return _zip_err_str[ZIP_ER_MEMORY].description;\n            }\n            length += length_error + 2;\n        }\n        if (length == SIZE_MAX || (s = (char *)malloc(length + 1)) == NULL) {\n            free(system_error_buffer);\n            return _zip_err_str[ZIP_ER_MEMORY].description;\n        }\n\n        snprintf_s(s, length + 1, \"%s%s%s\", (zip_error_string ? zip_error_string : \"\"), (zip_error_string ? \": \" : \"\"), system_error_string);\n        err->str = s;\n\n        free(system_error_buffer);\n        return s;\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_error_to_str.c",
    "content": "/*\n  zip_error_to_str.c -- get string representation of zip error code\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <string.h>\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_error_to_str(char *buf, zip_uint64_t len, int ze, int se) {\n    zip_error_t error;\n    const char *error_string;\n    int ret;\n\n    zip_error_init(&error);\n    zip_error_set(&error, ze, se);\n\n    error_string = zip_error_strerror(&error);\n\n    ret = snprintf_s(buf, ZIP_MIN(len, SIZE_MAX), error_string, strlen(error_string));\n\n    zip_error_fini(&error);\n\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_extra_field.c",
    "content": "/*\n  zip_extra_field.c -- manipulate extra fields\n  Copyright (C) 2012-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nzip_extra_field_t *\n_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) {\n    zip_extra_field_t *head, *prev, *def;\n\n    head = prev = NULL;\n\n    while (ef) {\n        if ((def = _zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            _zip_ef_free(head);\n            return NULL;\n        }\n\n        if (head == NULL)\n            head = def;\n        if (prev)\n            prev->next = def;\n        prev = def;\n\n        ef = ef->next;\n    }\n\n    return head;\n}\n\n\nzip_extra_field_t *\n_zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) {\n    zip_extra_field_t *head, *prev;\n    int i;\n\n    i = 0;\n    head = ef;\n    prev = NULL;\n    for (; ef; ef = (prev ? prev->next : head)) {\n        if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {\n            if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {\n                ef->flags &= ~(flags & ZIP_EF_BOTH);\n                if ((ef->flags & ZIP_EF_BOTH) == 0) {\n                    if (prev)\n                        prev->next = ef->next;\n                    else\n                        head = ef->next;\n                    ef->next = NULL;\n                    _zip_ef_free(ef);\n\n                    if (id_idx == ZIP_EXTRA_FIELD_ALL)\n                        continue;\n                }\n            }\n\n            i++;\n            if (i > id_idx)\n                break;\n        }\n        prev = ef;\n    }\n\n    return head;\n}\n\n\nvoid\n_zip_ef_free(zip_extra_field_t *ef) {\n    zip_extra_field_t *ef2;\n\n    while (ef) {\n        ef2 = ef->next;\n        free(ef->data);\n        free(ef);\n        ef = ef2;\n    }\n}\n\n\nconst zip_uint8_t *\n_zip_ef_get_by_id(const zip_extra_field_t *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, zip_error_t *error) {\n    static const zip_uint8_t empty[1] = {'\\0'};\n\n    int i;\n\n    i = 0;\n    for (; ef; ef = ef->next) {\n        if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {\n            if (i < id_idx) {\n                i++;\n                continue;\n            }\n\n            if (lenp)\n                *lenp = ef->size;\n            if (ef->size > 0)\n                return ef->data;\n            else\n                return empty;\n        }\n    }\n\n    zip_error_set(error, ZIP_ER_NOENT, 0);\n    return NULL;\n}\n\n\nzip_extra_field_t *\n_zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from) {\n    zip_extra_field_t *ef2, *tt, *tail;\n    int duplicate;\n\n    if (to == NULL)\n        return from;\n\n    for (tail = to; tail->next; tail = tail->next)\n        ;\n\n    for (; from; from = ef2) {\n        ef2 = from->next;\n\n        duplicate = 0;\n        for (tt = to; tt; tt = tt->next) {\n            if (tt->id == from->id && tt->size == from->size && (tt->size == 0 || memcmp(tt->data, from->data, tt->size) == 0)) {\n                tt->flags |= (from->flags & ZIP_EF_BOTH);\n                duplicate = 1;\n                break;\n            }\n        }\n\n        from->next = NULL;\n        if (duplicate)\n            _zip_ef_free(from);\n        else\n            tail = tail->next = from;\n    }\n\n    return to;\n}\n\n\nzip_extra_field_t *\n_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags) {\n    zip_extra_field_t *ef;\n\n    if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL)\n        return NULL;\n\n    ef->next = NULL;\n    ef->flags = flags;\n    ef->id = id;\n    ef->size = size;\n    if (size > 0) {\n        if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {\n            free(ef);\n            return NULL;\n        }\n    }\n    else\n        ef->data = NULL;\n\n    return ef;\n}\n\n\nbool\n_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) {\n    zip_buffer_t *buffer;\n    zip_extra_field_t *ef, *ef2, *ef_head;\n\n    if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return false;\n    }\n\n    ef_head = ef = NULL;\n\n    while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {\n        zip_uint16_t fid, flen;\n        zip_uint8_t *ef_data;\n\n        fid = _zip_buffer_get_16(buffer);\n        flen = _zip_buffer_get_16(buffer);\n        ef_data = _zip_buffer_get(buffer, flen);\n\n        if (ef_data == NULL) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH);\n            _zip_buffer_free(buffer);\n            _zip_ef_free(ef_head);\n            return false;\n        }\n\n        if ((ef2 = _zip_ef_new(fid, flen, ef_data, flags)) == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            _zip_buffer_free(buffer);\n            _zip_ef_free(ef_head);\n            return false;\n        }\n\n        if (ef_head) {\n            ef->next = ef2;\n            ef = ef2;\n        }\n        else\n            ef_head = ef = ef2;\n    }\n\n    if (!_zip_buffer_eof(buffer)) {\n        /* Android APK files align stored file data with padding in extra fields; ignore. */\n        /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */\n        /* buffer is at most 64k long, so this can't overflow. */\n        size_t glen = _zip_buffer_left(buffer);\n        zip_uint8_t *garbage;\n        garbage = _zip_buffer_get(buffer, glen);\n        if (glen >= 4 || garbage == NULL || memcmp(garbage, \"\\0\\0\\0\", (size_t)glen) != 0) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE);\n            _zip_buffer_free(buffer);\n            _zip_ef_free(ef_head);\n            return false;\n        }\n    }\n\n    _zip_buffer_free(buffer);\n\n    if (ef_head_p) {\n        *ef_head_p = ef_head;\n    }\n    else {\n        _zip_ef_free(ef_head);\n    }\n\n    return true;\n}\n\n\nzip_extra_field_t *\n_zip_ef_remove_internal(zip_extra_field_t *ef) {\n    zip_extra_field_t *ef_head;\n    zip_extra_field_t *prev, *next;\n\n    ef_head = ef;\n    prev = NULL;\n\n    while (ef) {\n        if (ZIP_EF_IS_INTERNAL(ef->id)) {\n            next = ef->next;\n            if (ef_head == ef)\n                ef_head = next;\n            ef->next = NULL;\n            _zip_ef_free(ef);\n            if (prev)\n                prev->next = next;\n            ef = next;\n        }\n        else {\n            prev = ef;\n            ef = ef->next;\n        }\n    }\n\n    return ef_head;\n}\n\n\nzip_uint16_t\n_zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags) {\n    zip_uint16_t size;\n\n    size = 0;\n    for (; ef; ef = ef->next) {\n        if (ef->flags & flags & ZIP_EF_BOTH)\n            size = (zip_uint16_t)(size + 4 + ef->size);\n    }\n\n    return size;\n}\n\n\nint\n_zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags) {\n    zip_uint8_t b[4];\n    zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b));\n\n    if (buffer == NULL) {\n        return -1;\n    }\n\n    for (; ef; ef = ef->next) {\n        if (ef->flags & flags & ZIP_EF_BOTH) {\n            _zip_buffer_set_offset(buffer, 0);\n            _zip_buffer_put_16(buffer, ef->id);\n            _zip_buffer_put_16(buffer, ef->size);\n            if (!_zip_buffer_ok(buffer)) {\n                zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n                _zip_buffer_free(buffer);\n                return -1;\n            }\n            if (_zip_write(za, b, 4) < 0) {\n                _zip_buffer_free(buffer);\n                return -1;\n            }\n            if (ef->size > 0) {\n                if (_zip_write(za, ef->data, ef->size) < 0) {\n                    _zip_buffer_free(buffer);\n                    return -1;\n                }\n            }\n        }\n    }\n\n    _zip_buffer_free(buffer);\n    return 0;\n}\n\n\nint\n_zip_read_local_ef(zip_t *za, zip_uint64_t idx) {\n    zip_entry_t *e;\n    unsigned char b[4];\n    zip_buffer_t *buffer;\n    zip_uint16_t fname_len, ef_len;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n    if (e->orig == NULL || e->orig->local_extra_fields_read)\n        return 0;\n\n    if (e->orig->offset + 26 > ZIP_INT64_MAX) {\n        zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);\n        return -1;\n    }\n\n    if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n\n    if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) {\n        return -1;\n    }\n\n    fname_len = _zip_buffer_get_16(buffer);\n    ef_len = _zip_buffer_get_16(buffer);\n\n    if (!_zip_buffer_eof(buffer)) {\n        _zip_buffer_free(buffer);\n        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    _zip_buffer_free(buffer);\n\n    if (ef_len > 0) {\n        zip_extra_field_t *ef;\n        zip_uint8_t *ef_raw;\n\n        if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {\n            zip_error_set(&za->error, ZIP_ER_SEEK, errno);\n            return -1;\n        }\n\n        ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);\n\n        if (ef_raw == NULL)\n            return -1;\n\n        if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) {\n            free(ef_raw);\n            return -1;\n        }\n        free(ef_raw);\n\n        if (ef) {\n            ef = _zip_ef_remove_internal(ef);\n            e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);\n        }\n    }\n\n    e->orig->local_extra_fields_read = 1;\n\n    if (e->changes && e->changes->local_extra_fields_read == 0) {\n        e->changes->extra_fields = e->orig->extra_fields;\n        e->changes->local_extra_fields_read = 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_extra_field_api.c",
    "content": "/*\n  zip_extra_field_api.c -- public extra fields API functions\n  Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_file_extra_field_delete(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags) {\n    zip_dirent_t *de;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)\n        return -1;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)\n        return -1;\n\n    de = za->entry[idx].changes;\n\n    de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags);\n    return 0;\n}\n\n\nZIP_EXTERN int\nzip_file_extra_field_delete_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) {\n    zip_dirent_t *de;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)\n        return -1;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)\n        return -1;\n\n    de = za->entry[idx].changes;\n\n    de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags);\n    return 0;\n}\n\n\nZIP_EXTERN const zip_uint8_t *\nzip_file_extra_field_get(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags) {\n    static const zip_uint8_t empty[1] = {'\\0'};\n\n    zip_dirent_t *de;\n    zip_extra_field_t *ef;\n    int i;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)\n        return NULL;\n\n    if (flags & ZIP_FL_LOCAL)\n        if (_zip_read_local_ef(za, idx) < 0)\n            return NULL;\n\n    i = 0;\n    for (ef = de->extra_fields; ef; ef = ef->next) {\n        if (ef->flags & flags & ZIP_EF_BOTH) {\n            if (i < ef_idx) {\n                i++;\n                continue;\n            }\n\n            if (idp)\n                *idp = ef->id;\n            if (lenp)\n                *lenp = ef->size;\n            if (ef->size > 0)\n                return ef->data;\n            else\n                return empty;\n        }\n    }\n\n    zip_error_set(&za->error, ZIP_ER_NOENT, 0);\n    return NULL;\n}\n\n\nZIP_EXTERN const zip_uint8_t *\nzip_file_extra_field_get_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags) {\n    zip_dirent_t *de;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)\n        return NULL;\n\n    if (flags & ZIP_FL_LOCAL)\n        if (_zip_read_local_ef(za, idx) < 0)\n            return NULL;\n\n    return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error);\n}\n\n\nZIP_EXTERN zip_int16_t\nzip_file_extra_fields_count(zip_t *za, zip_uint64_t idx, zip_flags_t flags) {\n    zip_dirent_t *de;\n    zip_extra_field_t *ef;\n    zip_uint16_t n;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)\n        return -1;\n\n    if (flags & ZIP_FL_LOCAL)\n        if (_zip_read_local_ef(za, idx) < 0)\n            return -1;\n\n    n = 0;\n    for (ef = de->extra_fields; ef; ef = ef->next)\n        if (ef->flags & flags & ZIP_EF_BOTH)\n            n++;\n\n    return (zip_int16_t)n;\n}\n\n\nZIP_EXTERN zip_int16_t\nzip_file_extra_fields_count_by_id(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags) {\n    zip_dirent_t *de;\n    zip_extra_field_t *ef;\n    zip_uint16_t n;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if ((de = _zip_get_dirent(za, idx, flags, &za->error)) == NULL)\n        return -1;\n\n    if (flags & ZIP_FL_LOCAL)\n        if (_zip_read_local_ef(za, idx) < 0)\n            return -1;\n\n    n = 0;\n    for (ef = de->extra_fields; ef; ef = ef->next)\n        if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH))\n            n++;\n\n    return (zip_int16_t)n;\n}\n\n\nZIP_EXTERN int\nzip_file_extra_field_set(zip_t *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags) {\n    zip_dirent_t *de;\n    zip_uint16_t ls, cs;\n    zip_extra_field_t *ef, *ef_prev, *ef_new;\n    int i, found, new_len;\n\n    if ((flags & ZIP_EF_BOTH) == 0) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)\n        return -1;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (ZIP_EF_IS_INTERNAL(ef_id)) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)\n        return -1;\n\n    de = za->entry[idx].changes;\n\n    ef = de->extra_fields;\n    ef_prev = NULL;\n    i = 0;\n    found = 0;\n\n    for (; ef; ef = ef->next) {\n        if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) {\n            if (i == ef_idx) {\n                found = 1;\n                break;\n            }\n            i++;\n        }\n        ef_prev = ef;\n    }\n\n    if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (flags & ZIP_EF_LOCAL)\n        ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL);\n    else\n        ls = 0;\n    if (flags & ZIP_EF_CENTRAL)\n        cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL);\n    else\n        cs = 0;\n\n    new_len = ls > cs ? ls : cs;\n    if (found)\n        new_len -= ef->size + 4;\n    new_len += len + 4;\n\n    if (new_len > ZIP_UINT16_MAX) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if ((ef_new = _zip_ef_new(ef_id, len, data, flags)) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    if (found) {\n        if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) {\n            ef_new->next = ef->next;\n            ef->next = NULL;\n            _zip_ef_free(ef);\n            if (ef_prev)\n                ef_prev->next = ef_new;\n            else\n                de->extra_fields = ef_new;\n        }\n        else {\n            ef->flags &= ~(flags & ZIP_EF_BOTH);\n            ef_new->next = ef->next;\n            ef->next = ef_new;\n        }\n    }\n    else if (ef_prev) {\n        ef_new->next = ef_prev->next;\n        ef_prev->next = ef_new;\n    }\n    else\n        de->extra_fields = ef_new;\n\n    return 0;\n}\n\n\nint\n_zip_file_extra_field_prepare_for_change(zip_t *za, zip_uint64_t idx) {\n    zip_entry_t *e;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n    if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD))\n        return 0;\n\n    if (e->orig) {\n        if (_zip_read_local_ef(za, idx) < 0)\n            return -1;\n    }\n\n    if (e->changes == NULL) {\n        if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n\n    if (e->orig && e->orig->extra_fields) {\n        if ((e->changes->extra_fields = _zip_ef_clone(e->orig->extra_fields, &za->error)) == NULL)\n            return -1;\n    }\n    e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fclose.c",
    "content": "/*\n  zip_fclose.c -- close file in zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_fclose(zip_file_t *zf) {\n    int ret;\n\n    if (zf == NULL)\n      return ZIP_ER_INVAL;\n\n    if (zf->src)\n        zip_source_free(zf->src);\n\n    ret = 0;\n    if (zf->error.zip_err)\n        ret = zf->error.zip_err;\n\n    zip_error_fini(&zf->error);\n    free(zf);\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fdopen.c",
    "content": "/*\n  zip_fdopen.c -- open read-only archive from file descriptor\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n\nZIP_EXTERN zip_t *\nzip_fdopen(int fd_orig, int _flags, int *zep) {\n    int fd;\n    FILE *fp;\n    zip_t *za;\n    zip_source_t *src;\n    struct zip_error error;\n\n    if (_flags < 0 || (_flags & ~(ZIP_CHECKCONS | ZIP_RDONLY))) {\n        _zip_set_open_error(zep, NULL, ZIP_ER_INVAL);\n        return NULL;\n    }\n\n#ifndef ENABLE_FDOPEN\n    _zip_set_open_error(zep, NULL, ZIP_ER_OPNOTSUPP);\n    return NULL;\n#else\n    /* We dup() here to avoid messing with the passed in fd.\n       We could not restore it to the original state in case of error. */\n\n    if ((fd = dup(fd_orig)) < 0) {\n        _zip_set_open_error(zep, NULL, ZIP_ER_OPEN);\n        return NULL;\n    }\n\n    if ((fp = fdopen(fd, \"rb\")) == NULL) {\n        close(fd);\n        _zip_set_open_error(zep, NULL, ZIP_ER_OPEN);\n        return NULL;\n    }\n\n    zip_error_init(&error);\n    if ((src = zip_source_filep_create(fp, 0, -1, &error)) == NULL) {\n        fclose(fp);\n        _zip_set_open_error(zep, &error, 0);\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {\n        zip_source_free(src);\n        _zip_set_open_error(zep, &error, 0);\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    zip_error_fini(&error);\n    close(fd_orig);\n    return za;\n#endif\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_add.c",
    "content": "/*\n  zip_file_add.c -- add file via callback function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n/*\n  NOTE: Return type is signed so we can return -1 on error.\n        The index can not be larger than ZIP_INT64_MAX since the size\n        of the central directory cannot be larger than\n        ZIP_UINT64_MAX, and each entry is larger than 2 bytes.\n*/\n\nZIP_EXTERN zip_int64_t\nzip_file_add(zip_t *za, const char *name, zip_source_t *source, zip_flags_t flags) {\n    if (name == NULL || source == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    return _zip_file_replace(za, ZIP_UINT64_MAX, name, source, flags);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_error_clear.c",
    "content": "/*\n  zip_file_error_clear.c -- clear zip file error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_file_error_clear(zip_file_t *zf) {\n    if (zf == NULL)\n        return;\n\n    _zip_error_clear(&zf->error);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_error_get.c",
    "content": "/*\n  zip_file_error_get.c -- get zip file error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_file_error_get(zip_file_t *zf, int *zep, int *sep) {\n    _zip_error_get(&zf->error, zep, sep);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_get_comment.c",
    "content": "/*\n  zip_file_get_comment.c -- get file comment\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n/* lenp is 32 bit because converted comment can be longer than ZIP_UINT16_MAX */\n\nZIP_EXTERN const char *\nzip_file_get_comment(zip_t *za, zip_uint64_t idx, zip_uint32_t *lenp, zip_flags_t flags) {\n    zip_dirent_t *de;\n    zip_uint32_t len;\n    const zip_uint8_t *str;\n\n    if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL)\n        return NULL;\n\n    if ((str = _zip_string_get(de->comment, &len, flags, &za->error)) == NULL)\n        return NULL;\n\n    if (lenp)\n        *lenp = len;\n\n    return (const char *)str;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_get_external_attributes.c",
    "content": "/*\n  zip_file_get_external_attributes.c -- get opsys/external attributes\n  Copyright (C) 2013-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\nint\nzip_file_get_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t *opsys, zip_uint32_t *attributes) {\n    zip_dirent_t *de;\n\n    if ((de = _zip_get_dirent(za, idx, flags, NULL)) == NULL)\n        return -1;\n\n    if (opsys)\n        *opsys = (zip_uint8_t)((de->version_madeby >> 8) & 0xff);\n\n    if (attributes)\n        *attributes = de->ext_attrib;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_get_offset.c",
    "content": "/*\n  zip_file_get_offset.c -- get offset of file data in archive.\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\n/* _zip_file_get_offset(za, ze):\n   Returns the offset of the file data for entry ze.\n\n   On error, fills in za->error and returns 0.\n*/\n\nzip_uint64_t\n_zip_file_get_offset(const zip_t *za, zip_uint64_t idx, zip_error_t *error) {\n    zip_uint64_t offset;\n    zip_int32_t size;\n\n    if (za->entry[idx].orig == NULL) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return 0;\n    }\n\n    offset = za->entry[idx].orig->offset;\n\n    if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {\n        zip_error_set_from_source(error, za->src);\n        return 0;\n    }\n\n    /* TODO: cache? */\n    if ((size = _zip_dirent_size(za->src, ZIP_EF_LOCAL, error)) < 0)\n        return 0;\n\n    if (offset + (zip_uint32_t)size > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return 0;\n    }\n\n    return offset + (zip_uint32_t)size;\n}\n\nzip_uint64_t\n_zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error) {\n    zip_uint64_t offset;\n    zip_dirent_t *entry;\n\n    if ((offset = _zip_file_get_offset(za, index, error)) == 0) {\n        return 0;\n    }\n\n    entry = za->entry[index].orig;\n\n    if (offset + entry->comp_size < offset || offset + entry->comp_size > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return 0;\n    }\n    offset += entry->comp_size;\n\n    if (entry->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {\n        zip_uint8_t buf[4];\n        if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {\n            zip_error_set_from_source(error, za->src);\n            return 0;\n        }\n        if (zip_source_read(za->src, buf, 4) != 4) {\n            zip_error_set_from_source(error, za->src);\n            return 0;\n        }\n        if (memcmp(buf, DATADES_MAGIC, 4) == 0) {\n            offset += 4;\n        }\n        offset += 12;\n        if (_zip_dirent_needs_zip64(entry, 0)) {\n            offset += 8;\n        }\n        if (offset > ZIP_INT64_MAX) {\n            zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n            return 0;\n        }\n    }\n\n    return offset;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_rename.c",
    "content": "/*\n  zip_file_rename.c -- rename file in zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_file_rename(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) {\n    const char *old_name;\n    int old_is_dir, new_is_dir;\n\n    if (idx >= za->nentry || (name != NULL && strlen(name) > ZIP_UINT16_MAX)) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if ((old_name = zip_get_name(za, idx, 0)) == NULL)\n        return -1;\n\n    new_is_dir = (name != NULL && name[strlen(name) - 1] == '/');\n    old_is_dir = (old_name[strlen(old_name) - 1] == '/');\n\n    if (new_is_dir != old_is_dir) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    return _zip_set_name(za, idx, name, flags);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_replace.c",
    "content": "/*\n  zip_file_replace.c -- replace file via callback function\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_file_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source, zip_flags_t flags) {\n    if (idx >= za->nentry || source == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_file_replace(za, idx, NULL, source, flags) == -1)\n        return -1;\n\n    return 0;\n}\n\n\n/* NOTE: Signed due to -1 on error.  See zip_add.c for more details. */\n\nzip_int64_t\n_zip_file_replace(zip_t *za, zip_uint64_t idx, const char *name, zip_source_t *source, zip_flags_t flags) {\n    zip_uint64_t za_nentry_prev;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    za_nentry_prev = za->nentry;\n    if (idx == ZIP_UINT64_MAX) {\n        zip_int64_t i = -1;\n\n        if (flags & ZIP_FL_OVERWRITE)\n            i = _zip_name_locate(za, name, flags, NULL);\n\n        if (i == -1) {\n            /* create and use new entry, used by zip_add */\n            if ((i = _zip_add_entry(za)) < 0)\n                return -1;\n        }\n        idx = (zip_uint64_t)i;\n    }\n\n    if (name && _zip_set_name(za, idx, name, flags) != 0) {\n        if (za->nentry != za_nentry_prev) {\n            _zip_entry_finalize(za->entry + idx);\n            za->nentry = za_nentry_prev;\n        }\n        return -1;\n    }\n\n    /* delete all extra fields - these are usually data that are\n     * strongly coupled with the original data */\n    if (zip_file_extra_field_delete(za, idx, ZIP_EXTRA_FIELD_ALL, ZIP_FL_CENTRAL | ZIP_FL_LOCAL) < 0) {\n        return -1;\n    }\n\n    /* does not change any name related data, so we can do it here;\n     * needed for a double add of the same file name */\n    _zip_unchange_data(za->entry + idx);\n\n    if (za->entry[idx].orig != NULL && (za->entry[idx].changes == NULL || (za->entry[idx].changes->changed & ZIP_DIRENT_COMP_METHOD) == 0)) {\n        if (za->entry[idx].changes == NULL) {\n            if ((za->entry[idx].changes = _zip_dirent_clone(za->entry[idx].orig)) == NULL) {\n                zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n        }\n\n        za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT;\n        za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD;\n    }\n\n    za->entry[idx].source = source;\n\n    return (zip_int64_t)idx;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_set_comment.c",
    "content": "/*\n  zip_file_set_comment.c -- set comment for file in archive\n  Copyright (C) 2006-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_file_set_comment(zip_t *za, zip_uint64_t idx, const char *comment, zip_uint16_t len, zip_flags_t flags) {\n    zip_entry_t *e;\n    zip_string_t *cstr;\n    int changed;\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)\n        return -1;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (len > 0 && comment == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (len > 0) {\n        if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, flags, &za->error)) == NULL)\n            return -1;\n        if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED)\n            cstr->encoding = ZIP_ENCODING_UTF8_KNOWN;\n    }\n    else\n        cstr = NULL;\n\n    e = za->entry + idx;\n\n    if (e->changes) {\n        _zip_string_free(e->changes->comment);\n        e->changes->comment = NULL;\n        e->changes->changed &= ~ZIP_DIRENT_COMMENT;\n    }\n\n    if (e->orig && e->orig->comment)\n        changed = !_zip_string_equal(e->orig->comment, cstr);\n    else\n        changed = (cstr != NULL);\n\n    if (changed) {\n        if (e->changes == NULL) {\n            if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n                zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n                _zip_string_free(cstr);\n                return -1;\n            }\n        }\n        e->changes->comment = cstr;\n        e->changes->changed |= ZIP_DIRENT_COMMENT;\n    }\n    else {\n        _zip_string_free(cstr);\n        if (e->changes && e->changes->changed == 0) {\n            _zip_dirent_free(e->changes);\n            e->changes = NULL;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_set_encryption.c",
    "content": "/*\n  zip_file_set_encryption.c -- set encryption for file in archive\n  Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nZIP_EXTERN int\nzip_file_set_encryption(zip_t *za, zip_uint64_t idx, zip_uint16_t method, const char *password) {\n    zip_entry_t *e;\n    char *our_password = NULL;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (method != ZIP_EM_NONE && _zip_get_encryption_implementation(method, ZIP_CODEC_ENCODE) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n\n    if (e->changes == NULL) {\n        if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n\n    if (password) {\n        if ((our_password = strdup(password)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n\n    e->changes->encryption_method = method;\n    e->changes->changed |= ZIP_DIRENT_ENCRYPTION_METHOD;\n    if (password) {\n        e->changes->password = our_password;\n        e->changes->changed |= ZIP_DIRENT_PASSWORD;\n    }\n    else {\n        if (e->changes->changed & ZIP_DIRENT_PASSWORD) {\n            _zip_crypto_clear(e->changes->password, strlen(e->changes->password));\n            free(e->changes->password);\n            e->changes->password = e->orig ? e->orig->password : NULL;\n            e->changes->changed &= ~ZIP_DIRENT_PASSWORD;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_set_external_attributes.c",
    "content": "/*\n  zip_file_set_external_attributes.c -- set external attributes for entry\n  Copyright (C) 2013-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\nZIP_EXTERN int\nzip_file_set_external_attributes(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t opsys, zip_uint32_t attributes) {\n    zip_entry_t *e;\n    int changed;\n    zip_uint8_t unchanged_opsys;\n    zip_uint32_t unchanged_attributes;\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL)\n        return -1;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n    unchanged_opsys = (e->orig ? (zip_uint8_t)(e->orig->version_madeby >> 8) : (zip_uint8_t)ZIP_OPSYS_DEFAULT);\n    unchanged_attributes = e->orig ? e->orig->ext_attrib : ZIP_EXT_ATTRIB_DEFAULT;\n\n    changed = (opsys != unchanged_opsys || attributes != unchanged_attributes);\n\n    if (changed) {\n        if (e->changes == NULL) {\n            if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n                zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n        }\n        e->changes->version_madeby = (zip_uint16_t)((opsys << 8) | (e->changes->version_madeby & 0xff));\n        e->changes->ext_attrib = attributes;\n        e->changes->changed |= ZIP_DIRENT_ATTRIBUTES;\n    }\n    else if (e->changes) {\n        e->changes->changed &= ~ZIP_DIRENT_ATTRIBUTES;\n        if (e->changes->changed == 0) {\n            _zip_dirent_free(e->changes);\n            e->changes = NULL;\n        }\n        else {\n            e->changes->version_madeby = (zip_uint16_t)((unchanged_opsys << 8) | (e->changes->version_madeby & 0xff));\n            e->changes->ext_attrib = unchanged_attributes;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_set_mtime.c",
    "content": "/*\n zip_file_set_mtime.c -- set modification time of entry.\n Copyright (C) 2014-2024 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include \"zipint.h\"\n\nstatic int zip_file_set_time(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags, time_t *mtime) {\n    zip_entry_t *e;\n\n    if (_zip_get_dirent(za, idx, 0, NULL) == NULL) {\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n    if (e->orig != NULL && e->orig->encryption_method == ZIP_EM_TRAD_PKWARE && !ZIP_ENTRY_CHANGED(e, ZIP_DIRENT_ENCRYPTION_METHOD) && !ZIP_ENTRY_DATA_CHANGED(e)) {\n        zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (e->changes == NULL) {\n        if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n\n    e->changes->last_mod.time = dtime;\n    e->changes->last_mod.date = ddate;\n    if (mtime != NULL) {\n        e->changes->last_mod_mtime = *mtime;\n        e->changes->last_mod_mtime_valid = true;\n    }\n    else {\n        e->changes->last_mod_mtime_valid = false;\n    }\n    e->changes->changed |= ZIP_DIRENT_LAST_MOD;\n\n    return 0;\n}\n\nZIP_EXTERN int zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags) {\n    return zip_file_set_time(za, idx, dtime, ddate, flags, NULL);\n}\n\n\nZIP_EXTERN int zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) {\n    zip_dostime_t dostime;\n\n    if (_zip_u2d_time(mtime, &dostime, &za->error) < 0) {\n        return -1;\n    }\n\n    return zip_file_set_time(za, idx, dostime.time, dostime.date, flags, &mtime);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_file_strerror.c",
    "content": "/*\n  zip_file_sterror.c -- get string representation of zip file error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_file_strerror(zip_file_t *zf) {\n    return zip_error_strerror(&zf->error);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fopen.c",
    "content": "/*\n  zip_fopen.c -- open file in zip archive for reading\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_file_t *\nzip_fopen(zip_t *za, const char *fname, zip_flags_t flags) {\n    zip_int64_t idx;\n\n    if ((idx = zip_name_locate(za, fname, flags)) < 0)\n        return NULL;\n\n    return zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, za->default_password);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fopen_encrypted.c",
    "content": "/*\n  zip_fopen_encrypted.c -- open file for reading with password\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_file_t *\nzip_fopen_encrypted(zip_t *za, const char *fname, zip_flags_t flags, const char *password) {\n    zip_int64_t idx;\n\n    if ((idx = zip_name_locate(za, fname, flags)) < 0)\n        return NULL;\n\n    return zip_fopen_index_encrypted(za, (zip_uint64_t)idx, flags, password);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fopen_index.c",
    "content": "/*\n  zip_fopen_index.c -- open file in zip archive for reading by index\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_file_t *\nzip_fopen_index(zip_t *za, zip_uint64_t index, zip_flags_t flags) {\n    return zip_fopen_index_encrypted(za, index, flags, za->default_password);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fopen_index_encrypted.c",
    "content": "/*\n  zip_fopen_index_encrypted.c -- open file for reading by index w/ password\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\nstatic zip_file_t *_zip_file_new(zip_t *za);\n\n\nZIP_EXTERN zip_file_t *\nzip_fopen_index_encrypted(zip_t *za, zip_uint64_t index, zip_flags_t flags, const char *password) {\n    zip_file_t *zf;\n    zip_source_t *src;\n\n    if (password != NULL && password[0] == '\\0') {\n        password = NULL;\n    }\n    \n    if ((src = zip_source_zip_file_create(za, index, flags, 0, -1, password, &za->error)) == NULL)\n        return NULL;\n\n    if (zip_source_open(src) < 0) {\n        zip_error_set_from_source(&za->error, src);\n        zip_source_free(src);\n        return NULL;\n    }\n\n    if ((zf = _zip_file_new(za)) == NULL) {\n        zip_source_free(src);\n        return NULL;\n    }\n\n    zf->src = src;\n\n    return zf;\n}\n\n\nstatic zip_file_t *\n_zip_file_new(zip_t *za) {\n    zip_file_t *zf;\n\n    if ((zf = (zip_file_t *)malloc(sizeof(struct zip_file))) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    zip_error_init(&zf->error);\n    zf->src = NULL;\n\n    return zf;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fread.c",
    "content": "/*\n  zip_fread.c -- read from file\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_fread(zip_file_t *zf, void *outbuf, zip_uint64_t toread) {\n    zip_int64_t n;\n\n    if (zf == NULL) {\n        return -1;\n    }\n\n    if (zf->error.zip_err != 0) {\n        return -1;\n    }\n\n    if (toread > ZIP_INT64_MAX) {\n        zip_error_set(&zf->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (toread == 0) {\n        return 0;\n    }\n\n    if ((n = zip_source_read(zf->src, outbuf, toread)) < 0) {\n        zip_error_set_from_source(&zf->error, zf->src);\n        return -1;\n    }\n\n    return n;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_fseek.c",
    "content": "/*\n  zip_fseek.c -- seek in file\n  Copyright (C) 2016-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\nZIP_EXTERN zip_int8_t\nzip_fseek(zip_file_t *zf, zip_int64_t offset, int whence) {\n    if (zf == NULL) {\n        return -1;\n    }\n\n    if (zf->error.zip_err != 0) {\n        return -1;\n    }\n\n    if (zip_source_seek(zf->src, offset, whence) < 0) {\n        zip_error_set_from_source(&zf->error, zf->src);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nZIP_EXTERN int\nzip_file_is_seekable(zip_file_t *zfile) {\n    if (zfile == NULL) {\n        return -1;\n    }\n    \n    return zip_source_is_seekable(zfile->src);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_ftell.c",
    "content": "/*\n  zip_ftell.c -- tell position in file\n  Copyright (C) 2016-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\nZIP_EXTERN zip_int64_t\nzip_ftell(zip_file_t *zf) {\n    zip_int64_t res;\n\n    if (zf == NULL) {\n        return -1;\n    }\n\n    if (zf->error.zip_err != 0) {\n        return -1;\n    }\n\n    res = zip_source_tell(zf->src);\n    if (res < 0) {\n        zip_error_set_from_source(&zf->error, zf->src);\n        return -1;\n    }\n\n    return res;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_archive_comment.c",
    "content": "/*\n  zip_get_archive_comment.c -- get archive comment\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_get_archive_comment(zip_t *za, int *lenp, zip_flags_t flags) {\n    zip_string_t *comment;\n    zip_uint32_t len;\n    const zip_uint8_t *str;\n\n    if ((flags & ZIP_FL_UNCHANGED) || (za->comment_changes == NULL))\n        comment = za->comment_orig;\n    else\n        comment = za->comment_changes;\n\n    if ((str = _zip_string_get(comment, &len, flags, &za->error)) == NULL)\n        return NULL;\n\n    if (lenp)\n        *lenp = (int)len;\n\n    return (const char *)str;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_archive_flag.c",
    "content": "/*\n  zip_get_archive_flag.c -- get archive global flag\n  Copyright (C) 2008-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_get_archive_flag(zip_t *za, zip_flags_t flag, zip_flags_t flags) {\n    unsigned int fl;\n\n    fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags;\n\n    return (fl & flag) ? 1 : 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_encryption_implementation.c",
    "content": "/*\n  zip_get_encryption_implementation.c -- get encryption implementation\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nzip_encryption_implementation\n_zip_get_encryption_implementation(zip_uint16_t em, int operation) {\n    switch (em) {\n    case ZIP_EM_TRAD_PKWARE:\n        return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode;\n\n#if defined(HAVE_CRYPTO)\n    case ZIP_EM_AES_128:\n    case ZIP_EM_AES_192:\n    case ZIP_EM_AES_256:\n        return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode;\n#endif\n\n    default:\n        return NULL;\n    }\n}\n\nZIP_EXTERN int\nzip_encryption_method_supported(zip_uint16_t method, int encode) {\n    if (method == ZIP_EM_NONE) {\n        return 1;\n    }\n    return _zip_get_encryption_implementation(method, encode ? ZIP_CODEC_ENCODE : ZIP_CODEC_DECODE) != NULL;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_file_comment.c",
    "content": "/*\n  zip_get_file_comment.c -- get file comment\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_get_file_comment(zip_t *za, zip_uint64_t idx, int *lenp, int flags) {\n    zip_uint32_t len;\n    const char *s;\n\n    if ((s = zip_file_get_comment(za, idx, &len, (zip_flags_t)flags)) != NULL) {\n        if (lenp)\n            *lenp = (int)len;\n    }\n\n    return s;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_name.c",
    "content": "/*\n  zip_get_name.c -- get filename for a file in zip file\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags) {\n    return _zip_get_name(za, idx, flags, &za->error);\n}\n\n\nconst char *\n_zip_get_name(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) {\n    zip_dirent_t *de;\n    const zip_uint8_t *str;\n\n    if ((de = _zip_get_dirent(za, idx, flags, error)) == NULL)\n        return NULL;\n\n    if ((str = _zip_string_get(de->filename, NULL, flags, error)) == NULL)\n        return NULL;\n\n    return (const char *)str;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_num_entries.c",
    "content": "/*\n  zip_get_num_entries.c -- get number of entries in archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_get_num_entries(zip_t *za, zip_flags_t flags) {\n    zip_uint64_t n;\n\n    if (za == NULL)\n        return -1;\n\n    if (flags & ZIP_FL_UNCHANGED) {\n        n = za->nentry;\n        while (n > 0 && za->entry[n - 1].orig == NULL)\n            --n;\n        return (zip_int64_t)n;\n    }\n    return (zip_int64_t)za->nentry;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_get_num_files.c",
    "content": "/*\n  zip_get_num_files.c -- get number of files in archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n#include <limits.h>\n\n\nZIP_EXTERN int\nzip_get_num_files(zip_t *za) {\n    if (za == NULL)\n        return -1;\n\n    if (za->nentry > INT_MAX) {\n        zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    return (int)za->nentry;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_hash.c",
    "content": "/*\n  zip_hash.c -- hash table string -> uint64\n  Copyright (C) 2015-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n#include <stdlib.h>\n#include <string.h>\n\n/* parameter for the string hash function */\n#define HASH_MULTIPLIER 33\n#define HASH_START 5381\n\n/* hash table's fill ratio is kept between these by doubling/halfing its size as necessary */\n#define HASH_MAX_FILL .75\n#define HASH_MIN_FILL .01\n\n/* but hash table size is kept between these */\n#define HASH_MIN_SIZE 256\n#define HASH_MAX_SIZE 0x80000000ul\n\nstruct zip_hash_entry {\n    const zip_uint8_t *name;\n    zip_int64_t orig_index;\n    zip_int64_t current_index;\n    struct zip_hash_entry *next;\n    zip_uint32_t hash_value;\n};\ntypedef struct zip_hash_entry zip_hash_entry_t;\n\nstruct zip_hash {\n    zip_uint32_t table_size;\n    zip_uint64_t nentries;\n    zip_hash_entry_t **table;\n};\n\n\n/* free list of entries */\nstatic void\nfree_list(zip_hash_entry_t *entry) {\n    while (entry != NULL) {\n        zip_hash_entry_t *next = entry->next;\n        free(entry);\n        entry = next;\n    }\n}\n\n\n/* compute hash of string, full 32 bit value */\nstatic zip_uint32_t\nhash_string(const zip_uint8_t *name) {\n    zip_uint64_t value = HASH_START;\n\n    if (name == NULL) {\n        return 0;\n    }\n\n    while (*name != 0) {\n        value = (zip_uint64_t)(((value * HASH_MULTIPLIER) + (zip_uint8_t)*name) % 0x100000000ul);\n        name++;\n    }\n\n    return (zip_uint32_t)value;\n}\n\n\n/* resize hash table; new_size must be a power of 2, can be larger or smaller than current size */\nstatic bool\nhash_resize(zip_hash_t *hash, zip_uint32_t new_size, zip_error_t *error) {\n    zip_hash_entry_t **new_table;\n\n    if (new_size == hash->table_size) {\n        return true;\n    }\n\n    if ((new_table = (zip_hash_entry_t **)calloc(new_size, sizeof(zip_hash_entry_t *))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return false;\n    }\n\n    if (hash->nentries > 0) {\n        zip_uint32_t i;\n\n        for (i = 0; i < hash->table_size; i++) {\n            zip_hash_entry_t *entry = hash->table[i];\n            while (entry) {\n                zip_hash_entry_t *next = entry->next;\n\n                zip_uint32_t new_index = entry->hash_value % new_size;\n\n                entry->next = new_table[new_index];\n                new_table[new_index] = entry;\n\n                entry = next;\n            }\n        }\n    }\n\n    free(hash->table);\n    hash->table = new_table;\n    hash->table_size = new_size;\n\n    return true;\n}\n\n\nstatic zip_uint32_t\nsize_for_capacity(zip_uint64_t capacity) {\n    double needed_size = capacity / HASH_MAX_FILL;\n    zip_uint32_t v;\n\n    if (needed_size > ZIP_UINT32_MAX) {\n        v = ZIP_UINT32_MAX;\n    }\n    else {\n        v = (zip_uint32_t)needed_size;\n    }\n\n    if (v > HASH_MAX_SIZE) {\n        return HASH_MAX_SIZE;\n    }\n\n    /* From Bit Twiddling Hacks by Sean Eron Anderson <seander@cs.stanford.edu>\n     (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2). */\n\n    v--;\n    v |= v >> 1;\n    v |= v >> 2;\n    v |= v >> 4;\n    v |= v >> 8;\n    v |= v >> 16;\n    v++;\n\n    return v;\n}\n\n\nzip_hash_t *\n_zip_hash_new(zip_error_t *error) {\n    zip_hash_t *hash;\n\n    if ((hash = (zip_hash_t *)malloc(sizeof(zip_hash_t))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    hash->table_size = 0;\n    hash->nentries = 0;\n    hash->table = NULL;\n\n    return hash;\n}\n\n\nvoid\n_zip_hash_free(zip_hash_t *hash) {\n    zip_uint32_t i;\n\n    if (hash == NULL) {\n        return;\n    }\n\n    if (hash->table != NULL) {\n        for (i = 0; i < hash->table_size; i++) {\n            if (hash->table[i] != NULL) {\n                free_list(hash->table[i]);\n            }\n        }\n        free(hash->table);\n    }\n    free(hash);\n}\n\n\n/* insert into hash, return error on existence or memory issues */\nbool\n_zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error) {\n    zip_uint32_t hash_value, table_index;\n    zip_hash_entry_t *entry;\n\n    if (hash == NULL || name == NULL || index > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n\n    if (hash->table_size == 0) {\n        if (!hash_resize(hash, HASH_MIN_SIZE, error)) {\n            return false;\n        }\n    }\n\n    hash_value = hash_string(name);\n    table_index = hash_value % hash->table_size;\n\n    for (entry = hash->table[table_index]; entry != NULL; entry = entry->next) {\n        if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) {\n            if (((flags & ZIP_FL_UNCHANGED) && entry->orig_index != -1) || entry->current_index != -1) {\n                zip_error_set(error, ZIP_ER_EXISTS, 0);\n                return false;\n            }\n            else {\n                break;\n            }\n        }\n    }\n\n    if (entry == NULL) {\n        if ((entry = (zip_hash_entry_t *)malloc(sizeof(zip_hash_entry_t))) == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            return false;\n        }\n        entry->name = name;\n        entry->next = hash->table[table_index];\n        hash->table[table_index] = entry;\n        entry->hash_value = hash_value;\n        entry->orig_index = -1;\n        hash->nentries++;\n        if (hash->nentries > hash->table_size * HASH_MAX_FILL && hash->table_size < HASH_MAX_SIZE) {\n            if (!hash_resize(hash, hash->table_size * 2, error)) {\n                return false;\n            }\n        }\n    }\n\n    if (flags & ZIP_FL_UNCHANGED) {\n        entry->orig_index = (zip_int64_t)index;\n    }\n    entry->current_index = (zip_int64_t)index;\n\n    return true;\n}\n\n\n/* remove entry from hash, error if not found */\nbool\n_zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *name, zip_error_t *error) {\n    zip_uint32_t hash_value, index;\n    zip_hash_entry_t *entry, *previous;\n\n    if (hash == NULL || name == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return false;\n    }\n\n    if (hash->nentries > 0) {\n        hash_value = hash_string(name);\n        index = hash_value % hash->table_size;\n        previous = NULL;\n        entry = hash->table[index];\n        while (entry) {\n            if (entry->hash_value == hash_value && strcmp((const char *)name, (const char *)entry->name) == 0) {\n                if (entry->orig_index == -1) {\n                    if (previous) {\n                        previous->next = entry->next;\n                    }\n                    else {\n                        hash->table[index] = entry->next;\n                    }\n                    free(entry);\n                    hash->nentries--;\n                    if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) {\n                        if (!hash_resize(hash, hash->table_size / 2, error)) {\n                            return false;\n                        }\n                    }\n                }\n                else {\n                    entry->current_index = -1;\n                }\n                return true;\n            }\n            previous = entry;\n            entry = entry->next;\n        }\n    }\n\n    zip_error_set(error, ZIP_ER_NOENT, 0);\n    return false;\n}\n\n\n/* find value for entry in hash, -1 if not found */\nzip_int64_t\n_zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error) {\n    zip_uint32_t hash_value, index;\n    zip_hash_entry_t *entry;\n\n    if (hash == NULL || name == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (hash->nentries > 0) {\n        hash_value = hash_string(name);\n        index = hash_value % hash->table_size;\n        for (entry = hash->table[index]; entry != NULL; entry = entry->next) {\n            if (strcmp((const char *)name, (const char *)entry->name) == 0) {\n                if (flags & ZIP_FL_UNCHANGED) {\n                    if (entry->orig_index != -1) {\n                        return entry->orig_index;\n                    }\n                }\n                else {\n                    if (entry->current_index != -1) {\n                        return entry->current_index;\n                    }\n                }\n                break;\n            }\n        }\n    }\n\n    zip_error_set(error, ZIP_ER_NOENT, 0);\n    return -1;\n}\n\n\nbool\n_zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error) {\n    zip_uint32_t new_size;\n\n    if (capacity == 0) {\n        return true;\n    }\n\n    new_size = size_for_capacity(capacity);\n\n    if (new_size <= hash->table_size) {\n        return true;\n    }\n\n    if (!hash_resize(hash, new_size, error)) {\n        return false;\n    }\n\n    return true;\n}\n\n\nbool\n_zip_hash_revert(zip_hash_t *hash, zip_error_t *error) {\n    zip_uint32_t i;\n    zip_hash_entry_t *entry, *previous;\n\n    for (i = 0; i < hash->table_size; i++) {\n        previous = NULL;\n        entry = hash->table[i];\n        while (entry) {\n            if (entry->orig_index == -1) {\n                zip_hash_entry_t *p;\n                if (previous) {\n                    previous->next = entry->next;\n                }\n                else {\n                    hash->table[i] = entry->next;\n                }\n                p = entry;\n                entry = entry->next;\n                /* previous does not change */\n                free(p);\n                hash->nentries--;\n            }\n            else {\n                entry->current_index = entry->orig_index;\n                previous = entry;\n                entry = entry->next;\n            }\n        }\n    }\n\n    if (hash->nentries < hash->table_size * HASH_MIN_FILL && hash->table_size > HASH_MIN_SIZE) {\n        zip_uint32_t new_size = hash->table_size / 2;\n        while (hash->nentries < new_size * HASH_MIN_FILL && new_size > HASH_MIN_SIZE) {\n            new_size /= 2;\n        }\n        if (!hash_resize(hash, new_size, error)) {\n            return false;\n        }\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_io_util.c",
    "content": "/*\n zip_io_util.c -- I/O helper functions\n Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <limits.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\nint\n_zip_read(zip_source_t *src, zip_uint8_t *b, zip_uint64_t length, zip_error_t *error) {\n    zip_int64_t n;\n\n    if (length > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    if ((n = zip_source_read(src, b, length)) < 0) {\n        zip_error_set_from_source(error, src);\n        return -1;\n    }\n\n    if (n < (zip_int64_t)length) {\n        zip_error_set(error, ZIP_ER_EOF, 0);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nzip_uint8_t *\n_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error) {\n    zip_uint8_t *r;\n\n    if (length == 0 && !nulp) {\n        return NULL;\n    }\n\n    r = (zip_uint8_t *)malloc(length + (nulp ? 1 : 0));\n    if (r == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (buffer) {\n        zip_uint8_t *data = _zip_buffer_get(buffer, length);\n\n        if (data == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            free(r);\n            return NULL;\n        }\n        (void)memcpy_s(r, length, data, length);\n    }\n    else {\n        if (_zip_read(src, r, length, error) < 0) {\n            free(r);\n            return NULL;\n        }\n    }\n\n    if (nulp) {\n        zip_uint8_t *o;\n        /* replace any in-string NUL characters with spaces */\n        r[length] = 0;\n        for (o = r; o < r + length; o++)\n            if (*o == '\\0')\n                *o = ' ';\n    }\n\n    return r;\n}\n\n\nzip_string_t *\n_zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t len, bool nulp, zip_error_t *error) {\n    zip_uint8_t *raw;\n    zip_string_t *s;\n\n    if ((raw = _zip_read_data(buffer, src, len, nulp, error)) == NULL)\n        return NULL;\n\n    s = _zip_string_new(raw, len, ZIP_FL_ENC_GUESS, error);\n    free(raw);\n    return s;\n}\n\n\nint\n_zip_write(zip_t *za, const void *data, zip_uint64_t length) {\n    zip_int64_t n;\n\n    if ((n = zip_source_write(za->src, data, length)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return -1;\n    }\n    if ((zip_uint64_t)n != length) {\n        zip_error_set(&za->error, ZIP_ER_WRITE, EINTR);\n        return -1;\n    }\n\n    if (za->write_crc != NULL) {\n        zip_uint64_t position = 0;\n        while (position < length) {\n            zip_uint64_t nn = ZIP_MIN(UINT_MAX, length - position);\n\n            *za->write_crc = (zip_uint32_t)crc32(*za->write_crc, (const Bytef *)data + position, (uInt)nn);\n            position += nn;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_libzip_version.c",
    "content": "/*\n  zip_libzip_version.c -- return run-time version of library\n  Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_libzip_version(void) {\n    return LIBZIP_VERSION;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_memdup.c",
    "content": "/*\n  zip_memdup.c -- internal zip function, \"strdup\" with len\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nvoid *\n_zip_memdup(const void *mem, size_t len, zip_error_t *error) {\n    void *ret;\n\n    if (len == 0)\n        return NULL;\n\n    ret = malloc(len);\n    if (ret == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    (void)memcpy_s(ret, len, mem, len);\n\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_name_locate.c",
    "content": "/*\n  zip_name_locate.c -- get index by name\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <string.h>\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_name_locate(zip_t *za, const char *fname, zip_flags_t flags) {\n    return _zip_name_locate(za, fname, flags, &za->error);\n}\n\n\nzip_int64_t\n_zip_name_locate(zip_t *za, const char *fname, zip_flags_t flags, zip_error_t *error) {\n    int (*cmp)(const char *, const char *);\n    size_t fname_length;\n    zip_string_t *str = NULL;\n    const char *fn, *p;\n    zip_uint64_t i;\n\n    if (za == NULL) {\n        return -1;\n    }\n\n    if (fname == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    fname_length = strlen(fname);\n\n    if (fname_length > ZIP_UINT16_MAX) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if ((flags & (ZIP_FL_ENC_UTF_8 | ZIP_FL_ENC_RAW)) == 0 && fname[0] != '\\0') {\n        if ((str = _zip_string_new((const zip_uint8_t *)fname, (zip_uint16_t)strlen(fname), flags, error)) == NULL) {\n            return -1;\n        }\n        if ((fname = (const char *)_zip_string_get(str, NULL, 0, error)) == NULL) {\n            _zip_string_free(str);\n            return -1;\n        }\n    }\n\n    if (flags & (ZIP_FL_NOCASE | ZIP_FL_NODIR | ZIP_FL_ENC_RAW | ZIP_FL_ENC_STRICT)) {\n        /* can't use hash table */\n        cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp;\n\n        for (i = 0; i < za->nentry; i++) {\n            fn = _zip_get_name(za, i, flags, error);\n\n            /* newly added (partially filled) entry or error */\n            if (fn == NULL)\n                continue;\n\n            if (flags & ZIP_FL_NODIR) {\n                p = strrchr(fn, '/');\n                if (p)\n                    fn = p + 1;\n            }\n\n            if (cmp(fname, fn) == 0) {\n                _zip_error_clear(error);\n                _zip_string_free(str);\n                return (zip_int64_t)i;\n            }\n        }\n\n        zip_error_set(error, ZIP_ER_NOENT, 0);\n        _zip_string_free(str);\n        return -1;\n    }\n    else {\n        zip_int64_t ret = _zip_hash_lookup(za->names, (const zip_uint8_t *)fname, flags, error);\n        _zip_string_free(str);\n        return ret;\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_new.c",
    "content": "/*\n  zip_new.c -- create and init struct zip\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\n/* _zip_new:\n   creates a new zipfile struct, and sets the contents to zero; returns\n   the new struct. */\n\nzip_t *\n_zip_new(zip_error_t *error) {\n    zip_t *za;\n\n    za = (zip_t *)malloc(sizeof(struct zip));\n    if (za == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((za->names = _zip_hash_new(error)) == NULL) {\n        free(za);\n        return NULL;\n    }\n\n    za->src = NULL;\n    za->open_flags = 0;\n    zip_error_init(&za->error);\n    za->flags = za->ch_flags = 0;\n    za->default_password = NULL;\n    za->comment_orig = za->comment_changes = NULL;\n    za->comment_changed = 0;\n    za->nentry = za->nentry_alloc = 0;\n    za->entry = NULL;\n    za->nopen_source = za->nopen_source_alloc = 0;\n    za->open_source = NULL;\n    za->progress = NULL;\n    za->torrent_mtime = 0;\n\n    return za;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_open.c",
    "content": "/*\n  zip_open.c -- open zip archive by name\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\ntypedef enum {\n    EXISTS_ERROR = -1,\n    EXISTS_NOT = 0,\n    EXISTS_OK\n} exists_t;\ntypedef enum {\n    CDIR_OK,\n    CDIR_INVALID,\n    CDIR_NOT_FOUND\n\n} cdir_status_t;\n\nstatic bool check_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error);\nstatic bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic);\nstatic zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);\nstatic zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);\nstatic void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir);\nstatic zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);\nstatic exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error);\nstatic int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *);\nstatic bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error);\nstatic zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error);\nstatic cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);\nstatic const unsigned char *find_eocd(zip_buffer_t *buffer, const unsigned char *last);\n\n\nZIP_EXTERN zip_t *\nzip_open(const char *fn, int _flags, int *zep) {\n    zip_t *za;\n    zip_source_t *src;\n    struct zip_error error;\n\n    zip_error_init(&error);\n    if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) {\n        _zip_set_open_error(zep, &error, 0);\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {\n        zip_source_free(src);\n        _zip_set_open_error(zep, &error, 0);\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    zip_error_fini(&error);\n    return za;\n}\n\n\nZIP_EXTERN zip_t *\nzip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) {\n    unsigned int flags;\n    zip_int64_t supported;\n    exists_t exists;\n\n    if (_flags < 0 || src == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    flags = (unsigned int)_flags;\n\n    supported = zip_source_supports(src);\n    if ((supported & ZIP_SOURCE_SUPPORTS_SEEKABLE) != ZIP_SOURCE_SUPPORTS_SEEKABLE) {\n        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);\n        return NULL;\n    }\n    if ((supported & ZIP_SOURCE_SUPPORTS_WRITABLE) != ZIP_SOURCE_SUPPORTS_WRITABLE) {\n        flags |= ZIP_RDONLY;\n    }\n\n    if ((flags & (ZIP_RDONLY | ZIP_TRUNCATE)) == (ZIP_RDONLY | ZIP_TRUNCATE)) {\n        zip_error_set(error, ZIP_ER_RDONLY, 0);\n        return NULL;\n    }\n\n    exists = _zip_file_exists(src, error);\n    switch (exists) {\n    case EXISTS_ERROR:\n        return NULL;\n\n    case EXISTS_NOT:\n        if ((flags & ZIP_CREATE) == 0) {\n            zip_error_set(error, ZIP_ER_NOENT, 0);\n            return NULL;\n        }\n        return _zip_allocate_new(src, flags, error);\n\n    default: {\n        zip_t *za;\n        if (flags & ZIP_EXCL) {\n            zip_error_set(error, ZIP_ER_EXISTS, 0);\n            return NULL;\n        }\n        if (zip_source_open(src) < 0) {\n            zip_error_set_from_source(error, src);\n            return NULL;\n        }\n\n        if (flags & ZIP_TRUNCATE) {\n            za = _zip_allocate_new(src, flags, error);\n        }\n        else {\n            /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */\n            za = _zip_open(src, flags, error);\n        }\n\n        if (za == NULL) {\n            zip_source_close(src);\n            return NULL;\n        }\n        return za;\n    }\n    }\n}\n\n\nstatic bool\n_is_truncated_zip(zip_source_t *src) {\n    unsigned char data[4];\n    /* check if the source is a truncated zip archive: true if yes, no\n       if not or can't be determined */\n    if (zip_source_seek(src, 0, SEEK_SET) < 0) {\n        return false;\n    }\n\n    if (zip_source_read(src, data, 4) != 4) {\n        return false;\n    }\n\n    if (memcmp(data, LOCAL_MAGIC, 4) == 0) {\n        /* file starts with a ZIP local header signature */\n        return true;\n    }\n    return false;\n}\n\n\nzip_t *\n_zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) {\n    zip_t *za;\n    zip_cdir_t *cdir;\n    struct zip_stat st;\n    zip_uint64_t len, idx;\n\n    zip_stat_init(&st);\n    if (zip_source_stat(src, &st) < 0) {\n        zip_error_set_from_source(error, src);\n        return NULL;\n    }\n    if ((st.valid & ZIP_STAT_SIZE) == 0) {\n        zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);\n        return NULL;\n    }\n    len = st.size;\n\n\n    if ((za = _zip_allocate_new(src, flags, error)) == NULL) {\n        return NULL;\n    }\n\n    /* treat empty files as empty archives */\n    if (len == 0 && zip_source_accept_empty(src)) {\n        return za;\n    }\n\n    if ((cdir = _zip_find_central_dir(za, len)) == NULL) {\n        _zip_error_copy(error, &za->error);\n        if (zip_error_code_zip(&za->error) == ZIP_ER_NOZIP) {\n            /* not a zip - find out if it's truncated */\n            if (_is_truncated_zip(src)) {\n                zip_error_set(error, ZIP_ER_TRUNCATED_ZIP, 0);\n            }\n        }\n        /* keep src so discard does not get rid of it */\n        zip_source_keep(src);\n        zip_discard(za);\n        return NULL;\n    }\n\n    za->entry = cdir->entry;\n    za->nentry = cdir->nentry;\n    za->nentry_alloc = cdir->nentry_alloc;\n\n    zip_check_torrentzip(za, cdir);\n\n    if (ZIP_IS_TORRENTZIP(za)) {\n        /* Torrentzip uses the archive comment to detect changes by tools that are not torrentzip aware. */\n        _zip_string_free(cdir->comment);\n    }\n    else {\n        za->comment_orig = cdir->comment;\n    }\n\n    free(cdir);\n\n    _zip_hash_reserve_capacity(za->names, za->nentry, &za->error);\n\n    for (idx = 0; idx < za->nentry; idx++) {\n        const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);\n        if (name == NULL) {\n            /* keep src so discard does not get rid of it */\n            zip_source_keep(src);\n            zip_discard(za);\n            return NULL;\n        }\n\n        if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {\n            if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {\n                _zip_error_copy(error, &za->error);\n                /* keep src so discard does not get rid of it */\n                zip_source_keep(src);\n                zip_discard(za);\n                return NULL;\n            }\n        }\n    }\n\n    za->ch_flags = za->flags;\n\n    return za;\n}\n\n\nvoid\n_zip_set_open_error(int *zep, const zip_error_t *err, int ze) {\n    if (err) {\n        ze = zip_error_code_zip(err);\n        switch (zip_error_system_type(err)) {\n        case ZIP_ET_SYS:\n        case ZIP_ET_LIBZIP:\n            errno = zip_error_code_system(err);\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    if (zep)\n        *zep = ze;\n}\n\n\n/* _zip_readcdir:\n   tries to find a valid end-of-central-directory at the beginning of\n   buf, and then the corresponding central directory entries.\n   Returns a struct zip_cdir which contains the central directory\n   entries, or NULL if unsuccessful. */\n\nstatic bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error) {\n    zip_cdir_t *cd;\n    zip_uint16_t comment_len;\n    zip_uint64_t i, left;\n    zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);\n    zip_buffer_t *cd_buffer;\n    bool eocd64_found = false;\n\n    *cdirp = NULL;\n\n    if ((cd = _zip_read_eocd(buffer, buf_offset, error)) == NULL) {\n        return false;\n    }\n\n    if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {\n        eocd64_found = true;\n        _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);\n        switch (_zip_read_eocd64(cd, za->src, buffer, buf_offset, za->flags, error)) {\n        case CDIR_OK:\n            break;\n\n        case CDIR_INVALID:\n            _zip_cdir_free(cd);\n            return true;\n\n        case CDIR_NOT_FOUND:\n            _zip_cdir_free(cd);\n            return false;\n        }\n    }\n\n    if ((cd->eocd_disk != 0 || cd->this_disk != 0) && !eocd64_found && cd->eocd_disk != cd->this_disk) {\n        /* If the central directory doesn't start on this disk, we can't check that offset is valid. Check as much as we can instead. */\n        if (cd->this_disk < cd->eocd_disk) {\n            /* Disks before the start of the central directory don't contain an EOCD. */\n            _zip_cdir_free(cd);\n            return false;\n        }\n        if (cd->size <= cd->eocd_offset) {\n            /* The complete central directory would fit on this disk. */\n            _zip_cdir_free(cd);\n            return false;\n        }\n    }\n\n    if (!eocd64_found) {\n        if (cd->this_disk == 0 && cd->eocd_disk == 0 && cd->eocd_offset == 0 && cd->offset == 0 && cd->num_entries == 0) {\n            /* An empty archive doesn't contain central directory entries. */\n        }\n        else if (!check_magic(cd->offset, buffer, buf_offset, za->src, CENTRAL_MAGIC)) {\n            _zip_cdir_free(cd);\n            return false;\n        }\n    }\n\n    /* We accept this EOCD as valid and won't search for an earlier one if it is unusable. */\n\n    if (!check_eocd(cd, za->flags, error)) {\n        _zip_cdir_free(cd);\n        return true;\n    }\n\n    _zip_buffer_set_offset(buffer, eocd_offset + 20);\n    comment_len = _zip_buffer_get_16(buffer);\n\n    if (cd->offset + cd->size > buf_offset + eocd_offset) {\n        /* cdir spans past EOCD record */\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD);\n        _zip_cdir_free(cd);\n        return true;\n    }\n\n    if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {\n        zip_uint64_t tail_len;\n\n        _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);\n        tail_len = _zip_buffer_left(buffer);\n\n        if (tail_len != comment_len) {\n            if (za->open_flags & ZIP_CHECKCONS) {\n                zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID);\n                _zip_cdir_free(cd);\n                return true;\n            }\n            if (tail_len < comment_len) {\n                comment_len = tail_len;\n            }\n        }\n\n        if (comment_len) {\n            if ((cd->comment = _zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {\n                _zip_cdir_free(cd);\n                return true;\n            }\n        }\n    }\n\n    if (cd->offset >= buf_offset) {\n        zip_uint8_t *data;\n        /* if buffer already read in, use it */\n        _zip_buffer_set_offset(buffer, cd->offset - buf_offset);\n\n        if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);\n            _zip_cdir_free(cd);\n            return true;\n        }\n        if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            _zip_cdir_free(cd);\n            return true;\n        }\n    }\n    else {\n        cd_buffer = NULL;\n\n        if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {\n            zip_error_set_from_source(error, za->src);\n            _zip_cdir_free(cd);\n            return true;\n        }\n\n        /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */\n        if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {\n            zip_error_set(error, ZIP_ER_NOZIP, 0);\n            _zip_cdir_free(cd);\n            return true;\n        }\n    }\n\n    if (!_zip_cdir_grow(cd, cd->num_entries, error)) {\n        _zip_cdir_free(cd);\n        _zip_buffer_free(cd_buffer);\n        return true;\n    }\n    left = (zip_uint64_t)cd->size;\n    i = 0;\n    while (left > 0) {\n        bool grown = false;\n        zip_int64_t entry_size;\n\n        if (i == cd->nentry) {\n            /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */\n            /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */\n\n            if (cd->is_zip64 || left < CDENTRYSIZE) {\n                break;\n            }\n\n            if (!_zip_cdir_grow(cd, 0x10000, error)) {\n                _zip_cdir_free(cd);\n                _zip_buffer_free(cd_buffer);\n                return true;\n            }\n            grown = true;\n        }\n\n        if ((cd->entry[i].orig = _zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, 0, za->open_flags & ZIP_CHECKCONS, error)) < 0) {\n            if (zip_error_code_zip(error) == ZIP_ER_INCONS) {\n                zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i));\n            }\n            else if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) {\n                zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, i));\n            }\n            _zip_cdir_free(cd);\n            _zip_buffer_free(cd_buffer);\n            return true;\n        }\n        i++;\n        left -= (zip_uint64_t)entry_size;\n    }\n\n    /* If we didn't fill all we grew, cd->num_entries was wrong. */\n    if (i != cd->nentry || left > 0) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT);\n        _zip_buffer_free(cd_buffer);\n        _zip_cdir_free(cd);\n        return true;\n    }\n\n    if (za->open_flags & ZIP_CHECKCONS) {\n        bool ok;\n\n        if (cd_buffer) {\n            ok = _zip_buffer_eof(cd_buffer);\n        }\n        else {\n            zip_int64_t offset = zip_source_tell(za->src);\n\n            if (offset < 0) {\n                zip_error_set_from_source(error, za->src);\n                _zip_cdir_free(cd);\n                return true;\n            }\n            ok = ((zip_uint64_t)offset == cd->offset + cd->size);\n        }\n\n        if (!ok) {\n            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);\n            _zip_buffer_free(cd_buffer);\n            _zip_cdir_free(cd);\n            return true;\n        }\n    }\n\n    _zip_buffer_free(cd_buffer);\n    *cdirp = cd;\n    return true;\n}\n\n\nstatic bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic) {\n    if (buffer_offset <= offset) {\n        zip_uint8_t* data;\n        if (_zip_buffer_set_offset(buffer, offset - buffer_offset) < 0 || (data = _zip_buffer_get(buffer, MAGIC_LEN)) == NULL) {\n            return false;\n        }\n        return memcmp(data, magic, MAGIC_LEN) == 0;\n    }\n    else {\n        zip_uint8_t data[MAGIC_LEN];\n\n        if (zip_source_seek(src, offset, SEEK_SET) < 0 || zip_source_read(src, data, MAGIC_LEN) != MAGIC_LEN) {\n            return false;\n        }\n        return memcmp(data, magic, MAGIC_LEN) == 0;\n    }\n}\n\n\n/* _zip_checkcons:\n   Checks the consistency of the central directory by comparing central\n   directory entries with local headers and checking for plausible\n   file and header offsets. Returns -1 if not plausible, else the\n   difference between the lowest and the highest fileposition reached */\n\nstatic zip_int64_t\n_zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error) {\n    zip_uint64_t i;\n    zip_uint64_t min, max, j;\n    struct zip_dirent temp;\n    int detail;\n\n    _zip_dirent_init(&temp);\n    if (cd->nentry) {\n        max = cd->entry[0].orig->offset;\n        min = cd->entry[0].orig->offset;\n    }\n    else\n        min = max = 0;\n\n    for (i = 0; i < cd->nentry; i++) {\n        if (cd->entry[i].orig->offset < min)\n            min = cd->entry[i].orig->offset;\n        if (min > (zip_uint64_t)cd->offset) {\n            zip_error_set(error, ZIP_ER_NOZIP, 0);\n            return -1;\n        }\n\n        j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;\n        if (j > max)\n            max = j;\n        if (max > (zip_uint64_t)cd->offset) {\n            zip_error_set(error, ZIP_ER_NOZIP, 0);\n            return -1;\n        }\n\n        if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {\n            zip_error_set_from_source(error, za->src);\n            return -1;\n        }\n\n        if (_zip_dirent_read(&temp, za->src, NULL, true, cd->entry[i].orig->comp_size, true, error) == -1) {\n            if (zip_error_code_zip(error) == ZIP_ER_INCONS) {\n                zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i));\n            }\n            _zip_dirent_finalize(&temp);\n            return -1;\n        }\n\n        if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {\n            zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH, i));\n            _zip_dirent_finalize(&temp);\n            return -1;\n        }\n\n        cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);\n        cd->entry[i].orig->local_extra_fields_read = 1;\n        temp.extra_fields = NULL;\n\n        _zip_dirent_finalize(&temp);\n\n        if ((detail = zip_dirent_check_consistency(cd->entry[i].orig)) != 0) {\n            zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(detail, i));\n            return -1;\n        }\n    }\n\n    return (max - min) < ZIP_INT64_MAX ? (zip_int64_t)(max - min) : ZIP_INT64_MAX;\n}\n\n\n/* _zip_headercomp:\n   compares a central directory entry and a local file header\n   Return 0 if they are consistent, -1 if not. */\n\nstatic int\n_zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local) {\n    if ((central->version_needed < local->version_needed)\n#if 0\n\t/* some zip-files have different values in local\n\t   and global headers for the bitflags */\n\t|| (central->bitflags != local->bitflags)\n#endif\n        || (central->comp_method != local->comp_method) || (central->last_mod.time != local->last_mod.time) || (central->last_mod.date != local->last_mod.date) || !_zip_string_equal(central->filename, local->filename))\n        return -1;\n\n    if ((central->crc != local->crc) || (central->comp_size != local->comp_size) || (central->uncomp_size != local->uncomp_size)) {\n        /* InfoZip stores valid values in local header even when data descriptor is used.\n           This is in violation of the appnote.\n           macOS Archive sets the compressed size even when data descriptor is used ( but not the others),\n           also in violation of the appnote.\n        */\n        /* if data descriptor is not used, the values must match */\n        if ((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0) {\n            return -1;\n        }\n        /* when using a data descriptor, the local header value must be zero or match */\n        if ((local->crc != 0 && central->crc != local->crc) || (local->comp_size != 0 && central->comp_size != local->comp_size) || (local->uncomp_size != 0 && central->uncomp_size != local->uncomp_size)) {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n\nstatic zip_t *\n_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error) {\n    zip_t *za;\n\n    if ((za = _zip_new(error)) == NULL) {\n        return NULL;\n    }\n\n    za->src = src;\n    za->open_flags = flags;\n    za->flags = 0;\n    za->ch_flags = 0;\n    za->write_crc = NULL;\n\n    if (flags & ZIP_RDONLY) {\n        za->flags |= ZIP_AFL_RDONLY;\n        za->ch_flags |= ZIP_AFL_RDONLY;\n    }\n\n    return za;\n}\n\n\n/*\n * tests for file existence\n */\nstatic exists_t\n_zip_file_exists(zip_source_t *src, zip_error_t *error) {\n    struct zip_stat st;\n\n    zip_stat_init(&st);\n    if (zip_source_stat(src, &st) != 0) {\n        zip_error_t *src_error = zip_source_error(src);\n        if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {\n            return EXISTS_NOT;\n        }\n        _zip_error_copy(error, src_error);\n        return EXISTS_ERROR;\n    }\n\n    return EXISTS_OK;\n}\n\n\nstatic zip_cdir_t *\n_zip_find_central_dir(zip_t *za, zip_uint64_t len) {\n    zip_cdir_t *cdir;\n    const zip_uint8_t *match;\n    zip_int64_t buf_offset;\n    zip_uint64_t buflen;\n    zip_error_t error;\n    zip_buffer_t *buffer;\n\n    if (len < EOCDLEN) {\n        zip_error_set(&za->error, ZIP_ER_NOZIP, 0);\n        return NULL;\n    }\n\n    buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);\n    if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {\n        zip_error_t *src_error = zip_source_error(za->src);\n        if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {\n            /* seek before start of file on my machine */\n            _zip_error_copy(&za->error, src_error);\n            return NULL;\n        }\n    }\n    if ((buf_offset = zip_source_tell(za->src)) < 0) {\n        zip_error_set_from_source(&za->error, za->src);\n        return NULL;\n    }\n\n    if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {\n        return NULL;\n    }\n\n    cdir = NULL;\n    if (buflen >= CDBUFSIZE) {\n        /* EOCD64 locator is before EOCD, so leave place for it */\n        _zip_buffer_set_offset(buffer, EOCD64LOCLEN);\n    }\n    zip_error_set(&error, ZIP_ER_NOZIP, 0);\n\n    match = NULL;\n    while ((match = find_eocd(buffer, match)) != NULL) {\n        _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));\n        if (_zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &cdir, &error)) {\n            if (cdir != NULL && (za->open_flags & ZIP_CHECKCONS) && _zip_checkcons(za, cdir, &error) < 0) {\n                _zip_cdir_free(cdir);\n                cdir = NULL;\n            }\n            break;\n        }\n    }\n\n    _zip_buffer_free(buffer);\n\n    if (cdir == NULL) {\n        _zip_error_copy(&za->error, &error);\n    }\n    return cdir;\n}\n\n\nstatic const unsigned char *\nfind_eocd(zip_buffer_t *buffer, const unsigned char *last) {\n    const unsigned char *data = _zip_buffer_data(buffer);\n    const unsigned char *p;\n\n    if (last == NULL) {\n        last = data + _zip_buffer_size(buffer) - MAGIC_LEN;\n    }\n    else if (last == _zip_buffer_data(buffer)) {\n        return NULL;\n    }\n    else {\n        last -= 1;\n    }\n\n    for (p = last; p >= data; p -= 1) {\n        if (*p == EOCD_MAGIC[0]) {\n            if (memcmp(p, EOCD_MAGIC, MAGIC_LEN) == 0) {\n                return p;\n            }\n        }\n    }\n\n    return NULL;\n}\n\n\nstatic zip_cdir_t *\n_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error) {\n    zip_cdir_t *cd;\n\n    if (_zip_buffer_left(buffer) < EOCDLEN) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD_LENGTH_INVALID);\n        return NULL;\n    }\n\n    if ((cd = _zip_cdir_new(error)) == NULL) {\n        return NULL;\n    }\n\n    cd->eocd_offset = buf_offset + _zip_buffer_offset(buffer);\n    /* This function is only called where EOCD magic was found, so no need to check that here. */\n    _zip_buffer_skip(buffer, MAGIC_LEN);\n    cd->is_zip64 = false;\n    cd->this_disk = _zip_buffer_get_16(buffer);\n    cd->eocd_disk = _zip_buffer_get_16(buffer);\n\n    /* number of cdir-entries on this disk */\n    cd->disk_entries = _zip_buffer_get_16(buffer);\n    /* number of cdir-entries */\n    cd->num_entries = _zip_buffer_get_16(buffer);\n    cd->size = _zip_buffer_get_32(buffer);\n    cd->offset = _zip_buffer_get_32(buffer);\n\n    return cd;\n}\n\nstatic bool\ncheck_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error) {\n    if (cd->disk_entries != cd->num_entries || cd->this_disk != 0 || cd->eocd_disk != 0) {\n        zip_error_set(error, ZIP_ER_MULTIDISK, 0);\n        return false;\n    }\n\n    if (cd->offset + cd->size < cd->offset) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return false;\n    }\n    if ((flags & ZIP_CHECKCONS) && cd->offset + cd->size != cd->eocd_offset) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);\n        return false;\n    }\n\n    return true;\n}\n\n\ncdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) {\n    zip_uint64_t offset;\n    zip_uint8_t eocd[EOCD64LEN];\n    zip_uint64_t eocd_offset;\n    zip_uint64_t size, nentry, i, eocdloc_offset;\n    bool free_buffer;\n    zip_uint32_t num_disks, eocd_disk, this_disk;\n\n    eocdloc_offset = _zip_buffer_offset(buffer);\n\n    _zip_buffer_get(buffer, 4); /* magic already verified */\n\n    eocd_disk = _zip_buffer_get_32(buffer);\n    eocd_offset = _zip_buffer_get_64(buffer);\n    num_disks = _zip_buffer_get_32(buffer);\n\n    if (!check_magic(eocd_offset, buffer, buf_offset, src, EOCD64_MAGIC)) {\n        return CDIR_NOT_FOUND;\n    }\n\n    if (num_disks != 1) {\n        zip_error_set(error, ZIP_ER_MULTIDISK, 0);\n        return CDIR_INVALID;\n    }\n\n    /* valid seek value for start of EOCD */\n    if (eocd_offset > ZIP_INT64_MAX) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return CDIR_INVALID;\n    }\n\n    /* does EOCD fit before EOCD locator? */\n    if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD);\n        return CDIR_INVALID;\n    }\n\n    /* make sure current position of buffer is beginning of EOCD */\n    if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {\n        _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);\n        free_buffer = false;\n    }\n    else {\n        if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {\n            zip_error_set_from_source(error, src);\n            return CDIR_INVALID;\n        }\n        if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {\n            return CDIR_INVALID;\n        }\n        free_buffer = true;\n    }\n\n    if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC);\n        if (free_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return CDIR_INVALID;\n    }\n\n    /* size of EOCD */\n    size = _zip_buffer_get_64(buffer);\n\n    /* is there a hole between EOCD and EOCD locator, or do they overlap? */\n    if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD);\n        if (free_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return CDIR_INVALID;\n    }\n\n    _zip_buffer_get(buffer, 4); /* skip version made by/needed */\n\n    this_disk = _zip_buffer_get_32(buffer);\n    if (_zip_buffer_get_32(buffer) != eocd_disk) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_LOCATOR_MISMATCH);\n        if (free_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return CDIR_INVALID;\n    }\n\n    i = _zip_buffer_get_64(buffer);\n    nentry = _zip_buffer_get_64(buffer);\n\n    if (nentry != i) {\n        zip_error_set(error, ZIP_ER_MULTIDISK, 0);\n        if (free_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return CDIR_INVALID;\n    }\n\n    size = _zip_buffer_get_64(buffer);\n    offset = _zip_buffer_get_64(buffer);\n\n    /* did we read past the end of the buffer? */\n    if (!_zip_buffer_ok(buffer)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        if (free_buffer) {\n            _zip_buffer_free(buffer);\n        }\n        return CDIR_INVALID;\n    }\n\n    if (free_buffer) {\n        _zip_buffer_free(buffer);\n    }\n\n    if (offset > ZIP_INT64_MAX || offset + size < offset) {\n        zip_error_set(error, ZIP_ER_SEEK, EFBIG);\n        return CDIR_INVALID;\n    }\n\n    if (nentry > size / CDENTRYSIZE) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_INVALID);\n        return CDIR_INVALID;\n    }\n\n    if ((cdir->size != 0xffffffff && cdir->size != size) || (cdir->offset != 0xffffffff && cdir->offset != offset) || (cdir->num_entries != 0xffff && cdir->num_entries != nentry) || (cdir->disk_entries != 0xffff && cdir->disk_entries != i) || (cdir->this_disk != 0xffff && cdir->this_disk != this_disk) || (cdir->eocd_disk != 0xffff && cdir->eocd_disk != eocd_disk)) {\n        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_MISMATCH);\n        return CDIR_INVALID;\n    }\n\n    cdir->is_zip64 = true;\n    cdir->size = size;\n    cdir->offset = offset;\n    cdir->disk_entries = i;\n    cdir->num_entries = nentry;\n    cdir->this_disk = this_disk;\n    cdir->eocd_disk = eocd_disk;\n\n    return CDIR_OK;\n}\n\n\nstatic int\ndecode_hex(char c) {\n    if (c >= '0' && c <= '9') {\n        return c - '0';\n    }\n    else if (c >= 'A' && c <= 'F') {\n        return c - 'A' + 10;\n    }\n    else {\n        return -1;\n    }\n}\n\n/* _zip_check_torrentzip:\n   check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */\n\nstatic void\nzip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir) {\n    zip_uint32_t crc_should;\n    char buf[8 + 1];\n    size_t i;\n\n    if (cdir == NULL) {\n        return;\n    }\n\n    if (_zip_string_length(cdir->comment) != TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH || strncmp((const char *)cdir->comment->raw, TORRENTZIP_SIGNATURE, TORRENTZIP_SIGNATURE_LENGTH) != 0)\n        return;\n\n    memcpy(buf, cdir->comment->raw + TORRENTZIP_SIGNATURE_LENGTH, TORRENTZIP_CRC_LENGTH);\n    buf[TORRENTZIP_CRC_LENGTH] = '\\0';\n    crc_should = 0;\n    for (i = 0; i < TORRENTZIP_CRC_LENGTH; i += 2) {\n        int low, high;\n        high = decode_hex((buf[i]));\n        low = decode_hex(buf[i + 1]);\n        if (high < 0 || low < 0) {\n            return;\n        }\n        crc_should = (crc_should << 8) + (high << 4) + low;\n    }\n\n    {\n        zip_stat_t st;\n        zip_source_t *src_window;\n        zip_source_t *src_crc;\n        zip_uint8_t buffer[512];\n        zip_int64_t ret;\n\n        zip_stat_init(&st);\n        st.valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC;\n        st.size = cdir->size;\n        st.crc = crc_should;\n        if ((src_window = _zip_source_window_new(za->src, cdir->offset, cdir->size, &st, 0, NULL, NULL, NULL, 0, false, NULL)) == NULL) {\n            return;\n        }\n        if ((src_crc = zip_source_crc_create(src_window, 1, NULL)) == NULL) {\n            zip_source_free(src_window);\n            return;\n        }\n        if (zip_source_open(src_crc) != 0) {\n            zip_source_free(src_crc);\n            return;\n        }\n        while ((ret = zip_source_read(src_crc, buffer, sizeof(buffer))) > 0) {\n        }\n        zip_source_free(src_crc);\n        if (ret < 0) {\n            return;\n        }\n    }\n\n    /* TODO: if check consistency, check cdir entries for valid values */\n    za->flags |= ZIP_AFL_IS_TORRENTZIP;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_pkware.c",
    "content": "/*\n  zip_pkware.c -- Traditional PKWARE de/encryption backend routines\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\n#define PKWARE_KEY0 305419896\n#define PKWARE_KEY1 591751049\n#define PKWARE_KEY2 878082192\n\n\nstatic void\nupdate_keys(zip_pkware_keys_t *keys, zip_uint8_t b) {\n    keys->key[0] = (zip_uint32_t)crc32(keys->key[0] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL;\n    keys->key[1] = (keys->key[1] + (keys->key[0] & 0xff)) * 134775813 + 1;\n    b = (zip_uint8_t)(keys->key[1] >> 24);\n    keys->key[2] = (zip_uint32_t)crc32(keys->key[2] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL;\n}\n\n\nstatic zip_uint8_t\ncrypt_byte(zip_pkware_keys_t *keys) {\n    zip_uint16_t tmp;\n    tmp = (zip_uint16_t)(keys->key[2] | 2);\n    tmp = (zip_uint16_t)(((zip_uint32_t)tmp * (tmp ^ 1)) >> 8);\n    return (zip_uint8_t)tmp;\n}\n\n\nvoid\n_zip_pkware_keys_reset(zip_pkware_keys_t *keys) {\n    keys->key[0] = PKWARE_KEY0;\n    keys->key[1] = PKWARE_KEY1;\n    keys->key[2] = PKWARE_KEY2;\n}\n\n\nvoid\n_zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) {\n    zip_uint64_t i;\n    zip_uint8_t b;\n    zip_uint8_t tmp;\n\n    for (i = 0; i < len; i++) {\n        b = in[i];\n\n        if (out != NULL) {\n            tmp = crypt_byte(keys);\n            update_keys(keys, b);\n            b ^= tmp;\n            out[i] = b;\n        }\n        else {\n            /* during initialization, we're only interested in key updates */\n            update_keys(keys, b);\n        }\n    }\n}\n\n\nvoid\n_zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) {\n    zip_uint64_t i;\n    zip_uint8_t b;\n    zip_uint8_t tmp;\n\n    for (i = 0; i < len; i++) {\n        b = in[i];\n\n        /* during initialization, we're only interested in key updates */\n        if (out != NULL) {\n            tmp = crypt_byte(keys);\n            b ^= tmp;\n            out[i] = b;\n        }\n\n        update_keys(keys, b);\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_progress.c",
    "content": "/*\n zip_progress.c -- progress reporting\n Copyright (C) 2017-2024 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n\n#include <stdlib.h>\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\nstruct zip_progress {\n    zip_t *za;\n\n    zip_progress_callback callback_progress;\n    void (*ud_progress_free)(void *);\n    void *ud_progress;\n\n    zip_cancel_callback callback_cancel;\n    void (*ud_cancel_free)(void *);\n    void *ud_cancel;\n\n    double precision;\n\n    /* state */\n    double last_update; /* last value callback function was called with */\n\n    double start; /* start of sub-progress section */\n    double end;   /* end of sub-progress section */\n};\n\nstatic void _zip_progress_free_cancel_callback(zip_progress_t *progress);\nstatic void _zip_progress_free_progress_callback(zip_progress_t *progress);\nstatic zip_progress_t *_zip_progress_new(zip_t *za);\nstatic void _zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud);\nstatic void _zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud);\n\nvoid\n_zip_progress_end(zip_progress_t *progress) {\n    _zip_progress_update(progress, 1.0);\n}\n\n\nvoid\n_zip_progress_free(zip_progress_t *progress) {\n    if (progress == NULL) {\n        return;\n    }\n\n    _zip_progress_free_progress_callback(progress);\n    _zip_progress_free_cancel_callback(progress);\n\n    free(progress);\n}\n\n\nstatic zip_progress_t *\n_zip_progress_new(zip_t *za) {\n    zip_progress_t *progress = (zip_progress_t *)malloc(sizeof(*progress));\n\n    if (progress == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    progress->za = za;\n\n    progress->callback_progress = NULL;\n    progress->ud_progress_free = NULL;\n    progress->ud_progress = NULL;\n    progress->precision = 0.0;\n\n    progress->callback_cancel = NULL;\n    progress->ud_cancel_free = NULL;\n    progress->ud_cancel = NULL;\n\n    return progress;\n}\n\nstatic void\n_zip_progress_free_progress_callback(zip_progress_t *progress) {\n    if (progress->ud_progress_free) {\n        progress->ud_progress_free(progress->ud_progress);\n    }\n\n    progress->callback_progress = NULL;\n    progress->ud_progress = NULL;\n    progress->ud_progress_free = NULL;\n}\n\nstatic void\n_zip_progress_free_cancel_callback(zip_progress_t *progress) {\n    if (progress->ud_cancel_free) {\n        progress->ud_cancel_free(progress->ud_cancel);\n    }\n\n    progress->callback_cancel = NULL;\n    progress->ud_cancel = NULL;\n    progress->ud_cancel_free = NULL;\n}\n\nstatic void\n_zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {\n    _zip_progress_free_progress_callback(progress);\n\n    progress->callback_progress = callback;\n    progress->ud_progress_free = ud_free;\n    progress->ud_progress = ud;\n    progress->precision = precision;\n}\n\nvoid\n_zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) {\n    _zip_progress_free_cancel_callback(progress);\n\n    progress->callback_cancel = callback;\n    progress->ud_cancel_free = ud_free;\n    progress->ud_cancel = ud;\n}\n\nint\n_zip_progress_start(zip_progress_t *progress) {\n    if (progress == NULL) {\n        return 0;\n    }\n\n    if (progress->callback_progress != NULL) {\n        progress->last_update = 0.0;\n        progress->callback_progress(progress->za, 0.0, progress->ud_progress);\n    }\n\n    if (progress->callback_cancel != NULL) {\n        if (progress->callback_cancel(progress->za, progress->ud_cancel)) {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n\nint\n_zip_progress_subrange(zip_progress_t *progress, double start, double end) {\n    if (progress == NULL) {\n        return 0;\n    }\n\n    progress->start = start;\n    progress->end = end;\n\n    return _zip_progress_update(progress, 0.0);\n}\n\nint\n_zip_progress_update(zip_progress_t *progress, double sub_current) {\n    double current;\n\n    if (progress == NULL) {\n        return 0;\n    }\n\n    if (progress->callback_progress != NULL) {\n        current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start;\n\n        if (current - progress->last_update > progress->precision || (progress->last_update < 1 && current == 1)) {\n            progress->callback_progress(progress->za, current, progress->ud_progress);\n            progress->last_update = current;\n        }\n    }\n\n    if (progress->callback_cancel != NULL) {\n        if (progress->callback_cancel(progress->za, progress->ud_cancel)) {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n\nZIP_EXTERN int\nzip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {\n    if (callback != NULL) {\n        if (za->progress == NULL) {\n            if ((za->progress = _zip_progress_new(za)) == NULL) {\n                return -1;\n            }\n        }\n\n        _zip_progress_set_progress_callback(za->progress, precision, callback, ud_free, ud);\n    }\n    else {\n        if (za->progress != NULL) {\n            if (za->progress->callback_cancel == NULL) {\n                _zip_progress_free(za->progress);\n                za->progress = NULL;\n            }\n            else {\n                _zip_progress_free_progress_callback(za->progress);\n            }\n        }\n    }\n\n    return 0;\n}\n\n\nZIP_EXTERN int\nzip_register_cancel_callback_with_state(zip_t *za, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) {\n    if (callback != NULL) {\n        if (za->progress == NULL) {\n            if ((za->progress = _zip_progress_new(za)) == NULL) {\n                return -1;\n            }\n        }\n\n        _zip_progress_set_cancel_callback(za->progress, callback, ud_free, ud);\n    }\n    else {\n        if (za->progress != NULL) {\n            if (za->progress->callback_progress == NULL) {\n                _zip_progress_free(za->progress);\n                za->progress = NULL;\n            }\n            else {\n                _zip_progress_free_cancel_callback(za->progress);\n            }\n        }\n    }\n\n    return 0;\n}\n\n\nstruct legacy_ud {\n    zip_progress_callback_t callback;\n};\n\n\nstatic void\n_zip_legacy_progress_callback(zip_t *za, double progress, void *vud) {\n    struct legacy_ud *ud = (struct legacy_ud *)vud;\n\n    ud->callback(progress);\n}\n\nZIP_EXTERN void\nzip_register_progress_callback(zip_t *za, zip_progress_callback_t progress_callback) {\n    struct legacy_ud *ud;\n\n    if (progress_callback == NULL) {\n        zip_register_progress_callback_with_state(za, 0, NULL, NULL, NULL);\n    }\n\n    if ((ud = (struct legacy_ud *)malloc(sizeof(*ud))) == NULL) {\n        return;\n    }\n\n    ud->callback = progress_callback;\n\n    if (zip_register_progress_callback_with_state(za, 0.001, _zip_legacy_progress_callback, free, ud) < 0) {\n        free(ud);\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_random_unix.c",
    "content": "/*\n  zip_random_unix.c -- fill the user's buffer with random stuff (Unix version)\n  Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#ifdef HAVE_CRYPTO\n#include \"zip_crypto.h\"\n#endif\n\n#ifdef HAVE_ARC4RANDOM\n\n#include <stdlib.h>\n\n#ifndef HAVE_SECURE_RANDOM\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    arc4random_buf(buffer, length);\n    return true;\n}\n#endif\n\n#ifndef HAVE_RANDOM_UINT32\nzip_uint32_t\nzip_random_uint32(void) {\n    return arc4random();\n}\n#endif\n\n#else /* HAVE_ARC4RANDOM */\n\n#ifndef HAVE_SECURE_RANDOM\n#include <fcntl.h>\n#include <unistd.h>\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    int fd;\n\n    if ((fd = open(\"/dev/urandom\", O_RDONLY)) < 0) {\n        return false;\n    }\n\n    if (read(fd, buffer, length) != length) {\n        close(fd);\n        return false;\n    }\n\n    close(fd);\n    return true;\n}\n#endif\n\n#ifndef HAVE_RANDOM_UINT32\n#include <stdlib.h>\n\n#ifndef HAVE_RANDOM\n#define srandom srand\n#define random rand\n#endif\n\nzip_uint32_t\nzip_random_uint32(void) {\n    static bool seeded = false;\n\n    zip_uint32_t value;\n\n    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {\n        return value;\n    }\n\n    if (!seeded) {\n        srandom((unsigned int)time(NULL));\n        seeded = true;\n    }\n\n    return (zip_uint32_t)random();\n}\n#endif\n\n#endif /* HAVE_ARC4RANDOM */\n"
  },
  {
    "path": "external/libzip/lib/zip_random_uwp.c",
    "content": "/*\n  zip_random_uwp.c -- fill the user's buffer with random stuff (UWP version)\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#ifdef HAVE_CRYPTO\n#include \"zip_crypto.h\"\n#endif\n\n#ifndef HAVE_SECURE_RANDOM\n\n#include <windows.h>\n#include <bcrypt.h>\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    BCRYPT_ALG_HANDLE hAlg = NULL;\n    NTSTATUS hr = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);\n    if (!BCRYPT_SUCCESS(hr) || hAlg == NULL) {\n        return false;\n    }\n    hr = BCryptGenRandom(&hAlg, buffer, length, 0);\n    BCryptCloseAlgorithmProvider(&hAlg, 0);\n    if (!BCRYPT_SUCCESS(hr)) {\n        return false;\n    }\n    return true;\n}\n\n#endif\n\n#ifndef HAVE_RANDOM_UINT32\n#include <stdlib.h>\n\nzip_uint32_t\nzip_random_uint32(void) {\n    static bool seeded = false;\n\n    zip_uint32_t value;\n\n    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {\n        return value;\n    }\n\n    if (!seeded) {\n        srand((unsigned int)time(NULL));\n        seeded = true;\n    }\n\n    return (zip_uint32_t)rand();\n}\n#endif\n"
  },
  {
    "path": "external/libzip/lib/zip_random_win32.c",
    "content": "/*\n  zip_random_win32.c -- fill the user's buffer with random stuff (Windows version)\n  Copyright (C) 2016-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#ifdef HAVE_CRYPTO\n#include \"zip_crypto.h\"\n#endif\n\n#include <windows.h>\n\n#ifndef HAVE_SECURE_RANDOM\n\n#include <wincrypt.h>\n\nZIP_EXTERN bool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    HCRYPTPROV hprov;\n    if (!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {\n        return false;\n    }\n    if (!CryptGenRandom(hprov, length, buffer)) {\n        return false;\n    }\n    if (!CryptReleaseContext(hprov, 0)) {\n        return false;\n    }\n    return true;\n}\n#endif\n\n#ifndef HAVE_RANDOM_UINT32\n#include <stdlib.h>\n\nzip_uint32_t\nzip_random_uint32(void) {\n    static bool seeded = false;\n\n    zip_uint32_t value;\n\n    if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {\n        return value;\n    }\n\n    if (!seeded) {\n        srand((unsigned int)time(NULL));\n        seeded = true;\n    }\n\n    return (zip_uint32_t)rand();\n}\n#endif\n"
  },
  {
    "path": "external/libzip/lib/zip_realloc.c",
    "content": "/*\n  zip_realloc.c -- reallocate with additional elements\n  Copyright (C) 2009-2025 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\nbool zip_realloc(void **memory, zip_uint64_t *alloced_elements, zip_uint64_t element_size, zip_uint64_t additional_elements, zip_error_t *error) {\n    zip_uint64_t new_alloced_elements;\n    void *new_memory;\n\n    if (additional_elements == 0) {\n        return true;\n    }\n\n    new_alloced_elements = *alloced_elements + additional_elements;\n\n    if (new_alloced_elements < additional_elements || new_alloced_elements > SIZE_MAX / element_size) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return false;\n    }\n\n    if ((new_memory = realloc(*memory, (size_t)(new_alloced_elements * element_size))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return false;\n    }\n\n    *memory = new_memory;\n    *alloced_elements = new_alloced_elements;\n\n    return true;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_rename.c",
    "content": "/*\n  zip_rename.c -- rename file in zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_rename(zip_t *za, zip_uint64_t idx, const char *name) {\n    return zip_file_rename(za, idx, name, 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_replace.c",
    "content": "/*\n  zip_replace.c -- replace file via callback function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_replace(zip_t *za, zip_uint64_t idx, zip_source_t *source) {\n    return zip_file_replace(za, idx, source, 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_archive_comment.c",
    "content": "/*\n  zip_set_archive_comment.c -- set archive comment\n  Copyright (C) 2006-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_set_archive_comment(zip_t *za, const char *comment, zip_uint16_t len) {\n    zip_string_t *cstr;\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (len > 0 && comment == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (len > 0) {\n        if ((cstr = _zip_string_new((const zip_uint8_t *)comment, len, ZIP_FL_ENC_GUESS, &za->error)) == NULL)\n            return -1;\n\n        if (_zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_CP437) {\n            _zip_string_free(cstr);\n            zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n    }\n    else\n        cstr = NULL;\n\n    _zip_string_free(za->comment_changes);\n    za->comment_changes = NULL;\n\n    if (((za->comment_orig && _zip_string_equal(za->comment_orig, cstr)) || (za->comment_orig == NULL && cstr == NULL))) {\n        _zip_string_free(cstr);\n        za->comment_changed = 0;\n    }\n    else {\n        za->comment_changes = cstr;\n        za->comment_changed = 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_archive_flag.c",
    "content": "/*\n  zip_get_archive_flag.c -- set archive global flag\n  Copyright (C) 2008-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_set_archive_flag(zip_t *za, zip_flags_t flag, int value) {\n    unsigned int new_flags;\n\n    if (flag == ZIP_AFL_IS_TORRENTZIP) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    /* TODO: when setting ZIP_AFL_WANT_TORRENTZIP, we should error out if any changes have been made that are not allowed for torrentzip. */\n\n    if (value) {\n        new_flags = za->ch_flags | flag;\n    }\n    else {\n        new_flags = za->ch_flags & ~flag;\n    }\n\n    if (new_flags == za->ch_flags) {\n        return 0;\n    }\n\n    /* Allow removing ZIP_AFL_RDONLY if manually set, not if archive was opened read-only. */\n    if (za->flags & ZIP_AFL_RDONLY) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if ((flag & ZIP_AFL_RDONLY) && value && (za->ch_flags & ZIP_AFL_RDONLY) == 0) {\n        if (_zip_changed(za, NULL)) {\n            zip_error_set(&za->error, ZIP_ER_CHANGED, 0);\n            return -1;\n        }\n    }\n\n    za->ch_flags = new_flags;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_default_password.c",
    "content": "/*\n  zip_set_default_password.c -- set default password for decryption\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_set_default_password(zip_t *za, const char *passwd) {\n    if (za == NULL)\n        return -1;\n\n    free(za->default_password);\n\n    if (passwd && passwd[0] != '\\0') {\n        if ((za->default_password = strdup(passwd)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n    else\n        za->default_password = NULL;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_file_comment.c",
    "content": "/*\n  zip_set_file_comment.c -- set comment for file in archive\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_set_file_comment(zip_t *za, zip_uint64_t idx, const char *comment, int len) {\n    if (len < 0 || len > ZIP_UINT16_MAX) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n    return zip_file_set_comment(za, idx, comment, (zip_uint16_t)len, 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_file_compression.c",
    "content": "/*\n  zip_set_file_compression.c -- set compression for file in archive\n  Copyright (C) 2012-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_set_file_compression(zip_t *za, zip_uint64_t idx, zip_int32_t method, zip_uint32_t flags) {\n    zip_entry_t *e;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n    if (ZIP_WANT_TORRENTZIP(za)) {\n        zip_error_set(&za->error, ZIP_ER_NOT_ALLOWED, 0);\n        return -1;\n    }\n\n    if (!zip_compression_method_supported(method, true)) {\n        zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);\n        return -1;\n    }\n\n    e = za->entry + idx;\n\n    /* TODO: do we want to recompress if level is set? Only if it's\n     * different than what bit flags tell us, but those are not\n     * defined for all compression methods, or not directly mappable\n     * to levels */\n\n    if (e->changes == NULL) {\n        if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n    }\n\n    e->changes->comp_method = method;\n    e->changes->compression_level = (zip_uint16_t)flags;\n    e->changes->changed |= ZIP_DIRENT_COMP_METHOD;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_set_name.c",
    "content": "/*\n  zip_set_name.c -- rename helper function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nint\n_zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) {\n    zip_entry_t *e;\n    zip_string_t *str;\n    bool same_as_orig;\n    zip_int64_t i;\n    const zip_uint8_t *old_name, *new_name;\n    zip_string_t *old_str;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (ZIP_IS_RDONLY(za)) {\n        zip_error_set(&za->error, ZIP_ER_RDONLY, 0);\n        return -1;\n    }\n\n    if (name && name[0] != '\\0') {\n        /* TODO: check for string too long */\n        if ((str = _zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL)\n            return -1;\n        if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED)\n            str->encoding = ZIP_ENCODING_UTF8_KNOWN;\n    }\n    else\n        str = NULL;\n\n    /* TODO: encoding flags needed for CP437? */\n    if ((i = _zip_name_locate(za, name, 0, NULL)) >= 0 && (zip_uint64_t)i != idx) {\n        _zip_string_free(str);\n        zip_error_set(&za->error, ZIP_ER_EXISTS, 0);\n        return -1;\n    }\n\n    /* no effective name change */\n    if (i >= 0 && (zip_uint64_t)i == idx) {\n        _zip_string_free(str);\n        return 0;\n    }\n\n    e = za->entry + idx;\n\n    if (e->orig)\n        same_as_orig = _zip_string_equal(e->orig->filename, str);\n    else\n        same_as_orig = false;\n\n    if (!same_as_orig && e->changes == NULL) {\n        if ((e->changes = _zip_dirent_clone(e->orig)) == NULL) {\n            zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n            _zip_string_free(str);\n            return -1;\n        }\n    }\n\n    if ((new_name = _zip_string_get(same_as_orig ? e->orig->filename : str, NULL, 0, &za->error)) == NULL) {\n        _zip_string_free(str);\n        return -1;\n    }\n\n    if (e->changes) {\n        old_str = e->changes->filename;\n    }\n    else if (e->orig) {\n        old_str = e->orig->filename;\n    }\n    else {\n        old_str = NULL;\n    }\n\n    if (old_str) {\n        if ((old_name = _zip_string_get(old_str, NULL, 0, &za->error)) == NULL) {\n            _zip_string_free(str);\n            return -1;\n        }\n    }\n    else {\n        old_name = NULL;\n    }\n\n    if (_zip_hash_add(za->names, new_name, idx, 0, &za->error) == false) {\n        _zip_string_free(str);\n        return -1;\n    }\n    if (old_name) {\n        _zip_hash_delete(za->names, old_name, NULL);\n    }\n\n    if (same_as_orig) {\n        if (e->changes) {\n            if (e->changes->changed & ZIP_DIRENT_FILENAME) {\n                _zip_string_free(e->changes->filename);\n                e->changes->changed &= ~ZIP_DIRENT_FILENAME;\n                if (e->changes->changed == 0) {\n                    _zip_dirent_free(e->changes);\n                    e->changes = NULL;\n                }\n                else {\n                    /* TODO: what if not cloned? can that happen? */\n                    e->changes->filename = e->orig->filename;\n                }\n            }\n        }\n        _zip_string_free(str);\n    }\n    else {\n        if (e->changes->changed & ZIP_DIRENT_FILENAME) {\n            _zip_string_free(e->changes->filename);\n        }\n        e->changes->changed |= ZIP_DIRENT_FILENAME;\n        e->changes->filename = str;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_accept_empty.c",
    "content": "/*\n  zip_source_accept_empty.c -- if empty source is a valid archive\n  Copyright (C) 2019-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nbool\nzip_source_accept_empty(zip_source_t *src) {\n    zip_int64_t ret;\n\n    if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY)) == 0) {\n        if (ZIP_SOURCE_IS_LAYERED(src)) {\n            return zip_source_accept_empty(src->src);\n        }\n        return true;\n    }\n\n    ret = _zip_source_call(src, NULL, 0, ZIP_SOURCE_ACCEPT_EMPTY);\n\n    return ret != 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_begin_write.c",
    "content": "/*\n  zip_source_begin_write.c -- start a new file for writing\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_begin_write(zip_source_t *src) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (ZIP_SOURCE_IS_OPEN_WRITING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_BEGIN_WRITE) < 0) {\n        return -1;\n    }\n\n    src->write_state = ZIP_SOURCE_WRITE_OPEN;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_begin_write_cloning.c",
    "content": "/*\n  zip_source_begin_write_cloning.c -- clone part of file for writing\n  Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_begin_write_cloning(zip_source_t *src, zip_uint64_t offset) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (ZIP_SOURCE_IS_OPEN_WRITING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (_zip_source_call(src, NULL, offset, ZIP_SOURCE_BEGIN_WRITE_CLONING) < 0) {\n        return -1;\n    }\n\n    src->write_state = ZIP_SOURCE_WRITE_OPEN;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_buffer.c",
    "content": "/*\n  zip_source_buffer.c -- create zip data source from buffer\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n#ifndef WRITE_FRAGMENT_SIZE\n#define WRITE_FRAGMENT_SIZE (64 * 1024)\n#endif\n\nstruct buffer {\n    zip_buffer_fragment_t *fragments; /* fragments */\n    zip_uint64_t *fragment_offsets;   /* offset of each fragment from start of buffer, nfragments+1 entries */\n    zip_uint64_t nfragments;          /* number of allocated fragments */\n    zip_uint64_t fragments_capacity;  /* size of fragments (number of pointers) */\n\n    zip_uint64_t first_owned_fragment; /* first fragment to free data from */\n\n    zip_uint64_t shared_fragments; /* number of shared fragments */\n    struct buffer *shared_buffer;  /* buffer fragments are shared with */\n\n    zip_uint64_t size;             /* size of buffer */\n    zip_uint64_t offset;           /* current offset in buffer */\n    zip_uint64_t current_fragment; /* fragment current offset is in */\n};\n\ntypedef struct buffer buffer_t;\n\nstruct read_data {\n    zip_error_t error;\n    time_t mtime;\n    zip_file_attributes_t attributes;\n    buffer_t *in;\n    buffer_t *out;\n};\n\n#define buffer_capacity(buffer) ((buffer)->fragment_offsets[(buffer)->nfragments])\n#define buffer_size(buffer) ((buffer)->size)\n\nstatic buffer_t *buffer_clone(buffer_t *buffer, zip_uint64_t length, zip_error_t *error);\nstatic zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset);\nstatic void buffer_free(buffer_t *buffer);\nstatic bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error);\nstatic buffer_t *buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error);\nstatic zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);\nstatic int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error);\nstatic zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *);\n\nstatic zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);\n\nzip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);\nzip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error);\n\n\nZIP_EXTERN zip_source_t *\nzip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) {\n    if (za == NULL)\n        return NULL;\n\n    return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) {\n    return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error);\n}\n\n\nzip_source_t *\nzip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {\n    zip_buffer_fragment_t fragment;\n\n    if (data == NULL) {\n        if (len > 0) {\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n\n        return zip_source_buffer_fragment_with_attributes_create(NULL, 0, freep, attributes, error);\n    }\n\n    fragment.data = (zip_uint8_t *)data;\n    fragment.length = len;\n\n    return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep) {\n    if (za == NULL) {\n        return NULL;\n    }\n\n    return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) {\n    return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error);\n}\n\nzip_source_t *\nzip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {\n    struct read_data *ctx;\n    zip_source_t *zs;\n    buffer_t *buffer;\n\n    if (fragments == NULL && nfragments > 0) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((buffer = buffer_new(fragments, nfragments, freep, error)) == NULL) {\n        return NULL;\n    }\n\n    if ((ctx = (struct read_data *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        buffer_free(buffer);\n        return NULL;\n    }\n\n    ctx->in = buffer;\n    ctx->out = NULL;\n    ctx->mtime = time(NULL);\n    if (attributes) {\n        (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes));\n    }\n    else {\n        zip_file_attributes_init(&ctx->attributes);\n    }\n    zip_error_init(&ctx->error);\n\n    if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) {\n        buffer_free(ctx->in);\n        free(ctx);\n        return NULL;\n    }\n\n    return zs;\n}\n\n\nzip_source_t *\nzip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) {\n    return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error);\n}\n\nstatic zip_int64_t\nread_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct read_data *ctx = (struct read_data *)state;\n\n    switch (cmd) {\n    case ZIP_SOURCE_BEGIN_WRITE:\n        if ((ctx->out = buffer_new(NULL, 0, 0, &ctx->error)) == NULL) {\n            return -1;\n        }\n        ctx->out->offset = 0;\n        ctx->out->current_fragment = 0;\n        return 0;\n\n    case ZIP_SOURCE_BEGIN_WRITE_CLONING:\n        if ((ctx->out = buffer_clone(ctx->in, len, &ctx->error)) == NULL) {\n            return -1;\n        }\n        ctx->out->offset = len;\n        ctx->out->current_fragment = ctx->out->nfragments;\n        return 0;\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_COMMIT_WRITE:\n        buffer_free(ctx->in);\n        ctx->in = ctx->out;\n        ctx->out = NULL;\n        return 0;\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        buffer_free(ctx->in);\n        buffer_free(ctx->out);\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {\n        if (len < sizeof(ctx->attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n\n        (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes));\n\n        return sizeof(ctx->attributes);\n    }\n\n    case ZIP_SOURCE_OPEN:\n        ctx->in->offset = 0;\n        ctx->in->current_fragment = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if (len > ZIP_INT64_MAX) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        return buffer_read(ctx->in, data, len);\n\n    case ZIP_SOURCE_REMOVE: {\n        buffer_t *empty = buffer_new(NULL, 0, 0, &ctx->error);\n        if (empty == NULL) {\n            return -1;\n        }\n\n        buffer_free(ctx->in);\n        ctx->in = empty;\n        return 0;\n    }\n\n    case ZIP_SOURCE_ROLLBACK_WRITE:\n        buffer_free(ctx->out);\n        ctx->out = NULL;\n        return 0;\n\n    case ZIP_SOURCE_SEEK:\n        return buffer_seek(ctx->in, data, len, &ctx->error);\n\n    case ZIP_SOURCE_SEEK_WRITE:\n        return buffer_seek(ctx->out, data, len, &ctx->error);\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        if (len < sizeof(*st)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n\n        st = (zip_stat_t *)data;\n\n        zip_stat_init(st);\n        st->mtime = ctx->mtime;\n        st->size = ctx->in->size;\n        st->comp_size = st->size;\n        st->comp_method = ZIP_CM_STORE;\n        st->encryption_method = ZIP_EM_NONE;\n        st->valid = ZIP_STAT_MTIME | ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;\n\n        return sizeof(*st);\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, ZIP_SOURCE_SUPPORTS_REOPEN, -1);\n\n    case ZIP_SOURCE_TELL:\n        if (ctx->in->offset > ZIP_INT64_MAX) {\n            zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);\n            return -1;\n        }\n        return (zip_int64_t)ctx->in->offset;\n\n\n    case ZIP_SOURCE_TELL_WRITE:\n        if (ctx->out->offset > ZIP_INT64_MAX) {\n            zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);\n            return -1;\n        }\n        return (zip_int64_t)ctx->out->offset;\n\n    case ZIP_SOURCE_WRITE:\n        if (len > ZIP_INT64_MAX) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        return buffer_write(ctx->out, data, len, &ctx->error);\n\n    default:\n        zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n}\n\n\nstatic buffer_t *\nbuffer_clone(buffer_t *buffer, zip_uint64_t offset, zip_error_t *error) {\n    zip_uint64_t fragment, fragment_offset, waste;\n    buffer_t *clone;\n\n    if (offset == 0) {\n        return buffer_new(NULL, 0, 1, error);\n    }\n\n    if (offset > buffer->size) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    if (buffer->shared_buffer != NULL) {\n        zip_error_set(error, ZIP_ER_INUSE, 0);\n        return NULL;\n    }\n\n    fragment = buffer_find_fragment(buffer, offset);\n    fragment_offset = offset - buffer->fragment_offsets[fragment];\n\n    if (fragment_offset == 0) {\n        /* We can't be at beginning of fragment zero if offset > 0. */\n        fragment--;\n        fragment_offset = buffer->fragments[fragment].length;\n    }\n\n    /* TODO: This should also consider the length of the fully shared fragments */\n    waste = buffer->fragments[fragment].length - fragment_offset;\n    if (waste > offset) {\n        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((clone = buffer_new(buffer->fragments, fragment + 1, 0, error)) == NULL) {\n        return NULL;\n    }\n\n#ifndef __clang_analyzer__\n    /* clone->fragments can't be null, since it was created with at least one fragment */\n    clone->fragments[fragment].length = fragment_offset;\n#endif\n    clone->fragment_offsets[clone->nfragments] = offset;\n    clone->size = offset;\n\n    clone->first_owned_fragment = ZIP_MIN(buffer->first_owned_fragment, clone->nfragments);\n\n    buffer->shared_buffer = clone;\n    clone->shared_buffer = buffer;\n    buffer->shared_fragments = fragment + 1;\n    clone->shared_fragments = fragment + 1;\n    \n    return clone;\n}\n\n\nstatic zip_uint64_t\nbuffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset) {\n    zip_uint64_t low, high, mid;\n\n    if (buffer->nfragments == 0) {\n        return 0;\n    }\n\n    low = 0;\n    high = buffer->nfragments - 1;\n\n    while (low < high) {\n        mid = (high - low) / 2 + low;\n        if (buffer->fragment_offsets[mid] > offset) {\n            high = mid - 1;\n        }\n        else if (mid == buffer->nfragments || buffer->fragment_offsets[mid + 1] > offset) {\n            return mid;\n        }\n        else {\n            low = mid + 1;\n        }\n    }\n\n    return low;\n}\n\n\nstatic void\nbuffer_free(buffer_t *buffer) {\n    zip_uint64_t i;\n\n    if (buffer == NULL) {\n        return;\n    }\n\n    if (buffer->shared_buffer != NULL) {\n        buffer->shared_buffer->shared_buffer = NULL;\n        buffer->shared_buffer->shared_fragments = 0;\n\n        buffer->first_owned_fragment = ZIP_MAX(buffer->first_owned_fragment, buffer->shared_fragments);\n    }\n\n    for (i = buffer->first_owned_fragment; i < buffer->nfragments; i++) {\n        free(buffer->fragments[i].data);\n    }\n    free(buffer->fragments);\n    free(buffer->fragment_offsets);\n    free(buffer);\n}\n\n\nstatic bool\nbuffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error) {\n    zip_uint64_t additional_fragments;\n    zip_uint64_t offset_capacity = buffer->fragments_capacity + 1;\n\n    if (capacity <= buffer->fragments_capacity) {\n        return true;\n    }\n\n    additional_fragments = capacity - buffer->fragments_capacity;\n\n    if (!ZIP_REALLOC(buffer->fragments, buffer->fragments_capacity, additional_fragments, error)) {\n        return false;\n    }\n    /* The size of both buffer->fragments and buffer->fragment_offsets is stored in buffer->fragments_capacity, so use a temporary capacity variable here for reallocating buffer->fragment_offsets. */\n    if (!ZIP_REALLOC(buffer->fragment_offsets, offset_capacity, additional_fragments, error)) {\n        buffer->fragments_capacity -= additional_fragments;\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic buffer_t *\nbuffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error) {\n    buffer_t *buffer;\n\n    if ((buffer = malloc(sizeof(*buffer))) == NULL) {\n        return NULL;\n    }\n\n    buffer->offset = 0;\n    buffer->first_owned_fragment = 0;\n    buffer->size = 0;\n    buffer->fragments = NULL;\n    buffer->fragment_offsets = NULL;\n    buffer->nfragments = 0;\n    buffer->fragments_capacity = 0;\n    buffer->shared_buffer = NULL;\n    buffer->shared_fragments = 0;\n\n    if (nfragments == 0) {\n        if ((buffer->fragment_offsets = malloc(sizeof(buffer->fragment_offsets[0]))) == NULL) {\n            free(buffer);\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            return NULL;\n        }\n        buffer->fragment_offsets[0] = 0;\n    }\n    else {\n        zip_uint64_t i, j, offset;\n\n        if (!buffer_grow_fragments(buffer, nfragments, NULL)) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            buffer_free(buffer);\n            return NULL;\n        }\n\n        offset = 0;\n        for (i = 0, j = 0; i < nfragments; i++) {\n            if (fragments[i].length == 0) {\n                continue;\n            }\n            if (fragments[i].data == NULL) {\n                zip_error_set(error, ZIP_ER_INVAL, 0);\n                buffer_free(buffer);\n                return NULL;\n            }\n            buffer->fragments[j].data = fragments[i].data;\n            buffer->fragments[j].length = fragments[i].length;\n            buffer->fragment_offsets[i] = offset;\n            /* TODO: overflow */\n            offset += fragments[i].length;\n            j++;\n        }\n        buffer->nfragments = j;\n        buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments;\n        buffer->fragment_offsets[buffer->nfragments] = offset;\n        buffer->size = offset;\n    }\n\n    return buffer;\n}\n\nstatic zip_int64_t\nbuffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) {\n    zip_uint64_t n, i, fragment_offset;\n\n    length = ZIP_MIN(length, buffer->size - buffer->offset);\n\n    if (length == 0) {\n        return 0;\n    }\n    if (length > ZIP_INT64_MAX) {\n        return -1;\n    }\n\n    i = buffer->current_fragment;\n    fragment_offset = buffer->offset - buffer->fragment_offsets[i];\n    n = 0;\n    while (n < length) {\n        zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset);\n#if ZIP_UINT64_MAX > SIZE_MAX\n        left = ZIP_MIN(left, SIZE_MAX);\n#endif\n\n        (void)memcpy_s(data + n, (size_t)left, buffer->fragments[i].data + fragment_offset, (size_t)left);\n\n        if (left == buffer->fragments[i].length - fragment_offset) {\n            i++;\n        }\n        n += left;\n        fragment_offset = 0;\n    }\n\n    buffer->offset += n;\n    buffer->current_fragment = i;\n    return (zip_int64_t)n;\n}\n\n\nstatic int\nbuffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error) {\n    zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error);\n\n    if (new_offset < 0) {\n        return -1;\n    }\n\n    buffer->offset = (zip_uint64_t)new_offset;\n    buffer->current_fragment = buffer_find_fragment(buffer, buffer->offset);\n    return 0;\n}\n\n\nstatic zip_int64_t\nbuffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) {\n    zip_uint64_t copied, i, fragment_offset, capacity;\n\n    if (buffer->offset + length + WRITE_FRAGMENT_SIZE - 1 < length) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    /* grow buffer if needed */\n    capacity = buffer_capacity(buffer);\n    if (buffer->offset + length > capacity) {\n        zip_uint64_t needed_fragments = buffer->nfragments + (length - (capacity - buffer->offset) + WRITE_FRAGMENT_SIZE - 1) / WRITE_FRAGMENT_SIZE;\n\n        if (needed_fragments > buffer->fragments_capacity) {\n            zip_uint64_t new_capacity = buffer->fragments_capacity;\n\n            if (new_capacity == 0) {\n                new_capacity = 16;\n            }\n            while (new_capacity < needed_fragments) {\n                new_capacity *= 2;\n            }\n\n            if (!buffer_grow_fragments(buffer, new_capacity, error)) {\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n        }\n\n        while (buffer->nfragments < needed_fragments) {\n            if ((buffer->fragments[buffer->nfragments].data = malloc(WRITE_FRAGMENT_SIZE)) == NULL) {\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n            buffer->fragments[buffer->nfragments].length = WRITE_FRAGMENT_SIZE;\n            buffer->nfragments++;\n            capacity += WRITE_FRAGMENT_SIZE;\n            buffer->fragment_offsets[buffer->nfragments] = capacity;\n        }\n    }\n\n    i = buffer->current_fragment;\n    fragment_offset = buffer->offset - buffer->fragment_offsets[i];\n    copied = 0;\n    while (copied < length) {\n        zip_uint64_t n = ZIP_MIN(ZIP_MIN(length - copied, buffer->fragments[i].length - fragment_offset), SIZE_MAX);\n#if ZIP_UINT64_MAX > SIZE_MAX\n        n = ZIP_MIN(n, SIZE_MAX);\n#endif\n\n        (void)memcpy_s(buffer->fragments[i].data + fragment_offset, (size_t)n, data + copied, (size_t)n);\n\n        if (n == buffer->fragments[i].length - fragment_offset) {\n            i++;\n            fragment_offset = 0;\n        }\n        else {\n            fragment_offset += n;\n        }\n        copied += n;\n    }\n\n    buffer->offset += copied;\n    buffer->current_fragment = i;\n    if (buffer->offset > buffer->size) {\n        buffer->size = buffer->offset;\n    }\n\n    return (zip_int64_t)copied;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_call.c",
    "content": "/*\n zip_source_call.c -- invoke callback command on zip_source\n Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n\n#include \"zipint.h\"\n\n\nzip_int64_t\n_zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) {\n    zip_int64_t ret;\n\n    if ((src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(command)) == 0) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (src->src == NULL) {\n        ret = src->cb.f(src->ud, data, length, command);\n    }\n    else {\n        ret = src->cb.l(src->src, src->ud, data, length, command);\n    }\n\n    if (ret < 0) {\n        if (command != ZIP_SOURCE_ERROR && command != ZIP_SOURCE_SUPPORTS) {\n            int e[2];\n\n            if (_zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) {\n                zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);\n            }\n            else {\n                zip_error_set(&src->error, e[0], e[1]);\n            }\n        }\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_close.c",
    "content": "/*\n  zip_source_close.c -- close zip_source (stop reading)\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nint\nzip_source_close(zip_source_t *src) {\n    if (!ZIP_SOURCE_IS_OPEN_READING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    src->open_count--;\n    if (src->open_count == 0) {\n        _zip_source_call(src, NULL, 0, ZIP_SOURCE_CLOSE);\n\n        if (ZIP_SOURCE_IS_LAYERED(src)) {\n            if (zip_source_close(src->src) < 0) {\n                zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);\n            }\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_commit_write.c",
    "content": "/*\n  zip_source_commit_write.c -- commit changes to file\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_commit_write(zip_source_t *src) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (src->open_count > 1) {\n        zip_error_set(&src->error, ZIP_ER_INUSE, 0);\n        return -1;\n    }\n    else if (ZIP_SOURCE_IS_OPEN_READING(src)) {\n        if (zip_source_close(src) < 0) {\n            return -1;\n        }\n    }\n\n    if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_COMMIT_WRITE) < 0) {\n        src->write_state = ZIP_SOURCE_WRITE_FAILED;\n        return -1;\n    }\n\n    src->write_state = ZIP_SOURCE_WRITE_CLOSED;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_compress.c",
    "content": "/*\n  zip_source_compress.c -- (de)compression routines\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\nstruct context {\n    zip_error_t error;\n\n    bool end_of_input;\n    bool end_of_stream;\n    bool can_store;\n    bool is_stored; /* only valid if end_of_stream is true */\n    bool compress;\n    bool check_consistency;\n    zip_int32_t method;\n\n    zip_uint64_t size;\n    zip_int64_t first_read;\n    zip_uint8_t buffer[BUFSIZE];\n\n    zip_compression_algorithm_t *algorithm;\n    void *ud;\n};\n\n\nstruct implementation {\n    zip_uint16_t method;\n    zip_compression_algorithm_t *compress;\n    zip_compression_algorithm_t *decompress;\n};\n\nstatic struct implementation implementations[] = {\n    {ZIP_CM_DEFLATE, &zip_algorithm_deflate_compress, &zip_algorithm_deflate_decompress},\n#if defined(HAVE_LIBBZ2)\n    {ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress},\n#endif\n#if defined(HAVE_LIBLZMA)\n    {ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},\n    /*  Disabled - because 7z isn't able to unpack ZIP+LZMA2\n        archives made this way - and vice versa.\n\n        {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},\n    */\n    {ZIP_CM_XZ, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},\n#endif\n#if defined(HAVE_LIBZSTD)\n    {ZIP_CM_ZSTD, &zip_algorithm_zstd_compress, &zip_algorithm_zstd_decompress},\n#endif\n\n};\n\nstatic size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]);\n\nstatic zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags);\nstatic zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);\nstatic void context_free(struct context *ctx);\nstatic struct context *context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm, bool check_consistency);\nstatic zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t);\n\nzip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress) {\n    size_t i;\n    zip_uint16_t real_method = ZIP_CM_ACTUAL(method);\n\n    for (i = 0; i < implementations_size; i++) {\n        if (implementations[i].method == real_method) {\n            if (compress) {\n                return implementations[i].compress;\n            }\n            else {\n                return implementations[i].decompress;\n            }\n        }\n    }\n\n    return NULL;\n}\n\nZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress) {\n    if (method == ZIP_CM_STORE) {\n        return 1;\n    }\n    return _zip_get_compression_algorithm(method, compress) != NULL;\n}\n\nzip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, zip_uint32_t compression_flags) {\n    return compression_source_new(za, src, method, true, compression_flags);\n}\n\nzip_source_t *\nzip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method) {\n    return compression_source_new(za, src, method, false, 0);\n}\n\n\nstatic zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, zip_uint32_t compression_flags) {\n    struct context *ctx;\n    zip_source_t *s2;\n    zip_compression_algorithm_t *algorithm = NULL;\n\n    if (src == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((algorithm = _zip_get_compression_algorithm(method, compress)) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((ctx = context_new(method, compress, compression_flags, algorithm, za->open_flags & ZIP_CHECKCONS)) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((s2 = zip_source_layered(za, src, compress_callback, ctx)) == NULL) {\n        context_free(ctx);\n        return NULL;\n    }\n\n    return s2;\n}\n\n\nstatic struct context *context_new(zip_int32_t method, bool compress, zip_uint32_t compression_flags, zip_compression_algorithm_t *algorithm, bool check_consistency) {\n    struct context *ctx;\n\n    if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) {\n        return NULL;\n    }\n    zip_error_init(&ctx->error);\n    ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false;\n    ctx->algorithm = algorithm;\n    ctx->method = method;\n    ctx->compress = compress;\n    ctx->end_of_input = false;\n    ctx->end_of_stream = false;\n    ctx->is_stored = false;\n    ctx->check_consistency = check_consistency;\n\n    if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) {\n        zip_error_fini(&ctx->error);\n        free(ctx);\n        return NULL;\n    }\n\n    return ctx;\n}\n\n\nstatic void\ncontext_free(struct context *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    ctx->algorithm->deallocate(ctx->ud);\n    zip_error_fini(&ctx->error);\n\n    free(ctx);\n}\n\n\nstatic zip_int64_t\ncompress_read(zip_source_t *src, struct context *ctx, void *data, zip_uint64_t len) {\n    zip_compression_status_t ret;\n    bool end;\n    zip_int64_t n;\n    zip_uint64_t out_offset;\n    zip_uint64_t out_len;\n\n    if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) {\n        return -1;\n    }\n\n    if (len == 0 || ctx->end_of_stream) {\n        return 0;\n    }\n\n    out_offset = 0;\n\n    end = false;\n    while (!end && out_offset < len) {\n        out_len = len - out_offset;\n        ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len);\n\n        if (ret != ZIP_COMPRESSION_ERROR) {\n            out_offset += out_len;\n        }\n\n        switch (ret) {\n        case ZIP_COMPRESSION_END:\n            ctx->end_of_stream = true;\n\n            if (!ctx->end_of_input) {\n                n = zip_source_read(src, ctx->buffer, 1);\n                if (n < 0) {\n                    zip_error_set_from_source(&ctx->error, src);\n                    end = true;\n                    break;\n                }\n                else if (n == 0) {\n                    ctx->end_of_input = true;\n                    n = ctx->algorithm->end_of_input(ctx->ud) ? 1 : 0;\n                }\n\n                if (n > 0 && ctx->check_consistency) {\n                    /* garbage after stream, or compression ended before all data read */\n                    zip_error_set(&ctx->error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMPRESSED_DATA_TRAILING_GARBAGE);\n                    end = true;\n                    break;\n                }\n            }\n\n            if (ctx->first_read < 0) {\n                /* we got end of processed stream before reading any input data */\n                zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n                end = true;\n                break;\n            }\n            if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) {\n                ctx->is_stored = true;\n                ctx->size = (zip_uint64_t)ctx->first_read;\n                (void)memcpy_s(data, ctx->size, ctx->buffer, ctx->size);\n                return (zip_int64_t)ctx->size;\n            }\n            end = true;\n            break;\n\n        case ZIP_COMPRESSION_OK:\n            break;\n\n        case ZIP_COMPRESSION_NEED_DATA:\n            if (ctx->end_of_input) {\n                /* TODO: error: stream not ended, but no more input */\n                end = true;\n                break;\n            }\n\n            if ((n = zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {\n                zip_error_set_from_source(&ctx->error, src);\n                end = true;\n                break;\n            }\n            else if (n == 0) {\n                ctx->end_of_input = true;\n                ctx->algorithm->end_of_input(ctx->ud);\n                if (ctx->first_read < 0) {\n                    ctx->first_read = 0;\n                }\n            }\n            else {\n                if (ctx->first_read >= 0) {\n                    /* we overwrote a previously filled ctx->buffer */\n                    ctx->can_store = false;\n                }\n                else {\n                    ctx->first_read = n;\n                }\n\n                ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n);\n            }\n            break;\n\n        case ZIP_COMPRESSION_ERROR:\n            /* error set by algorithm */\n            if (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) {\n                zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n            }\n            end = true;\n            break;\n        }\n    }\n\n    if (out_offset > 0) {\n        ctx->can_store = false;\n        ctx->size += out_offset;\n        return (zip_int64_t)out_offset;\n    }\n\n    return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;\n}\n\n\nstatic zip_int64_t\ncompress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct context *ctx;\n\n    ctx = (struct context *)ud;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN: {\n        zip_stat_t st;\n        zip_file_attributes_t attributes;\n        \n        ctx->size = 0;\n        ctx->end_of_input = false;\n        ctx->end_of_stream = false;\n        ctx->is_stored = false;\n        ctx->first_read = -1;\n        \n        if (zip_source_stat(src, &st) < 0 || zip_source_get_file_attributes(src, &attributes) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        if (!ctx->algorithm->start(ctx->ud, &st, &attributes)) {\n            return -1;\n        }\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_READ:\n        return compress_read(src, ctx, data, len);\n\n    case ZIP_SOURCE_CLOSE:\n        if (!ctx->algorithm->end(ctx->ud)) {\n            return -1;\n        }\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n\n        if (ctx->compress) {\n            if (ctx->end_of_stream) {\n                st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method);\n                st->comp_size = ctx->size;\n                st->valid |= ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD;\n            }\n            else {\n                st->valid &= ~(ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD);\n            }\n        }\n        else {\n            st->comp_method = ZIP_CM_STORE;\n            st->valid |= ZIP_STAT_COMP_METHOD;\n            st->valid &= ~ZIP_STAT_COMP_SIZE;\n            if (ctx->end_of_stream) {\n                st->size = ctx->size;\n                st->valid |= ZIP_STAT_SIZE;\n            }\n        }\n    }\n        return 0;\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        context_free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {\n        zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;\n\n        if (len < sizeof(*attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n\n        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;\n        attributes->version_needed = ctx->algorithm->version_needed;\n        attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;\n        attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud));\n\n        return sizeof(*attributes);\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS_REOPEN, -1);\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, len, cmd);\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_crc.c",
    "content": "/*\n  zip_source_crc.c -- pass-through source that calculates CRC32 and size\n  Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <limits.h>\n#include <stdlib.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\nstruct crc_context {\n    int validate;     /* whether to check CRC on EOF and return error on mismatch */\n    int crc_complete; /* whether CRC was computed for complete file */\n    zip_error_t error;\n    zip_uint64_t size;\n    zip_uint64_t position;     /* current reading position */\n    zip_uint64_t crc_position; /* how far we've computed the CRC */\n    zip_uint32_t crc;\n};\n\nstatic zip_int64_t crc_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);\n\n\nzip_source_t *\nzip_source_crc_create(zip_source_t *src, int validate, zip_error_t *error) {\n    struct crc_context *ctx;\n\n    if (src == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((ctx = (struct crc_context *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    zip_error_init(&ctx->error);\n    ctx->validate = validate;\n    ctx->crc_complete = 0;\n    ctx->crc_position = 0;\n    ctx->crc = (zip_uint32_t)crc32(0, NULL, 0);\n    ctx->size = 0;\n\n    return zip_source_layered_create(src, crc_read, ctx, error);\n}\n\n\nstatic zip_int64_t\ncrc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct crc_context *ctx;\n    zip_int64_t n;\n\n    ctx = (struct crc_context *)_ctx;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN:\n        ctx->position = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if ((n = zip_source_read(src, data, len)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        if (n == 0) {\n            if (ctx->crc_position == ctx->position) {\n                ctx->crc_complete = 1;\n                ctx->size = ctx->position;\n\n                if (ctx->validate) {\n                    struct zip_stat st;\n\n                    if (zip_source_stat(src, &st) < 0) {\n                        zip_error_set_from_source(&ctx->error, src);\n                        return -1;\n                    }\n\n                    if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) {\n                        zip_error_set(&ctx->error, ZIP_ER_CRC, 0);\n                        return -1;\n                    }\n                    if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) {\n                        /* We don't have the index here, but the caller should know which file they are reading from. */\n                        zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_INVALID_FILE_LENGTH, MAX_DETAIL_INDEX));\n                        return -1;\n                    }\n                }\n            }\n        }\n        else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) {\n            zip_uint64_t i, nn;\n\n            for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) {\n                nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n - i);\n\n                ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data + i, (uInt)nn);\n                ctx->crc_position += nn;\n            }\n        }\n        ctx->position += (zip_uint64_t)n;\n        return n;\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n\n        if (ctx->crc_complete) {\n            if ((st->valid & ZIP_STAT_SIZE) && st->size != ctx->size) {\n                zip_error_set(&ctx->error, ZIP_ER_DATA_LENGTH, 0);\n                return -1;\n            }\n            /* TODO: Set comp_size, comp_method, encryption_method?\n                    After all, this only works for uncompressed data. */\n            st->size = ctx->size;\n            st->crc = ctx->crc;\n            st->comp_size = ctx->size;\n            st->comp_method = ZIP_CM_STORE;\n            st->encryption_method = ZIP_EM_NONE;\n            st->valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;\n        }\n        return 0;\n    }\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_SUPPORTS: {\n        zip_int64_t mask = zip_source_supports(src);\n\n        if (mask < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        mask &= ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);\n        mask |= zip_source_make_command_bitmap(ZIP_SOURCE_FREE, -1);\n        return mask;\n    }\n\n    case ZIP_SOURCE_SEEK: {\n        zip_int64_t new_position;\n        zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);\n\n        if (args == NULL) {\n            return -1;\n        }\n        if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        ctx->position = (zip_uint64_t)new_position;\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_TELL:\n        return (zip_int64_t)ctx->position;\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, len, cmd);\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_error.c",
    "content": "/*\n  zip_source_error.c -- get last error from zip_source\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nzip_error_t *\nzip_source_error(zip_source_t *src) {\n    return &src->error;\n}\n\nbool\n_zip_source_had_error(zip_source_t *src) {\n    return zip_source_error(src)->zip_err != ZIP_ER_OK;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file.h",
    "content": "#ifndef _HAD_ZIP_SOURCE_FILE_H\n#define _HAD_ZIP_SOURCE_FILE_H\n\n/*\n  zip_source_file.h -- header for common file operations\n  Copyright (C) 2020-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\nstruct zip_source_file_stat {\n    zip_uint64_t size; /* must be valid for regular files */\n    time_t mtime;      /* must always be valid, is initialized to current time */\n    bool exists;       /* must always be valid */\n    bool regular_file; /* must always be valid */\n};\n\ntypedef struct zip_source_file_context zip_source_file_context_t;\ntypedef struct zip_source_file_operations zip_source_file_operations_t;\ntypedef struct zip_source_file_stat zip_source_file_stat_t;\n\nstruct zip_source_file_context {\n    zip_error_t error; /* last error information */\n    zip_int64_t supports;\n\n    /* reading */\n    char *fname;                      /* name of file to read from */\n    void *f;                          /* file to read from */\n    zip_stat_t st;                    /* stat information passed in */\n    zip_file_attributes_t attributes; /* additional file attributes */\n    zip_error_t stat_error;           /* error returned for stat */\n    zip_uint64_t start;               /* start offset of data to read */\n    zip_uint64_t len;                 /* length of the file, 0 for up to EOF */\n    zip_uint64_t offset;              /* current offset relative to start (0 is beginning of part we read) */\n\n    /* writing */\n    char *tmpname;\n    void *fout;\n\n    zip_source_file_operations_t *ops;\n    void *ops_userdata;\n};\n\n\n/* The following methods must be implemented to support each feature:\n   - close, read, seek, and stat must always be implemented.\n   - To support specifying the file by name, open, and strdup must be implemented.\n   - For write support, the file must be specified by name and close, commit_write, create_temp_output, remove, rollback_write, and tell must be implemented.\n   - create_temp_output_cloning is always optional. */\n\nstruct zip_source_file_operations {\n    void (*close)(zip_source_file_context_t *ctx);\n    zip_int64_t (*commit_write)(zip_source_file_context_t *ctx);\n    zip_int64_t (*create_temp_output)(zip_source_file_context_t *ctx);\n    zip_int64_t (*create_temp_output_cloning)(zip_source_file_context_t *ctx, zip_uint64_t len);\n    bool (*open)(zip_source_file_context_t *ctx);\n    zip_int64_t (*read)(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);\n    zip_int64_t (*remove)(zip_source_file_context_t *ctx);\n    void (*rollback_write)(zip_source_file_context_t *ctx);\n    bool (*seek)(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);\n    bool (*stat)(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);\n    char *(*string_duplicate)(zip_source_file_context_t *ctx, const char *);\n    zip_int64_t (*tell)(zip_source_file_context_t *ctx, void *f);\n    zip_int64_t (*write)(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);\n};\n\nzip_source_t *zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error);\n\n#endif /* _HAD_ZIP_SOURCE_FILE_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_common.c",
    "content": "/*\n  zip_source_file_common.c -- create data source from file\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\n#include \"zip_source_file.h\"\n\nstatic zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);\n\nstatic void\nzip_source_file_stat_init(zip_source_file_stat_t *st) {\n    st->size = 0;\n    st->mtime = time(NULL);\n    st->exists = false;\n    st->regular_file = false;\n}\n\nzip_source_t *\nzip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error) {\n    zip_source_file_context_t *ctx;\n    zip_source_t *zs;\n    zip_source_file_stat_t sb;\n    zip_uint64_t length;\n\n    if (ops == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if (ops->close == NULL || ops->read == NULL || ops->seek == NULL || ops->stat == NULL) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n\n    if (ops->write != NULL && (ops->commit_write == NULL || ops->create_temp_output == NULL || ops->remove == NULL || ops->rollback_write == NULL || ops->tell == NULL)) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n\n    if (fname != NULL) {\n        if (ops->open == NULL || ops->string_duplicate == NULL) {\n            zip_error_set(error, ZIP_ER_INTERNAL, 0);\n            return NULL;\n        }\n    }\n    else if (file == NULL) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if (len < 0) {\n        if (len == -1) {\n            len = ZIP_LENGTH_TO_END;\n        }\n        // TODO: return ZIP_ER_INVAL if len != ZIP_LENGTH_UNCHECKED?\n        length = 0;\n    }\n    else {\n        length = (zip_uint64_t)len;\n    }\n\n    if (start > ZIP_INT64_MAX || start + length < start) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((ctx = (zip_source_file_context_t *)malloc(sizeof(zip_source_file_context_t))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    ctx->ops = ops;\n    ctx->ops_userdata = ops_userdata;\n    ctx->fname = NULL;\n    if (fname) {\n        if ((ctx->fname = ops->string_duplicate(ctx, fname)) == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            free(ctx);\n            return NULL;\n        }\n    }\n    ctx->f = file;\n    ctx->start = start;\n    ctx->len = length;\n    if (st) {\n        (void)memcpy_s(&ctx->st, sizeof(ctx->st), st, sizeof(*st));\n        ctx->st.name = NULL;\n        ctx->st.valid &= ~ZIP_STAT_NAME;\n    }\n    else {\n        zip_stat_init(&ctx->st);\n    }\n\n    if (ctx->len > 0) {\n        ctx->st.size = ctx->len;\n        ctx->st.valid |= ZIP_STAT_SIZE;\n    }\n\n    zip_error_init(&ctx->stat_error);\n\n    ctx->tmpname = NULL;\n    ctx->fout = NULL;\n\n    zip_error_init(&ctx->error);\n    zip_file_attributes_init(&ctx->attributes);\n\n    ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_SUPPORTS_REOPEN, -1);\n\n    zip_source_file_stat_init(&sb);\n    if (!ops->stat(ctx, &sb)) {\n        _zip_error_copy(error, &ctx->error);\n        free(ctx->fname);\n        free(ctx);\n        return NULL;\n    }\n\n    if (!sb.exists) {\n        if (ctx->fname && ctx->start == 0 && ctx->len == 0 && ops->write != NULL) {\n            ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;\n            /* zip_open_from_source checks for this to detect non-existing files */\n            zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT);\n        }\n        else {\n            zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT);\n            free(ctx->fname);\n            free(ctx);\n            return NULL;\n        }\n    }\n    else {\n        if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {\n            ctx->st.mtime = sb.mtime;\n            ctx->st.valid |= ZIP_STAT_MTIME;\n        }\n        if (sb.regular_file) {\n            ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;\n\n            if (ctx->start + ctx->len > sb.size) {\n                zip_error_set(error, ZIP_ER_INVAL, 0);\n                free(ctx->fname);\n                free(ctx);\n                return NULL;\n            }\n\n            if (ctx->len == 0) {\n                if (len != ZIP_LENGTH_UNCHECKED) {\n                    ctx->len = sb.size - ctx->start;\n                    ctx->st.size = ctx->len;\n                    ctx->st.valid |= ZIP_STAT_SIZE;\n                }\n\n                /* when using a partial file, don't allow writing */\n                if (ctx->fname && start == 0 && ops->write != NULL) {\n                    ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;\n                }\n            }\n        }\n\n        ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES);\n    }\n\n    ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY);\n    if (ops->create_temp_output_cloning != NULL) {\n        if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) {\n            ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING);\n        }\n    }\n\n    if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) {\n        free(ctx->fname);\n        free(ctx);\n        return NULL;\n    }\n\n    return zs;\n}\n\n\nstatic zip_int64_t\nread_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    zip_source_file_context_t *ctx;\n    char *buf;\n\n    ctx = (zip_source_file_context_t *)state;\n    buf = (char *)data;\n\n    switch (cmd) {\n    case ZIP_SOURCE_ACCEPT_EMPTY:\n        return 0;\n\n    case ZIP_SOURCE_BEGIN_WRITE:\n        /* write support should not be set if fname is NULL */\n        if (ctx->fname == NULL) {\n            zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n        return ctx->ops->create_temp_output(ctx);\n\n    case ZIP_SOURCE_BEGIN_WRITE_CLONING:\n        /* write support should not be set if fname is NULL */\n        if (ctx->fname == NULL) {\n            zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n        return ctx->ops->create_temp_output_cloning(ctx, len);\n\n    case ZIP_SOURCE_CLOSE:\n        if (ctx->fname) {\n            ctx->ops->close(ctx);\n            ctx->f = NULL;\n        }\n        return 0;\n\n    case ZIP_SOURCE_COMMIT_WRITE: {\n        zip_int64_t ret = ctx->ops->commit_write(ctx);\n        ctx->fout = NULL;\n        if (ret == 0) {\n            free(ctx->tmpname);\n            ctx->tmpname = NULL;\n        }\n        return ret;\n    }\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        free(ctx->fname);\n        free(ctx->tmpname);\n        if (ctx->f) {\n            ctx->ops->close(ctx);\n        }\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES:\n        if (len < sizeof(ctx->attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes));\n        return sizeof(ctx->attributes);\n\n    case ZIP_SOURCE_OPEN:\n        if (ctx->fname) {\n            if (ctx->ops->open(ctx) == false) {\n                return -1;\n            }\n        }\n\n        if (ctx->start > 0) { /* TODO: rewind on re-open */\n            if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)ctx->start, SEEK_SET) == false) {\n                /* TODO: skip by reading */\n                return -1;\n            }\n        }\n        ctx->offset = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ: {\n        zip_int64_t i;\n        zip_uint64_t n;\n\n        if (ctx->len > 0) {\n            n = ZIP_MIN(ctx->len - ctx->offset, len);\n        }\n        else {\n            n = len;\n        }\n\n        if ((i = ctx->ops->read(ctx, buf, n)) < 0) {\n            zip_error_set(&ctx->error, ZIP_ER_READ, errno);\n            return -1;\n        }\n        ctx->offset += (zip_uint64_t)i;\n\n        return i;\n    }\n\n    case ZIP_SOURCE_REMOVE:\n        return ctx->ops->remove(ctx);\n\n    case ZIP_SOURCE_ROLLBACK_WRITE:\n        ctx->ops->rollback_write(ctx);\n        ctx->fout = NULL;\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return 0;\n\n    case ZIP_SOURCE_SEEK: {\n        zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset, ctx->len, data, len, &ctx->error);\n\n        if (new_offset < 0) {\n            return -1;\n        }\n\n        /* The actual offset inside the file must be representable as zip_int64_t. */\n        if (new_offset > ZIP_INT64_MAX - (zip_int64_t)ctx->start) {\n            zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW);\n            return -1;\n        }\n\n        ctx->offset = (zip_uint64_t)new_offset;\n\n        if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)(ctx->offset + ctx->start), SEEK_SET) == false) {\n            return -1;\n        }\n        return 0;\n    }\n\n    case ZIP_SOURCE_SEEK_WRITE: {\n        zip_source_args_seek_t *args;\n\n        args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);\n        if (args == NULL) {\n            return -1;\n        }\n\n        if (ctx->ops->seek(ctx, ctx->fout, args->offset, args->whence) == false) {\n            return -1;\n        }\n        return 0;\n    }\n\n    case ZIP_SOURCE_STAT: {\n        if (len < sizeof(ctx->st))\n            return -1;\n\n        if (zip_error_code_zip(&ctx->stat_error) != 0) {\n            zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error));\n            return -1;\n        }\n\n        (void)memcpy_s(data, sizeof(ctx->st), &ctx->st, sizeof(ctx->st));\n        return sizeof(ctx->st);\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return ctx->supports;\n\n    case ZIP_SOURCE_TELL:\n        return (zip_int64_t)ctx->offset;\n\n    case ZIP_SOURCE_TELL_WRITE:\n        return ctx->ops->tell(ctx, ctx->fout);\n\n    case ZIP_SOURCE_WRITE:\n        return ctx->ops->write(ctx, data, len);\n\n    default:\n        zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_stdio.c",
    "content": "/*\n  zip_source_file_stdio.c -- read-only stdio file source implementation\n  Copyright (C) 2020-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include \"zip_source_file.h\"\n#include \"zip_source_file_stdio.h\"\n\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n#ifndef S_IWUSR\n#define S_IWUSR _S_IWRITE\n#endif\n#endif\n\n/* clang-format off */\nstatic zip_source_file_operations_t ops_stdio_read = {\n    _zip_stdio_op_close,\n    NULL,\n    NULL,\n    NULL,\n    NULL,\n    _zip_stdio_op_read,\n    NULL,\n    NULL,\n    _zip_stdio_op_seek,\n    _zip_stdio_op_stat,\n    NULL,\n    _zip_stdio_op_tell,\n    NULL\n};\n/* clang-format on */\n\n\nZIP_EXTERN zip_source_t *\nzip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL) {\n        return NULL;\n    }\n\n    return zip_source_filep_create(file, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (file == NULL || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    return zip_source_file_common_new(NULL, file, start, length, NULL, &ops_stdio_read, NULL, error);\n}\n\n\nvoid\n_zip_stdio_op_close(zip_source_file_context_t *ctx) {\n    fclose((FILE *)ctx->f);\n}\n\n\nzip_int64_t\n_zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) {\n    size_t i;\n#if SIZE_MAX < ZIP_UINT64_MAX\n    if (len > SIZE_MAX) {\n        len = SIZE_MAX;\n    }\n#endif\n\n    if ((i = fread(buf, 1, (size_t)len, ctx->f)) == 0) {\n        if (ferror((FILE *)ctx->f)) {\n            zip_error_set(&ctx->error, ZIP_ER_READ, errno);\n            return -1;\n        }\n    }\n\n    return (zip_int64_t)i;\n}\n\n\nbool\n_zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) {\n#if ZIP_FSEEK_MAX > ZIP_INT64_MAX\n    if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW);\n        return false;\n    }\n#endif\n\n    if (zip_os_fseek((FILE *)f, (zip_off_t)offset, whence) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);\n        return false;\n    }\n    return true;\n}\n\n\nbool\n_zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {\n    zip_os_stat_t sb;\n\n    int ret;\n\n    if (ctx->fname) {\n        ret = zip_os_stat(ctx->fname, &sb);\n    }\n    else {\n        ret = zip_os_fstat(fileno((FILE *)ctx->f), &sb);\n    }\n\n    if (ret < 0) {\n        if (errno == ENOENT) {\n            st->exists = false;\n            return true;\n        }\n        zip_error_set(&ctx->error, ZIP_ER_READ, errno);\n        return false;\n    }\n\n    st->size = (zip_uint64_t)sb.st_size;\n    st->mtime = sb.st_mtime;\n\n    st->regular_file = S_ISREG(sb.st_mode);\n    st->exists = true;\n\n    /* We're using UNIX file API, even on Windows; thus, we supply external file attributes with Unix values. */\n    /* TODO: This could be improved on Windows by providing Windows-specific file attributes */\n    ctx->attributes.valid = ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;\n    ctx->attributes.host_system = ZIP_OPSYS_UNIX;\n    ctx->attributes.external_file_attributes = (((zip_uint32_t)sb.st_mode) << 16) | ((sb.st_mode & S_IWUSR) ? 0 : 1);\n\n    return true;\n}\n\n\nzip_int64_t\n_zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f) {\n    zip_off_t offset = zip_os_ftell((FILE *)f);\n\n    if (offset < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);\n    }\n\n    return offset;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_stdio.h",
    "content": "#ifndef _HAD_ZIP_SOURCE_FILE_STDIO_H\n#define _HAD_ZIP_SOURCE_FILE_STDIO_H\n\n/*\n  zip_source_file_stdio.h -- common header for stdio file implementation\n  Copyright (C) 2020-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdio.h>\n\nvoid _zip_stdio_op_close(zip_source_file_context_t *ctx);\nzip_int64_t _zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);\nbool _zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);\nbool _zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);\nzip_int64_t _zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f);\n\n#endif /* _HAD_ZIP_SOURCE_FILE_STDIO_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_stdio_named.c",
    "content": "/*\n  zip_source_file_stdio_named.c -- source for stdio file opened by name\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include \"zip_source_file.h\"\n#include \"zip_source_file_stdio.h\"\n\n#include <fcntl.h>\n#include <stdlib.h>\n#include <sys/stat.h>\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#ifdef HAVE_CLONEFILE\n#include <sys/attr.h>\n#include <sys/clonefile.h>\n#define CAN_CLONE\n#endif\n#ifdef HAVE_FICLONERANGE\n#include <linux/fs.h>\n#include <sys/ioctl.h>\n#define CAN_CLONE\n#endif\n\nstatic int create_temp_file(zip_source_file_context_t *ctx, bool create_file);\n\nstatic zip_int64_t _zip_stdio_op_commit_write(zip_source_file_context_t *ctx);\nstatic zip_int64_t _zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx);\n#ifdef CAN_CLONE\nstatic zip_int64_t _zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset);\n#endif\nstatic bool _zip_stdio_op_open(zip_source_file_context_t *ctx);\nstatic zip_int64_t _zip_stdio_op_remove(zip_source_file_context_t *ctx);\nstatic void _zip_stdio_op_rollback_write(zip_source_file_context_t *ctx);\nstatic char *_zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string);\nstatic zip_int64_t _zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);\nstatic FILE *_zip_fopen_close_on_exec(const char *name, bool writeable);\n\n/* clang-format off */\nstatic zip_source_file_operations_t ops_stdio_named = {\n    _zip_stdio_op_close,\n    _zip_stdio_op_commit_write,\n    _zip_stdio_op_create_temp_output,\n#ifdef CAN_CLONE\n    _zip_stdio_op_create_temp_output_cloning,\n#else\n    NULL,\n#endif\n    _zip_stdio_op_open,\n    _zip_stdio_op_read,\n    _zip_stdio_op_remove,\n    _zip_stdio_op_rollback_write,\n    _zip_stdio_op_seek,\n    _zip_stdio_op_stat,\n    _zip_stdio_op_strdup,\n    _zip_stdio_op_tell,\n    _zip_stdio_op_write\n};\n/* clang-format on */\n\nZIP_EXTERN zip_source_t *\nzip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL)\n        return NULL;\n\n    return zip_source_file_create(fname, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    return zip_source_file_common_new(fname, NULL, start, length, NULL, &ops_stdio_named, NULL, error);\n}\n\n\nstatic zip_int64_t\n_zip_stdio_op_commit_write(zip_source_file_context_t *ctx) {\n    if (fclose(ctx->fout) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);\n        return -1;\n    }\n    if (rename(ctx->tmpname, ctx->fname) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nstatic zip_int64_t\n_zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx) {\n    int fd = create_temp_file(ctx, true);\n    \n    if (fd < 0) {\n        return -1;\n    }\n    \n    if ((ctx->fout = fdopen(fd, \"r+b\")) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n        close(fd);\n        (void)remove(ctx->tmpname);\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return -1;\n    }\n\n    return 0;\n}\n\n#ifdef CAN_CLONE\nstatic zip_int64_t\n_zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset) {\n    FILE *tfp;\n    \n    if (offset > ZIP_OFF_MAX) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);\n        return -1;\n    }\n    \n#ifdef HAVE_CLONEFILE\n    /* clonefile insists on creating the file, so just create a name */\n    if (create_temp_file(ctx, false) < 0) {\n        return -1;\n    }\n    \n    if (clonefile(ctx->fname, ctx->tmpname, 0) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return -1;\n    }\n    if ((tfp = _zip_fopen_close_on_exec(ctx->tmpname, true)) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n        (void)remove(ctx->tmpname);\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return -1;\n    }\n#else\n    {\n        int fd;\n        struct file_clone_range range;\n        zip_os_stat_t st;\n        \n        if (zip_os_fstat(fileno(ctx->f), &st) < 0) {\n            zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n            return -1;\n        }\n        \n        if ((fd = create_temp_file(ctx, true)) < 0) {\n            return -1;\n        }\n            \n        range.src_fd = fileno(ctx->f);\n        range.src_offset = 0;\n        range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize;\n        if (range.src_length > st.st_size) {\n            range.src_length = 0;\n        }\n        range.dest_offset = 0;\n        if (ioctl(fd, FICLONERANGE, &range) < 0) {\n            zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n            (void)close(fd);\n            (void)remove(ctx->tmpname);\n            free(ctx->tmpname);\n            ctx->tmpname = NULL;\n            return -1;\n        }\n\n        if ((tfp = fdopen(fd, \"r+b\")) == NULL) {\n            zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n            (void)close(fd);\n            (void)remove(ctx->tmpname);\n            free(ctx->tmpname);\n            ctx->tmpname = NULL;\n            return -1;\n        }\n    }\n#endif\n\n    if (ftruncate(fileno(tfp), (off_t)offset) < 0) {\n        (void)fclose(tfp);\n        (void)remove(ctx->tmpname);\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return -1;\n    }\n    if (zip_os_fseek(tfp, (zip_off_t)offset, SEEK_SET) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n        (void)fclose(tfp);\n        (void)remove(ctx->tmpname);\n        free(ctx->tmpname);\n        ctx->tmpname = NULL;\n        return -1;\n    }\n\n    ctx->fout = tfp;\n\n    return 0;\n}\n#endif\n\nstatic bool\n_zip_stdio_op_open(zip_source_file_context_t *ctx) {\n    if ((ctx->f = _zip_fopen_close_on_exec(ctx->fname, false)) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);\n        return false;\n    }\n    return true;\n}\n\n\nstatic zip_int64_t\n_zip_stdio_op_remove(zip_source_file_context_t *ctx) {\n    if (remove(ctx->fname) < 0) {\n        zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);\n        return -1;\n    }\n    return 0;\n}\n\n\nstatic void\n_zip_stdio_op_rollback_write(zip_source_file_context_t *ctx) {\n    if (ctx->fout) {\n        fclose(ctx->fout);\n    }\n    (void)remove(ctx->tmpname);\n}\n\nstatic char *\n_zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string) {\n    return strdup(string);\n}\n\n\nstatic zip_int64_t\n_zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {\n    size_t ret;\n\n    clearerr((FILE *)ctx->fout);\n    ret = fwrite(data, 1, len, (FILE *)ctx->fout);\n    if (ret != len || ferror((FILE *)ctx->fout)) {\n        zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);\n        return -1;\n    }\n\n    return (zip_int64_t)ret;\n}\n\n\nstatic int create_temp_file(zip_source_file_context_t *ctx, bool create_file) {\n    char *temp;\n    int mode;\n    zip_os_stat_t st;\n    int fd = 0;\n    char *start, *end;\n    \n    if (zip_os_stat(ctx->fname, &st) == 0) {\n        mode = st.st_mode;\n    }\n    else {\n        mode = -1;\n    }\n    \n    size_t temp_size = strlen(ctx->fname) + 13;\n    if ((temp = (char *)malloc(temp_size)) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n    snprintf_s(temp, temp_size, \"%s.XXXXXX.part\", ctx->fname);\n    end = temp + strlen(temp) - 5;\n    start = end - 6;\n    \n    for (;;) {\n        zip_uint32_t value = zip_random_uint32();\n        char *xs = start;\n        \n        while (xs < end) {\n            char digit = value % 36;\n            if (digit < 10) {\n                *(xs++) = digit + '0';\n            }\n            else {\n                *(xs++) = digit - 10 + 'a';\n            }\n            value /= 36;\n        }\n        \n        if (create_file) {\n            if ((fd = open(temp, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {\n                if (mode != -1) {\n                    /* open() honors umask(), which we don't want in this case */\n#ifdef HAVE_FCHMOD\n                    (void)fchmod(fd, (mode_t)mode);\n#else\n                    (void)chmod(temp, (mode_t)mode);\n#endif\n                }\n                break;\n            }\n            if (errno != EEXIST) {\n                zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n                free(temp);\n                return -1;\n            }\n        }\n        else {\n            if (zip_os_stat(temp, &st) < 0) {\n                if (errno == ENOENT) {\n                    break;\n                }\n                else {\n                    zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);\n                    free(temp);\n                    return -1;\n                }\n            }\n        }\n    }\n    \n    ctx->tmpname = temp;\n    \n    return fd; /* initialized to 0 if !create_file */\n}\n\n\n/*\n * fopen replacement that sets the close-on-exec flag\n * some implementations support an fopen 'e' flag for that,\n * but e.g. macOS doesn't.\n */\nstatic FILE *_zip_fopen_close_on_exec(const char *name, bool writeable) {\n    int fd;\n    int flags;\n    FILE *fp;\n\n    flags = O_CLOEXEC;\n    if (writeable) {\n        flags |= O_RDWR;\n    }\n    else {\n        flags |= O_RDONLY;\n    }\n\n    /* mode argument needed on Windows */\n    if ((fd = open(name, flags, 0666)) < 0) {\n        return NULL;\n    }\n    if ((fp = fdopen(fd, writeable ? \"r+b\" : \"rb\")) == NULL) {\n        return NULL;\n    }\n    return fp;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32.c",
    "content": "/*\n  zip_source_file_win32.c -- read-only Windows file source implementation\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip_source_file_win32.h\"\n\nstatic bool _zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);\n\nstatic bool _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h);\n\n/* clang-format off */\n\nstatic zip_source_file_operations_t ops_win32_read = {\n    _zip_win32_op_close,\n    NULL,\n    NULL,\n    NULL,\n    NULL,\n    _zip_win32_op_read,\n    NULL,\n    NULL,\n    _zip_win32_op_seek,\n    _zip_win32_op_stat,\n    NULL,\n    _zip_win32_op_tell,\n    NULL\n};\n\n/* clang-format on */\n\nZIP_EXTERN zip_source_t *\nzip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL) {\n        return NULL;\n    }\n\n    return zip_source_win32handle_create(h, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_win32handle_create(HANDLE h, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (h == INVALID_HANDLE_VALUE || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    return zip_source_file_common_new(NULL, h, start, length, NULL, &ops_win32_read, NULL, error);\n}\n\n\nvoid\n_zip_win32_op_close(zip_source_file_context_t *ctx) {\n    CloseHandle((HANDLE)ctx->f);\n}\n\n\nzip_int64_t\n_zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) {\n    DWORD i;\n\n    /* TODO: cap len to \"DWORD_MAX\" */\n    if (!ReadFile((HANDLE)ctx->f, buf, (DWORD)len, &i, NULL)) {\n        zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    return (zip_int64_t)i;\n}\n\n\nbool\n_zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) {\n    LARGE_INTEGER li;\n    DWORD method;\n\n    switch (whence) {\n    case SEEK_SET:\n        method = FILE_BEGIN;\n        break;\n    case SEEK_END:\n        method = FILE_END;\n        break;\n    case SEEK_CUR:\n        method = FILE_CURRENT;\n        break;\n    default:\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, EINVAL);\n        return false;\n    }\n\n    li.QuadPart = (LONGLONG)offset;\n    if (!SetFilePointerEx((HANDLE)f, li, NULL, method)) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic bool\n_zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {\n    return _zip_stat_win32(ctx, st, (HANDLE)ctx->f);\n}\n\n\nzip_int64_t\n_zip_win32_op_tell(zip_source_file_context_t *ctx, void *f) {\n    LARGE_INTEGER zero;\n    LARGE_INTEGER new_offset;\n\n    zero.QuadPart = 0;\n    if (!SetFilePointerEx((HANDLE)f, zero, &new_offset, FILE_CURRENT)) {\n        zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    return (zip_int64_t)new_offset.QuadPart;\n}\n\n\nint\n_zip_win32_error_to_errno(DWORD win32err) {\n    /* Note: This list isn't exhaustive, but should cover common cases. */\n    switch (win32err) {\n    case ERROR_INVALID_PARAMETER:\n        return EINVAL;\n    case ERROR_FILE_NOT_FOUND:\n    case ERROR_PATH_NOT_FOUND:\n        return ENOENT;\n    case ERROR_INVALID_HANDLE:\n        return EBADF;\n    case ERROR_ACCESS_DENIED:\n        return EACCES;\n    case ERROR_FILE_EXISTS:\n        return EEXIST;\n    case ERROR_TOO_MANY_OPEN_FILES:\n        return EMFILE;\n    case ERROR_DISK_FULL:\n        return ENOSPC;\n    default:\n        return 10000 + win32err;\n    }\n}\n\n\nstatic bool\n_zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) {\n    FILETIME mtimeft;\n    time_t mtime;\n    LARGE_INTEGER size;\n\n    if (!GetFileTime(h, NULL, NULL, &mtimeft)) {\n        zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));\n        return false;\n    }\n    if (!_zip_filetime_to_time_t(mtimeft, &mtime)) {\n        zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);\n        return false;\n    }\n\n    st->exists = true;\n    st->mtime = mtime;\n\n    if (GetFileType(h) == FILE_TYPE_DISK) {\n        st->regular_file = 1;\n\n        if (!GetFileSizeEx(h, &size)) {\n            zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));\n            return false;\n        }\n\n        st->size = (zip_uint64_t)size.QuadPart;\n    }\n\n    /* TODO: fill in ctx->attributes */\n\n    return true;\n}\n\n\nbool\n_zip_filetime_to_time_t(FILETIME ft, time_t *t) {\n    /*\n    Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux\n    */\n    const zip_int64_t WINDOWS_TICK = 10000000LL;\n    const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL;\n    ULARGE_INTEGER li;\n    zip_int64_t secs;\n    time_t temp;\n\n    li.LowPart = ft.dwLowDateTime;\n    li.HighPart = ft.dwHighDateTime;\n    secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);\n\n    temp = (time_t)secs;\n    if (secs != (zip_int64_t)temp) {\n        return false;\n    }\n\n    *t = temp;\n    return true;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32.h",
    "content": "#ifndef _HAD_ZIP_SOURCE_FILE_WIN32_H\n#define _HAD_ZIP_SOURCE_FILE_WIN32_H\n\n/*\n  zip_source_file_win32.h -- common header for Windows file implementation\n  Copyright (C) 2020-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/* 0x0501 => Windows XP; needs to be at least this value because of GetFileSizeEx */\n#if !defined(MS_UWP) && !defined(_WIN32_WINNT)\n#define _WIN32_WINNT 0x0501\n#endif\n\n#include <windows.h>\n\n#include <aclapi.h>\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n#include \"zip_source_file.h\"\n\nstruct zip_win32_file_operations {\n    char *(*allocate_tempname)(const char *name, size_t extra_chars, size_t *lengthp);\n    HANDLE(__stdcall *create_file)(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);\n    BOOL(__stdcall *delete_file)(const void *name);\n    DWORD(__stdcall *get_file_attributes)(const void *name);\n    BOOL(__stdcall *get_file_attributes_ex)(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information);\n    void (*make_tempname)(char *buf, size_t len, const char *name, zip_uint32_t i);\n    BOOL(__stdcall *move_file)(const void *from, const void *to, DWORD flags);\n    BOOL(__stdcall *set_file_attributes)(const void *name, DWORD attributes);\n    char *(*string_duplicate)(const char *string);\n    HANDLE(__stdcall *find_first_file)(const void *name, void *data);\n};\n\ntypedef struct zip_win32_file_operations zip_win32_file_operations_t;\n\nextern zip_source_file_operations_t _zip_source_file_win32_named_ops;\n\nvoid _zip_win32_op_close(zip_source_file_context_t *ctx);\nzip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);\nbool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);\nzip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f);\n\nbool _zip_filetime_to_time_t(FILETIME ft, time_t *t);\nint _zip_win32_error_to_errno(DWORD win32err);\n\n#endif /* _HAD_ZIP_SOURCE_FILE_WIN32_H */\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32_ansi.c",
    "content": "/*\n  zip_source_file_win32_ansi.c -- source for Windows file opened by ANSI name\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip_source_file_win32.h\"\n\nstatic char *ansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp);\nstatic HANDLE __stdcall ansi_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);\nstatic BOOL __stdcall ansi_delete_file(const void *name);\nstatic DWORD __stdcall ansi_get_file_attributes(const void *name);\nstatic BOOL __stdcall ansi_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information);\nstatic void ansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i);\nstatic BOOL __stdcall ansi_move_file(const void *from, const void *to, DWORD flags);\nstatic BOOL __stdcall ansi_set_file_attributes(const void *name, DWORD attributes);\nstatic HANDLE __stdcall ansi_find_first_file(const void *name, void* data);\n\n/* clang-format off */\nzip_win32_file_operations_t ops_ansi = {\n    ansi_allocate_tempname,\n    ansi_create_file,\n    ansi_delete_file,\n    ansi_get_file_attributes,\n    ansi_get_file_attributes_ex,\n    ansi_make_tempname,\n    ansi_move_file,\n    ansi_set_file_attributes,\n    strdup,\n    ansi_find_first_file,\n};\n/* clang-format on */\n\nZIP_EXTERN zip_source_t *\nzip_source_win32a(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL)\n        return NULL;\n\n    return zip_source_win32a_create(fname, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_win32a_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    return zip_source_file_common_new(fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_ansi, error);\n}\n\n\nstatic char *\nansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) {\n    *lengthp = strlen(name) + extra_chars;\n    return (char *)malloc(*lengthp);\n}\n\nstatic HANDLE __stdcall\nansi_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file)\n{\n    return CreateFileA((const char *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, template_file);\n}\n\nstatic BOOL __stdcall\nansi_delete_file(const void *name)\n{\n    return DeleteFileA((const char *)name);\n}\n\nstatic DWORD __stdcall\nansi_get_file_attributes(const void *name)\n{\n    return GetFileAttributesA((const char *)name);\n}\n\nstatic BOOL __stdcall\nansi_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information)\n{\n    return GetFileAttributesExA((const char *)name, info_level, information);\n}\n\nstatic void\nansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) {\n    snprintf_s(buf, len, \"%s.%08x\", name, i);\n}\n\nstatic BOOL __stdcall\nansi_move_file(const void *from, const void *to, DWORD flags)\n{\n    return MoveFileExA((const char *)from, (const char *)to, flags);\n}\n\nstatic BOOL __stdcall\nansi_set_file_attributes(const void *name, DWORD attributes)\n{\n    return SetFileAttributesA((const char *)name, attributes);\n}\n\nstatic HANDLE __stdcall\nansi_find_first_file(const void *name, void *data)\n{\n    return FindFirstFileA((const char *)name, data); \n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32_named.c",
    "content": "/*\n  zip_source_file_win32_named.c -- source for Windows file opened by name\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip_source_file_win32.h\"\n\nstatic zip_int64_t _zip_win32_named_op_commit_write(zip_source_file_context_t *ctx);\nstatic zip_int64_t _zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx);\nstatic bool _zip_win32_named_op_open(zip_source_file_context_t *ctx);\nstatic zip_int64_t _zip_win32_named_op_remove(zip_source_file_context_t *ctx);\nstatic void _zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx);\nstatic bool _zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);\nstatic char *_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string);\nstatic zip_int64_t _zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);\n\nstatic HANDLE win32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes);\n\n/* clang-format off */\nzip_source_file_operations_t _zip_source_file_win32_named_ops = {\n    _zip_win32_op_close,\n    _zip_win32_named_op_commit_write,\n    _zip_win32_named_op_create_temp_output,\n    NULL,\n    _zip_win32_named_op_open,\n    _zip_win32_op_read,\n    _zip_win32_named_op_remove,\n    _zip_win32_named_op_rollback_write,\n    _zip_win32_op_seek,\n    _zip_win32_named_op_stat,\n    _zip_win32_named_op_string_duplicate,\n    _zip_win32_op_tell,\n    _zip_win32_named_op_write\n};\n/* clang-format on */\n\nstatic zip_int64_t\n_zip_win32_named_op_commit_write(zip_source_file_context_t *ctx) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n    DWORD attributes;\n\n    if (!CloseHandle((HANDLE)ctx->fout)) {\n        zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    attributes = file_ops->get_file_attributes(ctx->tmpname);\n    if (attributes == INVALID_FILE_ATTRIBUTES) {\n        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    if (attributes & FILE_ATTRIBUTE_TEMPORARY) {\n        if (!file_ops->set_file_attributes(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {\n            zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));\n            return -1;\n        }\n    }\n\n    if (!file_ops->move_file(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {\n        zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    return 0;\n}\n\nstatic zip_int64_t\n_zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    zip_uint32_t value, i;\n    HANDLE th = INVALID_HANDLE_VALUE;\n    PSECURITY_ATTRIBUTES psa = NULL;\n    PSECURITY_DESCRIPTOR psd = NULL;\n#ifdef HAVE_GETSECURITYINFO\n    SECURITY_ATTRIBUTES sa;\n#endif\n    char *tempname = NULL;\n    size_t tempname_size = 0;\n\n#ifdef HAVE_GETSECURITYINFO\n    if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {\n        if (GetSecurityInfo((HANDLE)ctx->f, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd) == ERROR_SUCCESS) {\n            sa.nLength = sizeof(SECURITY_ATTRIBUTES);\n            sa.bInheritHandle = FALSE;\n            sa.lpSecurityDescriptor = psd;\n            psa = &sa;\n        }\n    }\n#endif\n\n#ifndef MS_UWP\n    value = GetTickCount();\n#else\n    value = (zip_uint32_t)(GetTickCount64() & 0xffffffff);\n#endif\n\n    if ((tempname = file_ops->allocate_tempname(ctx->fname, 10, &tempname_size)) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {\n        file_ops->make_tempname(tempname, tempname_size, ctx->fname, value + i);\n\n        th = win32_named_open(ctx, tempname, true, psa);\n        if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)\n            break;\n    }\n\n    if (th == INVALID_HANDLE_VALUE) {\n        free(tempname);\n        LocalFree(psd);\n        zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    LocalFree(psd);\n    ctx->fout = th;\n    ctx->tmpname = tempname;\n\n    return 0;\n}\n\n\nstatic bool\n_zip_win32_named_op_open(zip_source_file_context_t *ctx) {\n    HANDLE h = win32_named_open(ctx, ctx->fname, false, NULL);\n\n    if (h == INVALID_HANDLE_VALUE) {\n        return false;\n    }\n\n    ctx->f = h;\n    return true;\n}\n\n\nstatic zip_int64_t\n_zip_win32_named_op_remove(zip_source_file_context_t *ctx) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    if (!file_ops->delete_file(ctx->fname)) {\n        zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    return 0;\n}\n\n\nstatic void\n_zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    if (ctx->fout) {\n        CloseHandle((HANDLE)ctx->fout);\n    }\n    file_ops->delete_file(ctx->tmpname);\n}\n\n\nstatic bool\n_zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    WIN32_FILE_ATTRIBUTE_DATA file_attributes;\n\n    if (!file_ops->get_file_attributes_ex(ctx->fname, GetFileExInfoStandard, &file_attributes)) {\n        DWORD error = GetLastError();\n        if (error == ERROR_FILE_NOT_FOUND) {\n            st->exists = false;\n            return true;\n        }\n        zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(error));\n        return false;\n    }\n\n    st->exists = true;\n    st->regular_file = false;\n\n    if (file_attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES) {\n        if ((file_attributes.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0) {\n            if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {\n                WIN32_FIND_DATA find_data;\n                /* Deduplication on Windows replaces files with reparse points;\n\t\t * accept them as regular files. */\n                if (file_ops->find_first_file(ctx->fname, &find_data) != INVALID_HANDLE_VALUE) {\n                    st->regular_file = (find_data.dwReserved0 == IO_REPARSE_TAG_DEDUP);\n                }\n            }\n            else {\n                st->regular_file = true;\n            }\n        }\n    }\n\n    if (!_zip_filetime_to_time_t(file_attributes.ftLastWriteTime, &st->mtime)) {\n        zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);\n        return false;\n    }\n    st->size = ((zip_uint64_t)file_attributes.nFileSizeHigh << 32) | file_attributes.nFileSizeLow;\n\n    /* TODO: fill in ctx->attributes */\n\n    return true;\n}\n\n\nstatic char *\n_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    return file_ops->string_duplicate(string);\n}\n\n\nstatic zip_int64_t\n_zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {\n    DWORD ret;\n    if (!WriteFile((HANDLE)ctx->fout, data, (DWORD)len, &ret, NULL) || ret != len) {\n        zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));\n        return -1;\n    }\n\n    return (zip_int64_t)ret;\n}\n\n\nstatic HANDLE\nwin32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes) {\n    zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;\n\n    DWORD access = GENERIC_READ;\n    DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;\n    DWORD creation_disposition = OPEN_EXISTING;\n    DWORD file_attributes = FILE_ATTRIBUTE_NORMAL;\n    HANDLE h;\n\n    if (temporary) {\n        access = GENERIC_READ | GENERIC_WRITE;\n        share_mode = FILE_SHARE_READ;\n        creation_disposition = CREATE_NEW;\n        file_attributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY;\n    }\n\n    h = file_ops->create_file(name, access, share_mode, security_attributes, creation_disposition, file_attributes, NULL);\n\n    if (h == INVALID_HANDLE_VALUE) {\n        zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));\n    }\n\n    return h;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32_utf16.c",
    "content": "/*\n  zip_source_file_win32_utf16.c -- source for Windows file opened by UTF-16 name\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip_source_file_win32.h\"\n\nstatic char *utf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp);\nstatic HANDLE __stdcall utf16_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);\nstatic BOOL __stdcall utf16_delete_file(const void *name);\nstatic DWORD __stdcall utf16_get_file_attributes(const void *name);\nstatic BOOL __stdcall utf16_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information);\nstatic void utf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i);\nstatic BOOL __stdcall utf16_move_file(const void *from, const void *to, DWORD flags);\nstatic BOOL __stdcall utf16_set_file_attributes(const void *name, DWORD attributes);\nstatic char *utf16_strdup(const char *string);\nstatic HANDLE __stdcall utf16_find_first_file(const void *name, void* data);\n\n\n/* clang-format off */\nzip_win32_file_operations_t ops_utf16 = {\n    utf16_allocate_tempname,\n    utf16_create_file,\n    utf16_delete_file,\n    utf16_get_file_attributes,\n    utf16_get_file_attributes_ex,\n    utf16_make_tempname,\n    utf16_move_file,\n    utf16_set_file_attributes,\n    utf16_strdup,\n    utf16_find_first_file\n};\n/* clang-format on */\n\nZIP_EXTERN zip_source_t *\nzip_source_win32w(zip_t *za, const wchar_t *fname, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL)\n        return NULL;\n\n    return zip_source_win32w_create(fname, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_win32w_create(const wchar_t *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n\n    return zip_source_file_common_new((const char *)fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_utf16, error);\n}\n\n\nstatic char *\nutf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) {\n    *lengthp = wcslen((const wchar_t *)name) + extra_chars;\n    return (char *)malloc(*lengthp * sizeof(wchar_t));\n}\n\n\nstatic HANDLE __stdcall utf16_create_file(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) {\n#ifdef MS_UWP\n    CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};\n    extParams.dwFileAttributes = file_attributes;\n    extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS;\n    extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;\n    extParams.dwSize = sizeof(extParams);\n    extParams.hTemplateFile = template_file;\n    extParams.lpSecurityAttributes = security_attributes;\n\n    return CreateFile2((const wchar_t *)name, access, share_mode, creation_disposition, &extParams);\n#else\n    return CreateFileW((const wchar_t *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, template_file);\n#endif\n}\n\nstatic BOOL __stdcall\nutf16_delete_file(const void *name)\n{\n    return DeleteFileW((const wchar_t *)name);\n}\n\nstatic DWORD __stdcall\nutf16_get_file_attributes(const void *name)\n{\n    return GetFileAttributesW((const wchar_t *)name);\n}\n\nstatic BOOL __stdcall\nutf16_get_file_attributes_ex(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information)\n{\n    return GetFileAttributesExW((const wchar_t *)name, info_level, information);\n}\n\nstatic void\nutf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) {\n    _snwprintf_s((wchar_t *)buf, len, len, L\"%s.%08x\", (const wchar_t *)name, i);\n}\n\nstatic BOOL __stdcall\nutf16_move_file(const void *from, const void *to, DWORD flags)\n{\n    return MoveFileExW((const wchar_t *)from, (const wchar_t *)to, flags);\n}\n\nstatic BOOL __stdcall\nutf16_set_file_attributes(const void *name, DWORD attributes)\n{\n    return SetFileAttributesW((const wchar_t *)name, attributes);\n}\n\nstatic char *\nutf16_strdup(const char *string) {\n    return (char *)_wcsdup((const wchar_t *)string);\n}\n\n\nstatic HANDLE __stdcall\nutf16_find_first_file(const void *name, void* data)\n{\n    return FindFirstFileW((const wchar_t *)name, data);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_file_win32_utf8.c",
    "content": "/*\n  zip_source_file_win32_ansi.c -- source for Windows file opened by UTF-8 name\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip_source_file_win32.h\"\n\nZIP_EXTERN zip_source_t *\nzip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {\n    if (za == NULL) {\n        return NULL;\n    }\n\n    return zip_source_file_create(fname, start, len, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    int size;\n    wchar_t *wfname;\n    zip_source_t *source;\n\n    if (fname == NULL || length < ZIP_LENGTH_UNCHECKED) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    /* Convert fname from UTF-8 to Windows-friendly UTF-16. */\n    size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);\n    if (size == 0) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);\n\n    source = zip_source_win32w_create(wfname, start, length, error);\n\n    free(wfname);\n    return source;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_free.c",
    "content": "/*\n  zip_source_free.c -- free zip data source\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_source_free(zip_source_t *src) {\n    if (src == NULL)\n        return;\n\n    if (src->refcount > 0) {\n        src->refcount--;\n    }\n    if (src->refcount > 0) {\n        return;\n    }\n\n    if (ZIP_SOURCE_IS_OPEN_READING(src)) {\n        src->open_count = 1; /* force close */\n        zip_source_close(src);\n    }\n    if (ZIP_SOURCE_IS_OPEN_WRITING(src)) {\n        zip_source_rollback_write(src);\n    }\n\n    if (src->source_archive && !src->source_closed) {\n        _zip_deregister_source(src->source_archive, src);\n    }\n\n    (void)_zip_source_call(src, NULL, 0, ZIP_SOURCE_FREE);\n\n    if (src->src) {\n        zip_source_free(src->src);\n    }\n\n    free(src);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_function.c",
    "content": "/*\n  zip_source_function.c -- create zip data source from callback function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_source_t *\nzip_source_function(zip_t *za, zip_source_callback zcb, void *ud) {\n    if (za == NULL) {\n        return NULL;\n    }\n\n    return zip_source_function_create(zcb, ud, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *\nzip_source_function_create(zip_source_callback zcb, void *ud, zip_error_t *error) {\n    zip_source_t *zs;\n\n    if ((zs = _zip_source_new(error)) == NULL)\n        return NULL;\n\n    zs->cb.f = zcb;\n    zs->ud = ud;\n\n    zs->supports = zcb(ud, NULL, 0, ZIP_SOURCE_SUPPORTS);\n    if (zs->supports < 0) {\n        zs->supports = ZIP_SOURCE_SUPPORTS_READABLE;\n    }\n    zs->supports |= zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, -1);\n\n    return zs;\n}\n\n\nZIP_EXTERN void\nzip_source_keep(zip_source_t *src) {\n    src->refcount++;\n}\n\n\nzip_source_t *\n_zip_source_new(zip_error_t *error) {\n    zip_source_t *src;\n\n    if ((src = (zip_source_t *)malloc(sizeof(*src))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    src->src = NULL;\n    src->cb.f = NULL;\n    src->ud = NULL;\n    src->open_count = 0;\n    src->write_state = ZIP_SOURCE_WRITE_CLOSED;\n    src->source_closed = false;\n    src->source_archive = NULL;\n    src->refcount = 1;\n    zip_error_init(&src->error);\n    src->eof = false;\n    src->had_read_error = false;\n    src->bytes_read = 0;\n\n    return src;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_get_dostime.c",
    "content": "/*\n  zip_source_get_dostime.c -- get modification time in DOS format from source\n  Copyright (C) 2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n/* Returns -1 on error, 0 on no dostime available, 1 for dostime returned */\nint\nzip_source_get_dos_time(zip_source_t *src, zip_dostime_t *dos_time) {\n    if (src->source_closed) {\n        return -1;\n    }\n    if (dos_time == NULL) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) {\n        zip_error_set(&src->error, ZIP_ER_READ, ENOENT);\n    }\n\n    if (zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_DOS_TIME)) {\n        zip_int64_t n = _zip_source_call(src, dos_time, sizeof(*dos_time), ZIP_SOURCE_GET_DOS_TIME);\n\n        if (n < 0) {\n            return -1;\n        }\n        else if (n == 0) {\n            return 0;\n        }\n        else if (n == sizeof(*dos_time)) {\n            return 1;\n        }\n        else {\n            zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n    }\n    else {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_get_file_attributes.c",
    "content": "/*\n  zip_source_get_file_attributes.c -- get attributes for file from source\n  Copyright (C) 2020-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\nZIP_EXTERN void\nzip_file_attributes_init(zip_file_attributes_t *attributes) {\n    attributes->valid = 0;\n    attributes->version = 1;\n}\n\nint zip_source_get_file_attributes(zip_source_t *src, zip_file_attributes_t *attributes) {\n    if (src->source_closed) {\n        return -1;\n    }\n    if (attributes == NULL) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    zip_file_attributes_init(attributes);\n\n    if (src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES)) {\n        if (_zip_source_call(src, attributes, sizeof(*attributes), ZIP_SOURCE_GET_FILE_ATTRIBUTES) < 0) {\n            return -1;\n        }\n    }\n\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_file_attributes_t lower_attributes;\n\n        zip_file_attributes_init(&lower_attributes);\n\n        if (zip_source_get_file_attributes(src->src, &lower_attributes) < 0) {\n            zip_error_set_from_source(&src->error, src->src);\n            return -1;\n        }\n\n        if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) == 0) {\n            attributes->host_system = lower_attributes.host_system;\n            attributes->valid |= ZIP_FILE_ATTRIBUTES_HOST_SYSTEM;\n        }\n        if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_ASCII) && (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) == 0) {\n            attributes->ascii = lower_attributes.ascii;\n            attributes->valid |= ZIP_FILE_ATTRIBUTES_ASCII;\n        }\n        if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED)) {\n            if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {\n                attributes->version_needed = ZIP_MAX(lower_attributes.version_needed, attributes->version_needed);\n            }\n            else {\n                attributes->version_needed = lower_attributes.version_needed;\n                attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;\n            }\n        }\n        if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) == 0) {\n            attributes->external_file_attributes = lower_attributes.external_file_attributes;\n            attributes->valid |= ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;\n        }\n        if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS)) {\n            if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {\n\t\t/* only take from lower level what is not defined at current level */\n\t\tlower_attributes.general_purpose_bit_mask &= ~attributes->general_purpose_bit_mask;\n\n                attributes->general_purpose_bit_flags |= lower_attributes.general_purpose_bit_flags & lower_attributes.general_purpose_bit_mask;\n                attributes->general_purpose_bit_mask |= lower_attributes.general_purpose_bit_mask;\n            }\n            else {\n                attributes->valid |= ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;\n                attributes->general_purpose_bit_flags = lower_attributes.general_purpose_bit_flags;\n                attributes->general_purpose_bit_mask = lower_attributes.general_purpose_bit_mask;\n            }\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_is_deleted.c",
    "content": "/*\n  zip_source_is_deleted.c -- was archive was removed?\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_is_deleted(zip_source_t *src) {\n    return src->write_state == ZIP_SOURCE_WRITE_REMOVED;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_layered.c",
    "content": "/*\n  zip_source_layered.c -- create layered source\n  Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nzip_source_t *\nzip_source_layered(zip_t *za, zip_source_t *src, zip_source_layered_callback cb, void *ud) {\n    if (za == NULL)\n        return NULL;\n\n    return zip_source_layered_create(src, cb, ud, &za->error);\n}\n\n\nzip_source_t *\nzip_source_layered_create(zip_source_t *src, zip_source_layered_callback cb, void *ud, zip_error_t *error) {\n    zip_source_t *zs;\n    zip_int64_t lower_supports, supports;\n\n    lower_supports = zip_source_supports(src);\n    supports = cb(src, ud, &lower_supports, sizeof(lower_supports), ZIP_SOURCE_SUPPORTS);\n    if (supports < 0) {\n        zip_error_set(error,ZIP_ER_INVAL, 0); /* Initialize in case cb doesn't return valid error. */\n        cb(src, ud, error, sizeof(*error), ZIP_SOURCE_ERROR);\n        return NULL;\n    }\n\n    if ((zs = _zip_source_new(error)) == NULL) {\n        return NULL;\n    }\n\n    zs->src = src;\n    zs->cb.l = cb;\n    zs->ud = ud;\n    zs->supports = supports;\n\n    /* Layered sources can't support writing, since we currently have no use case. If we want to revisit this, we have to define how the two sources interact. */\n    zs->supports &= ~(ZIP_SOURCE_SUPPORTS_WRITABLE & ~ZIP_SOURCE_SUPPORTS_SEEKABLE);\n\n    return zs;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_open.c",
    "content": "/*\n  zip_source_open.c -- open zip_source (prepare for reading)\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\nZIP_EXTERN int\nzip_source_open(zip_source_t *src) {\n    if (src->source_closed) {\n        return -1;\n    }\n    if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) {\n        zip_error_set(&src->error, ZIP_ER_DELETED, 0);\n        return -1;\n    }\n\n    if (ZIP_SOURCE_IS_OPEN_READING(src)) {\n        if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) == 0) {\n            zip_error_set(&src->error, ZIP_ER_INUSE, 0);\n            return -1;\n        }\n    }\n    else {\n        if (ZIP_SOURCE_IS_LAYERED(src)) {\n            if (zip_source_open(src->src) < 0) {\n                zip_error_set_from_source(&src->error, src->src);\n                return -1;\n            }\n        }\n\n        if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) {\n            if (ZIP_SOURCE_IS_LAYERED(src)) {\n                zip_source_close(src->src);\n            }\n            return -1;\n        }\n    }\n\n    src->eof = false;\n    src->had_read_error = false;\n    _zip_error_clear(&src->error);\n    src->bytes_read = 0;\n    src->open_count++;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_pass_to_lower_layer.c",
    "content": "/*\n  zip_source_pass_to_lower_layer.c -- pass command to lower layer\n  Copyright (C) 2022-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\nzip_int64_t zip_source_pass_to_lower_layer(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command) {\n    switch (command) {\n    case ZIP_SOURCE_OPEN:\n    case ZIP_SOURCE_CLOSE:\n    case ZIP_SOURCE_FREE:\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES:\n    case ZIP_SOURCE_SUPPORTS_REOPEN:\n        return 0;\n\n    case ZIP_SOURCE_STAT:\n        return sizeof(zip_stat_t);\n\n    case ZIP_SOURCE_ACCEPT_EMPTY:\n    case ZIP_SOURCE_ERROR:\n    case ZIP_SOURCE_GET_DOS_TIME:\n    case ZIP_SOURCE_READ:\n    case ZIP_SOURCE_SEEK:\n    case ZIP_SOURCE_TELL:\n        return _zip_source_call(src, data, length, command);\n\n    case ZIP_SOURCE_BEGIN_WRITE:\n    case ZIP_SOURCE_BEGIN_WRITE_CLONING:\n    case ZIP_SOURCE_COMMIT_WRITE:\n    case ZIP_SOURCE_REMOVE:\n    case ZIP_SOURCE_ROLLBACK_WRITE:\n    case ZIP_SOURCE_SEEK_WRITE:\n    case ZIP_SOURCE_TELL_WRITE:\n    case ZIP_SOURCE_WRITE:\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n\n    case ZIP_SOURCE_SUPPORTS:\n        if (length < sizeof(zip_int64_t)) {\n            zip_error_set(&src->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n        return *(zip_int64_t *)data;\n\n    default:\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n}"
  },
  {
    "path": "external/libzip/lib/zip_source_pkware_decode.c",
    "content": "/*\n  zip_source_pkware_decode.c -- Traditional PKWARE decryption routines\n  Copyright (C) 2009-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\nstruct trad_pkware {\n    char *password;\n    zip_pkware_keys_t keys;\n    zip_error_t error;\n};\n\n\nstatic int decrypt_header(zip_source_t *, struct trad_pkware *);\nstatic zip_int64_t pkware_decrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);\nstatic struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);\nstatic void trad_pkware_free(struct trad_pkware *);\n\n\nzip_source_t *\nzip_source_pkware_decode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {\n    struct trad_pkware *ctx;\n    zip_source_t *s2;\n\n    if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    if (flags & ZIP_CODEC_ENCODE) {\n        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((ctx = trad_pkware_new(password, &za->error)) == NULL) {\n        return NULL;\n    }\n\n    if ((s2 = zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) {\n        trad_pkware_free(ctx);\n        return NULL;\n    }\n\n    return s2;\n}\n\n\nstatic int\ndecrypt_header(zip_source_t *src, struct trad_pkware *ctx) {\n    zip_uint8_t header[ZIP_CRYPTO_PKWARE_HEADERLEN];\n    zip_stat_t st;\n    zip_dostime_t dostime;\n    zip_int64_t n;\n\n    if ((n = zip_source_read(src, header, ZIP_CRYPTO_PKWARE_HEADERLEN)) < 0) {\n        zip_error_set_from_source(&ctx->error, src);\n        return -1;\n    }\n\n    if (n != ZIP_CRYPTO_PKWARE_HEADERLEN) {\n        zip_error_set(&ctx->error, ZIP_ER_EOF, 0);\n        return -1;\n    }\n\n    _zip_pkware_decrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN);\n\n    if (zip_source_stat(src, &st) < 0 || (st.valid & ZIP_STAT_CRC) == 0) {\n        /* skip password validation */\n        return 0;\n    }\n\n    if (zip_source_get_dos_time(src, &dostime) <= 0) {\n        if ((st.valid & ZIP_STAT_MTIME) == 0) {\n            /* no date available, skip password validation */\n            return 0;\n        }\n\n        if (_zip_u2d_time(st.mtime, &dostime, &ctx->error) < 0) {\n            return -1;\n        }\n    }\n\n    /*\n       password verification - two ways:\n       - mtime - InfoZIP way, to avoid computing complete CRC before encrypting data\n       - CRC - old PKWare way\n    */\n    if (header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == dostime.time >> 8\n        || header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == st.crc >> 24) {\n        return 0;\n    }\n    else {\n        zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);\n        return -1;\n    }\n}\n\n\nstatic zip_int64_t\npkware_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct trad_pkware *ctx;\n    zip_int64_t n;\n\n    ctx = (struct trad_pkware *)ud;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN:\n        _zip_pkware_keys_reset(&ctx->keys);\n        _zip_pkware_decrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password));\n        if (decrypt_header(src, ctx) < 0) {\n            return -1;\n        }\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if ((n = zip_source_read(src, data, len)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        _zip_pkware_decrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);\n        return n;\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n\n        st->encryption_method = ZIP_EM_NONE;\n        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;\n        if (st->valid & ZIP_STAT_COMP_SIZE) {\n            st->comp_size -= ZIP_CRYPTO_PKWARE_HEADERLEN;\n        }\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1);\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        trad_pkware_free(ctx);\n        return 0;\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, len, cmd);\n    }\n}\n\n\nstatic struct trad_pkware *\ntrad_pkware_new(const char *password, zip_error_t *error) {\n    struct trad_pkware *ctx;\n\n    if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->password = strdup(password)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        free(ctx);\n        return NULL;\n    }\n\n    zip_error_init(&ctx->error);\n\n    return ctx;\n}\n\n\nstatic void\ntrad_pkware_free(struct trad_pkware *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    free(ctx->password);\n    free(ctx);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_pkware_encode.c",
    "content": "/*\n  zip_source_pkware_encode.c -- Traditional PKWARE encryption routines\n  Copyright (C) 2009-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\nstruct trad_pkware {\n    char *password;\n    zip_pkware_keys_t keys;\n    zip_buffer_t *buffer;\n    bool eof;\n    zip_dostime_t dostime;\n    zip_error_t error;\n};\n\n\nstatic int encrypt_header(zip_source_t *, struct trad_pkware *);\nstatic zip_int64_t pkware_encrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);\nstatic void trad_pkware_free(struct trad_pkware *);\nstatic struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);\n\nzip_source_t *\nzip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {\n    struct trad_pkware *ctx;\n    zip_source_t *s2;\n\n    if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    if (!(flags & ZIP_CODEC_ENCODE)) {\n        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((ctx = trad_pkware_new(password, &za->error)) == NULL) {\n        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if (zip_source_get_dos_time(src, &ctx->dostime) <= 0) {\n        zip_stat_t st;\n\n        if (zip_source_stat(src, &st) < 0) {\n            zip_error_set_from_source(&za->error, src);\n            trad_pkware_free(ctx);\n            return NULL;\n        }\n        if (_zip_u2d_time((st.valid & ZIP_STAT_MTIME) ? st.mtime : time(NULL), &ctx->dostime, &za->error) < 0) {\n            trad_pkware_free(ctx);\n            return NULL;\n        }\n    }\n\n    if ((s2 = zip_source_layered(za, src, pkware_encrypt, ctx)) == NULL) {\n        trad_pkware_free(ctx);\n        return NULL;\n    }\n\n    return s2;\n}\n\n\nstatic int\nencrypt_header(zip_source_t *src, struct trad_pkware *ctx) {\n    zip_uint8_t *header;\n\n    if ((ctx->buffer = _zip_buffer_new(NULL, ZIP_CRYPTO_PKWARE_HEADERLEN)) == NULL) {\n        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    header = _zip_buffer_data(ctx->buffer);\n\n    /* generate header from random bytes and mtime\n       see appnote.iz, XIII. Decryption, Step 2, last paragraph */\n    if (!zip_secure_random(header, ZIP_CRYPTO_PKWARE_HEADERLEN - 1)) {\n        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n        _zip_buffer_free(ctx->buffer);\n        ctx->buffer = NULL;\n        return -1;\n    }\n    header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] = (zip_uint8_t)((ctx->dostime.time >> 8) & 0xff);\n\n    _zip_pkware_encrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN);\n\n    return 0;\n}\n\n\nstatic zip_int64_t\npkware_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) {\n    struct trad_pkware *ctx;\n    zip_int64_t n;\n    zip_uint64_t buffer_n;\n\n    ctx = (struct trad_pkware *)ud;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN:\n        ctx->eof = false;\n\n        /* initialize keys */\n        _zip_pkware_keys_reset(&ctx->keys);\n        _zip_pkware_encrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password));\n\n        if (encrypt_header(src, ctx) < 0) {\n            return -1;\n        }\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        buffer_n = 0;\n\n        if (ctx->buffer) {\n            /* write header values to data */\n            buffer_n = _zip_buffer_read(ctx->buffer, data, length);\n            data = (zip_uint8_t *)data + buffer_n;\n            length -= buffer_n;\n\n            if (_zip_buffer_eof(ctx->buffer)) {\n                _zip_buffer_free(ctx->buffer);\n                ctx->buffer = NULL;\n            }\n        }\n\n        if (ctx->eof) {\n            return (zip_int64_t)buffer_n;\n        }\n\n        if ((n = zip_source_read(src, data, length)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        _zip_pkware_encrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);\n\n        if ((zip_uint64_t)n < length) {\n            ctx->eof = true;\n        }\n\n        return (zip_int64_t)buffer_n + n;\n\n    case ZIP_SOURCE_CLOSE:\n        _zip_buffer_free(ctx->buffer);\n        ctx->buffer = NULL;\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n        st->encryption_method = ZIP_EM_TRAD_PKWARE;\n        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;\n        if (st->valid & ZIP_STAT_COMP_SIZE) {\n            st->comp_size += ZIP_CRYPTO_PKWARE_HEADERLEN;\n        }\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {\n        zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;\n        if (length < sizeof(*attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;\n        attributes->version_needed = 20;\n        attributes->general_purpose_bit_flags = ZIP_GPBF_DATA_DESCRIPTOR;\n        attributes->general_purpose_bit_mask = ZIP_GPBF_DATA_DESCRIPTOR;\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_GET_DOS_TIME:\n        if (length < sizeof(ctx->dostime)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        (void)memcpy_s(data, sizeof(ctx->dostime), &ctx->dostime, sizeof(ctx->dostime));\n        return sizeof(ctx->dostime);\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_GET_DOS_TIME, -1);\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, length);\n\n    case ZIP_SOURCE_FREE:\n        trad_pkware_free(ctx);\n        return 0;\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, length, cmd);\n    }\n}\n\n\nstatic struct trad_pkware *\ntrad_pkware_new(const char *password, zip_error_t *error) {\n    struct trad_pkware *ctx;\n\n    if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->password = strdup(password)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        free(ctx);\n        return NULL;\n    }\n    ctx->buffer = NULL;\n    zip_error_init(&ctx->error);\n\n    return ctx;\n}\n\n\nstatic void\ntrad_pkware_free(struct trad_pkware *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    free(ctx->password);\n    _zip_buffer_free(ctx->buffer);\n    zip_error_fini(&ctx->error);\n    free(ctx);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_read.c",
    "content": "/*\n  zip_source_read.c -- read data from zip_source\n  Copyright (C) 2009-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nzip_int64_t\nzip_source_read(zip_source_t *src, void *data, zip_uint64_t len) {\n    zip_uint64_t bytes_read;\n    zip_int64_t n;\n\n    if (src->source_closed) {\n        return -1;\n    }\n    if (!ZIP_SOURCE_IS_OPEN_READING(src) || len > ZIP_INT64_MAX || (len > 0 && data == NULL)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (src->had_read_error) {\n        return -1;\n    }\n\n    if (_zip_source_eof(src)) {\n        return 0;\n    }\n\n    if (len == 0) {\n        return 0;\n    }\n\n    bytes_read = 0;\n    while (bytes_read < len) {\n        if ((n = _zip_source_call(src, (zip_uint8_t *)data + bytes_read, len - bytes_read, ZIP_SOURCE_READ)) < 0) {\n            src->had_read_error = true;\n            if (bytes_read == 0) {\n                return -1;\n            }\n            else {\n                return (zip_int64_t)bytes_read;\n            }\n        }\n\n        if (n == 0) {\n            src->eof = 1;\n            break;\n        }\n\n        bytes_read += (zip_uint64_t)n;\n    }\n\n    if (src->bytes_read + bytes_read < src->bytes_read) {\n        src->bytes_read = ZIP_UINT64_MAX;\n    }\n    else {\n        src->bytes_read += bytes_read;\n    }\n    return (zip_int64_t)bytes_read;\n}\n\n\nbool\n_zip_source_eof(zip_source_t *src) {\n    return src->eof;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_remove.c",
    "content": "/*\n zip_source_remove.c -- remove empty archive\n Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n\n#include \"zipint.h\"\n\n\nint\nzip_source_remove(zip_source_t *src) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) {\n        return 0;\n    }\n\n    if (ZIP_SOURCE_IS_OPEN_READING(src)) {\n        if (zip_source_close(src) < 0) {\n            return -1;\n        }\n    }\n    if (src->write_state != ZIP_SOURCE_WRITE_CLOSED) {\n        zip_source_rollback_write(src);\n    }\n\n    if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_REMOVE) < 0) {\n        return -1;\n    }\n\n    src->write_state = ZIP_SOURCE_WRITE_REMOVED;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_rollback_write.c",
    "content": "/*\n  zip_source_rollback_write.c -- discard changes\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_source_rollback_write(zip_source_t *src) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        return;\n    }\n\n    if (src->write_state != ZIP_SOURCE_WRITE_OPEN && src->write_state != ZIP_SOURCE_WRITE_FAILED) {\n        return;\n    }\n\n    _zip_source_call(src, NULL, 0, ZIP_SOURCE_ROLLBACK_WRITE);\n    src->write_state = ZIP_SOURCE_WRITE_CLOSED;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_seek.c",
    "content": "/*\n  zip_source_seek.c -- seek to offset\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_seek(zip_source_t *src, zip_int64_t offset, int whence) {\n    zip_source_args_seek_t args;\n\n    if (src->source_closed) {\n        return -1;\n    }\n    if (!ZIP_SOURCE_IS_OPEN_READING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    args.offset = offset;\n    args.whence = whence;\n\n    if (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK) < 0) {\n        return -1;\n    }\n\n    src->eof = 0;\n    return 0;\n}\n\n\nzip_int64_t\nzip_source_seek_compute_offset(zip_uint64_t offset, zip_uint64_t length, void *data, zip_uint64_t data_length, zip_error_t *error) {\n    zip_int64_t new_offset;\n    zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, data_length, error);\n\n    if (args == NULL) {\n        return -1;\n    }\n\n    switch (args->whence) {\n    case SEEK_CUR:\n        new_offset = (zip_int64_t)offset + args->offset;\n        break;\n\n    case SEEK_END:\n        new_offset = (zip_int64_t)length + args->offset;\n        break;\n\n    case SEEK_SET:\n        new_offset = args->offset;\n        break;\n\n    default:\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (new_offset < 0 || (zip_uint64_t)new_offset > length) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    return new_offset;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_seek_write.c",
    "content": "/*\n  zip_source_seek_write.c -- seek to offset for writing\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_seek_write(zip_source_t *src, zip_int64_t offset, int whence) {\n    zip_source_args_seek_t args;\n\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    args.offset = offset;\n    args.whence = whence;\n\n    return (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK_WRITE) < 0 ? -1 : 0);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_stat.c",
    "content": "/*\n  zip_source_stat.c -- get meta information from zip_source\n  Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_source_stat(zip_source_t *src, zip_stat_t *st) {\n    if (src->source_closed) {\n        return -1;\n    }\n    if (st == NULL) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) {\n        zip_error_set(&src->error, ZIP_ER_READ, ENOENT);\n    }\n\n    zip_stat_init(st);\n\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        if (zip_source_stat(src->src, st) < 0) {\n            zip_error_set_from_source(&src->error, src->src);\n            return -1;\n        }\n    }\n\n    if (_zip_source_call(src, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) {\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_supports.c",
    "content": "/*\n  zip_source_supports.c -- check for supported functions\n  Copyright (C) 2014-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdarg.h>\n\n#include \"zipint.h\"\n\n\nzip_int64_t\nzip_source_supports(zip_source_t *src) {\n    return src->supports;\n}\n\nbool\nzip_source_supports_reopen(zip_source_t *src) {\n    return (zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SUPPORTS_REOPEN)) != 0;\n}\n\nZIP_EXTERN zip_int64_t\nzip_source_make_command_bitmap(zip_source_cmd_t cmd0, ...) {\n    zip_int64_t bitmap;\n    va_list ap;\n\n    bitmap = ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd0);\n\n\n    va_start(ap, cmd0);\n    for (;;) {\n        int cmd = va_arg(ap, int);\n        if (cmd < 0) {\n            break;\n        }\n        bitmap |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(cmd);\n    }\n    va_end(ap);\n\n    return bitmap;\n}\n\n\nZIP_EXTERN int zip_source_is_seekable(zip_source_t *src) {\n    return ZIP_SOURCE_CHECK_SUPPORTED(zip_source_supports(src->src), ZIP_SOURCE_SEEK);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_tell.c",
    "content": "/*\n  zip_source_tell.c -- report current offset\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_source_tell(zip_source_t *src) {\n    if (src->source_closed) {\n        return -1;\n    }\n    if (!ZIP_SOURCE_IS_OPEN_READING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    if ((src->supports & (ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_TELL) | ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK))) == 0) {\n        if (src->bytes_read > ZIP_INT64_MAX) {\n            zip_error_set(&src->error, ZIP_ER_TELL, EOVERFLOW);\n            return -1;\n        }\n        return (zip_int64_t)src->bytes_read;\n    }\n\n    return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_tell_write.c",
    "content": "/*\n  zip_source_tell_write.c -- report current offset for writing\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_source_tell_write(zip_source_t *src) {\n    if (ZIP_SOURCE_IS_LAYERED(src)) {\n        zip_error_set(&src->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n\n    if (!ZIP_SOURCE_IS_OPEN_WRITING(src)) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    return _zip_source_call(src, NULL, 0, ZIP_SOURCE_TELL_WRITE);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_window.c",
    "content": "/*\n  zip_source_window.c -- return part of lower source\n  Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n\nstruct window {\n    zip_uint64_t start; /* where in file we start reading */\n    zip_uint64_t end;   /* where in file we stop reading */\n    bool end_valid;     /* whether end is set, otherwise read until EOF */\n\n    /* if not NULL, read file data for this file */\n    zip_t *source_archive;\n    zip_uint64_t source_index;\n\n    zip_uint64_t offset; /* offset in src for next read */\n\n    zip_stat_t stat;\n    zip_uint64_t stat_invalid;\n    zip_file_attributes_t attributes;\n    zip_dostime_t dostime;\n    bool dostime_valid;\n    zip_error_t error;\n    zip_int64_t supports;\n    bool needs_seek;\n};\n\nstatic zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);\n\n\nZIP_EXTERN zip_source_t *\nzip_source_window_create(zip_source_t *src, zip_uint64_t start, zip_int64_t len, zip_error_t *error) {\n    return _zip_source_window_new(src, start, len, NULL, 0, NULL, NULL, NULL, 0, false, error);\n}\n\n\nzip_source_t *\n_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_dostime_t *dostime, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error) {\n    zip_source_t* window_source;\n    struct window *ctx;\n\n    if (src == NULL || length < -1 || (source_archive == NULL && source_index != 0)) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    \n    if (length >= 0) {\n        if (start + (zip_uint64_t)length < start) {\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n    }\n\n    if ((ctx = (struct window *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    ctx->start = start;\n    if (length == -1) {\n        ctx->end_valid = false;\n    }\n    else {\n        ctx->end = start + (zip_uint64_t)length;\n        ctx->end_valid = true;\n    }\n    zip_stat_init(&ctx->stat);\n    ctx->stat_invalid = st_invalid;\n    if (attributes != NULL) {\n        (void)memcpy_s(&ctx->attributes, sizeof(ctx->attributes), attributes, sizeof(ctx->attributes));\n    }\n    else {\n        zip_file_attributes_init(&ctx->attributes);\n    }\n    if (dostime != NULL) {\n        ctx->dostime = *dostime;\n        ctx->dostime_valid = true;\n    }\n    else {\n        ctx->dostime_valid = false;\n    }\n    ctx->source_archive = source_archive;\n    ctx->source_index = source_index;\n    zip_error_init(&ctx->error);\n    ctx->supports = (zip_source_supports(src) & (ZIP_SOURCE_SUPPORTS_SEEKABLE | ZIP_SOURCE_SUPPORTS_REOPEN)) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_GET_DOS_TIME, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, ZIP_SOURCE_FREE, -1));\n    ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;\n\n    if (st) {\n        if (_zip_stat_merge(&ctx->stat, st, error) < 0) {\n            free(ctx);\n            return NULL;\n        }\n    }\n    \n    window_source = zip_source_layered_create(src, window_read, ctx, error);\n    if (window_source != NULL && !take_ownership) {\n        zip_source_keep(src);\n    }\n    return window_source;\n}\n\n\nint\n_zip_source_set_source_archive(zip_source_t *src, zip_t *za) {\n    src->source_archive = za;\n    return _zip_register_source(za, src);\n}\n\n\n/* called by zip_discard to avoid operating on file from closed archive */\nvoid\n_zip_source_invalidate(zip_source_t *src) {\n    src->source_closed = 1;\n\n    if (zip_error_code_zip(&src->error) == ZIP_ER_OK) {\n        zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0);\n    }\n}\n\n\nstatic zip_int64_t\nwindow_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct window *ctx;\n    zip_int64_t ret;\n    zip_uint64_t n, i;\n\n    ctx = (struct window *)_ctx;\n\n    switch (cmd) {\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_OPEN:\n        if (ctx->source_archive) {\n            zip_uint64_t offset;\n\n            if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) {\n                return -1;\n            }\n            if (ctx->end + offset < ctx->end) {\n                /* zip archive data claims end of data past zip64 limits */\n                zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, ctx->source_index));\n                return -1;\n            }\n            ctx->start += offset;\n            ctx->end += offset;\n            ctx->source_archive = NULL;\n        }\n\n        if (!ctx->needs_seek) {\n            DEFINE_BYTE_ARRAY(b, BUFSIZE);\n\n            if (!byte_array_init(b, BUFSIZE)) {\n                zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n\n            for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) {\n                i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n);\n                if ((ret = zip_source_read(src, b, i)) < 0) {\n                    zip_error_set_from_source(&ctx->error, src);\n                    byte_array_fini(b);\n                    return -1;\n                }\n                if (ret == 0) {\n                    zip_error_set(&ctx->error, ZIP_ER_EOF, 0);\n                    byte_array_fini(b);\n                    return -1;\n                }\n            }\n\n            byte_array_fini(b);\n        }\n\n        ctx->offset = ctx->start;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if (ctx->end_valid && len > ctx->end - ctx->offset) {\n            len = ctx->end - ctx->offset;\n        }\n\n        if (len == 0) {\n            return 0;\n        }\n\n        if (ctx->needs_seek) {\n            if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {\n                zip_error_set_from_source(&ctx->error, src);\n                return -1;\n            }\n        }\n\n        if ((ret = zip_source_read(src, data, len)) < 0) {\n            zip_error_set(&ctx->error, ZIP_ER_EOF, 0);\n            return -1;\n        }\n\n        ctx->offset += (zip_uint64_t)ret;\n\n        if (ret == 0) {\n            if (ctx->end_valid && ctx->offset < ctx->end) {\n                zip_error_set(&ctx->error, ZIP_ER_EOF, 0);\n                return -1;\n            }\n        }\n        return ret;\n\n    case ZIP_SOURCE_SEEK: {\n        zip_int64_t new_offset;\n        \n        if (!ctx->end_valid) {\n            zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);\n            \n            if (args == NULL) {\n                return -1;\n            }\n            if (args->whence == SEEK_END) {\n                if (zip_source_seek(src, args->offset, args->whence) < 0) {\n                    zip_error_set_from_source(&ctx->error, src);\n                    return -1;\n                }\n                new_offset = zip_source_tell(src);\n                if (new_offset < 0) {\n                    zip_error_set_from_source(&ctx->error, src);\n                    return -1;\n                }\n                if ((zip_uint64_t)new_offset < ctx->start) {\n                    zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n                    (void)zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET);\n                    return -1;\n                }\n                ctx->offset = (zip_uint64_t)new_offset;\n                return 0;\n            }\n        }\n\n        new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);\n        \n        if (new_offset < 0) {\n            return -1;\n        }\n        \n        ctx->offset = (zip_uint64_t)new_offset + ctx->start;\n        return 0;\n    }\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n\n        if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {\n            return -1;\n        }\n\n        if (!(ctx->stat.valid & ZIP_STAT_SIZE)) {\n            if (ctx->end_valid) {\n                st->valid |= ZIP_STAT_SIZE;\n                st->size = ctx->end - ctx->start;\n            }\n            else if (st->valid & ZIP_STAT_SIZE) {\n                st->size -= ctx->start;\n            }\n        }\n\n        st->valid &= ~ctx->stat_invalid;\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES:\n        if (len < sizeof(ctx->attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n\n        (void)memcpy_s(data, sizeof(ctx->attributes), &ctx->attributes, sizeof(ctx->attributes));\n        return sizeof(ctx->attributes);\n\n    case ZIP_SOURCE_GET_DOS_TIME:\n        if (len < sizeof(ctx->dostime)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        if (ctx->dostime_valid) {\n            (void)memcpy_s(data, sizeof(ctx->dostime), &ctx->dostime, sizeof(ctx->dostime));\n            return sizeof(ctx->dostime);\n        }\n        else {\n            return 0;\n        }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return ctx->supports;\n\n    case ZIP_SOURCE_TELL:\n        return (zip_int64_t)(ctx->offset - ctx->start);\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, len, cmd);\n    }\n}\n\n\nvoid\n_zip_deregister_source(zip_t *za, zip_source_t *src) {\n    zip_uint64_t i;\n\n    for (i = 0; i < za->nopen_source; i++) {\n        if (za->open_source[i] == src) {\n            za->open_source[i] = za->open_source[za->nopen_source - 1];\n            za->nopen_source--;\n            break;\n        }\n    }\n}\n\n\nint\n_zip_register_source(zip_t *za, zip_source_t *src) {\n    if (za->nopen_source + 1 >= za->nopen_source_alloc) {\n        if (!ZIP_REALLOC(za->open_source, za->nopen_source_alloc, 10, &za->error)) {\n            return -1;\n        }\n    }\n\n    za->open_source[za->nopen_source++] = src;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_winzip_aes_decode.c",
    "content": "/*\n  zip_source_winzip_aes_decode.c -- Winzip AES decryption routines\n  Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n#include \"zip_crypto.h\"\n\nstruct winzip_aes {\n    char *password;\n    zip_uint16_t encryption_method;\n\n    zip_uint64_t data_length;\n    zip_uint64_t current_position;\n\n    zip_winzip_aes_t *aes_ctx;\n    zip_error_t error;\n};\n\n\nstatic int decrypt_header(zip_source_t *src, struct winzip_aes *ctx);\nstatic void winzip_aes_free(struct winzip_aes *);\nstatic zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);\nstatic struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error);\n\n\nzip_source_t *\nzip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) {\n    zip_source_t *s2;\n    zip_stat_t st;\n    zip_uint64_t aux_length;\n    struct winzip_aes *ctx;\n\n    if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    if (flags & ZIP_CODEC_ENCODE) {\n        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);\n        return NULL;\n    }\n\n    if (zip_source_stat(src, &st) != 0) {\n        zip_error_set_from_source(&za->error, src);\n        return NULL;\n    }\n\n    aux_length = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(encryption_method) + HMAC_LENGTH;\n\n    if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) {\n        zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) {\n        return NULL;\n    }\n\n    ctx->data_length = st.comp_size - aux_length;\n\n    if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) {\n        winzip_aes_free(ctx);\n        return NULL;\n    }\n\n    return s2;\n}\n\n\nstatic int\ndecrypt_header(zip_source_t *src, struct winzip_aes *ctx) {\n    zip_uint8_t header[WINZIP_AES_MAX_HEADER_LENGTH];\n    zip_uint8_t password_verification[WINZIP_AES_PASSWORD_VERIFY_LENGTH];\n    unsigned int headerlen;\n    zip_int64_t n;\n\n    headerlen = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method);\n    if ((n = zip_source_read(src, header, headerlen)) < 0) {\n        zip_error_set_from_source(&ctx->error, src);\n        return -1;\n    }\n\n    if (n != headerlen) {\n        zip_error_set(&ctx->error, ZIP_ER_EOF, 0);\n        return -1;\n    }\n\n    if ((ctx->aes_ctx = _zip_winzip_aes_new((zip_uint8_t *)ctx->password, strlen(ctx->password), header, ctx->encryption_method, password_verification, &ctx->error)) == NULL) {\n        return -1;\n    }\n    if (memcmp(password_verification, header + SALT_LENGTH(ctx->encryption_method), WINZIP_AES_PASSWORD_VERIFY_LENGTH) != 0) {\n        _zip_winzip_aes_free(ctx->aes_ctx);\n        ctx->aes_ctx = NULL;\n        zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);\n        return -1;\n    }\n    return 0;\n}\n\n\nstatic bool\nverify_hmac(zip_source_t *src, struct winzip_aes *ctx) {\n    unsigned char computed[ZIP_CRYPTO_SHA1_LENGTH], from_file[HMAC_LENGTH];\n    if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) {\n        zip_error_set_from_source(&ctx->error, src);\n        return false;\n    }\n\n    if (!_zip_winzip_aes_finish(ctx->aes_ctx, computed)) {\n        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n        return false;\n    }\n    _zip_winzip_aes_free(ctx->aes_ctx);\n    ctx->aes_ctx = NULL;\n\n    if (memcmp(from_file, computed, HMAC_LENGTH) != 0) {\n        zip_error_set(&ctx->error, ZIP_ER_CRC, 0);\n        return false;\n    }\n\n    return true;\n}\n\n\nstatic zip_int64_t\nwinzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {\n    struct winzip_aes *ctx;\n    zip_int64_t n;\n\n    ctx = (struct winzip_aes *)ud;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN:\n        if (decrypt_header(src, ctx) < 0) {\n            return -1;\n        }\n        ctx->current_position = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if (len > ctx->data_length - ctx->current_position) {\n            len = ctx->data_length - ctx->current_position;\n        }\n\n        if (len == 0) {\n            if (!verify_hmac(src, ctx)) {\n                return -1;\n            }\n            return 0;\n        }\n\n        if ((n = zip_source_read(src, data, len)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n        ctx->current_position += (zip_uint64_t)n;\n\n        if (!_zip_winzip_aes_decrypt(ctx->aes_ctx, (zip_uint8_t *)data, (zip_uint64_t)n)) {\n            zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n            return -1;\n        }\n\n        return n;\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n\n        st->encryption_method = ZIP_EM_NONE;\n        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;\n        if (st->valid & ZIP_STAT_COMP_SIZE) {\n            st->comp_size -= 12 + SALT_LENGTH(ctx->encryption_method);\n        }\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1);\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, len);\n\n    case ZIP_SOURCE_FREE:\n        winzip_aes_free(ctx);\n        return 0;\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, len, cmd);\n    }\n}\n\n\nstatic void\nwinzip_aes_free(struct winzip_aes *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    _zip_crypto_clear(ctx->password, strlen(ctx->password));\n    free(ctx->password);\n    zip_error_fini(&ctx->error);\n    _zip_winzip_aes_free(ctx->aes_ctx);\n    free(ctx);\n}\n\n\nstatic struct winzip_aes *\nwinzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) {\n    struct winzip_aes *ctx;\n\n    if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->password = strdup(password)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        free(ctx);\n        return NULL;\n    }\n\n    ctx->encryption_method = encryption_method;\n    ctx->aes_ctx = NULL;\n\n    zip_error_init(&ctx->error);\n\n    return ctx;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_winzip_aes_encode.c",
    "content": "/*\n  zip_source_winzip_aes_encode.c -- Winzip AES encryption routines\n  Copyright (C) 2009-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zipint.h\"\n#include \"zip_crypto.h\"\n\nstruct winzip_aes {\n    char *password;\n    zip_uint16_t encryption_method;\n\n    zip_uint8_t data[ZIP_MAX(WINZIP_AES_MAX_HEADER_LENGTH, ZIP_CRYPTO_SHA1_LENGTH)];\n    zip_buffer_t *buffer;\n\n    zip_winzip_aes_t *aes_ctx;\n    bool eof;\n    zip_error_t error;\n};\n\n\nstatic int encrypt_header(zip_source_t *src, struct winzip_aes *ctx);\nstatic void winzip_aes_free(struct winzip_aes *);\nstatic zip_int64_t winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);\nstatic struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error);\n\n\nzip_source_t *\nzip_source_winzip_aes_encode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) {\n    zip_source_t *s2;\n    struct winzip_aes *ctx;\n\n    if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) {\n        return NULL;\n    }\n\n    if ((s2 = zip_source_layered(za, src, winzip_aes_encrypt, ctx)) == NULL) {\n        winzip_aes_free(ctx);\n        return NULL;\n    }\n\n    return s2;\n}\n\n\nstatic int\nencrypt_header(zip_source_t *src, struct winzip_aes *ctx) {\n    zip_uint16_t salt_length = SALT_LENGTH(ctx->encryption_method);\n    if (!zip_secure_random(ctx->data, salt_length)) {\n        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n        return -1;\n    }\n\n    if ((ctx->aes_ctx = _zip_winzip_aes_new((zip_uint8_t *)ctx->password, strlen(ctx->password), ctx->data, ctx->encryption_method, ctx->data + salt_length, &ctx->error)) == NULL) {\n        return -1;\n    }\n\n    if ((ctx->buffer = _zip_buffer_new(ctx->data, salt_length + WINZIP_AES_PASSWORD_VERIFY_LENGTH)) == NULL) {\n        _zip_winzip_aes_free(ctx->aes_ctx);\n        ctx->aes_ctx = NULL;\n        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nstatic zip_int64_t\nwinzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) {\n    struct winzip_aes *ctx;\n    zip_int64_t ret;\n    zip_uint64_t buffer_n;\n\n    ctx = (struct winzip_aes *)ud;\n\n    switch (cmd) {\n    case ZIP_SOURCE_OPEN:\n        ctx->eof = false;\n        if (encrypt_header(src, ctx) < 0) {\n            return -1;\n        }\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        buffer_n = 0;\n\n        if (ctx->buffer) {\n            buffer_n = _zip_buffer_read(ctx->buffer, data, length);\n\n            data = (zip_uint8_t *)data + buffer_n;\n            length -= buffer_n;\n\n            if (_zip_buffer_eof(ctx->buffer)) {\n                _zip_buffer_free(ctx->buffer);\n                ctx->buffer = NULL;\n            }\n        }\n\n        if (ctx->eof) {\n            return (zip_int64_t)buffer_n;\n        }\n\n        if ((ret = zip_source_read(src, data, length)) < 0) {\n            zip_error_set_from_source(&ctx->error, src);\n            return -1;\n        }\n\n        if (!_zip_winzip_aes_encrypt(ctx->aes_ctx, data, (zip_uint64_t)ret)) {\n            zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n            /* TODO: return partial read? */\n            return -1;\n        }\n\n        if ((zip_uint64_t)ret < length) {\n            ctx->eof = true;\n            if (!_zip_winzip_aes_finish(ctx->aes_ctx, ctx->data)) {\n                zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);\n                /* TODO: return partial read? */\n                return -1;\n            }\n            _zip_winzip_aes_free(ctx->aes_ctx);\n            ctx->aes_ctx = NULL;\n            if ((ctx->buffer = _zip_buffer_new(ctx->data, HMAC_LENGTH)) == NULL) {\n                zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);\n                /* TODO: return partial read? */\n                return -1;\n            }\n            buffer_n += _zip_buffer_read(ctx->buffer, (zip_uint8_t *)data + ret, length - (zip_uint64_t)ret);\n        }\n\n        return (zip_int64_t)(buffer_n + (zip_uint64_t)ret);\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st;\n\n        st = (zip_stat_t *)data;\n        st->encryption_method = ctx->encryption_method;\n        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;\n        if (st->valid & ZIP_STAT_COMP_SIZE) {\n            st->comp_size += 12 + SALT_LENGTH(ctx->encryption_method);\n        }\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {\n        zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;\n        if (length < sizeof(*attributes)) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;\n        attributes->version_needed = 51;\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, length);\n\n    case ZIP_SOURCE_FREE:\n        winzip_aes_free(ctx);\n        return 0;\n\n    default:\n        return zip_source_pass_to_lower_layer(src, data, length, cmd);\n    }\n}\n\n\nstatic void\nwinzip_aes_free(struct winzip_aes *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    _zip_crypto_clear(ctx->password, strlen(ctx->password));\n    free(ctx->password);\n    zip_error_fini(&ctx->error);\n    _zip_buffer_free(ctx->buffer);\n    _zip_winzip_aes_free(ctx->aes_ctx);\n    free(ctx);\n}\n\n\nstatic struct winzip_aes *\nwinzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) {\n    struct winzip_aes *ctx;\n\n    if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->password = strdup(password)) == NULL) {\n        free(ctx);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    ctx->encryption_method = encryption_method;\n    ctx->buffer = NULL;\n    ctx->aes_ctx = NULL;\n\n    zip_error_init(&ctx->error);\n\n    ctx->eof = false;\n    return ctx;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_write.c",
    "content": "/*\n  zip_source_write.c -- start a new file for writing\n  Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN zip_int64_t\nzip_source_write(zip_source_t *src, const void *data, zip_uint64_t length) {\n    if (!ZIP_SOURCE_IS_OPEN_WRITING(src) || length > ZIP_INT64_MAX) {\n        zip_error_set(&src->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    return _zip_source_call(src, (void *)data, length, ZIP_SOURCE_WRITE);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_zip.c",
    "content": "/*\n  zip_source_zip.c -- create data source from zip file\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#define _ZIP_COMPILING_DEPRECATED\n#include \"zipint.h\"\n\nZIP_EXTERN zip_source_t *zip_source_zip_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, zip_error_t *error) {\n    if (len < -1) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n    \n    if (len == 0) {\n        len = -1;\n    }\n    \n    if (start == 0 && len == -1) {\n        flags |= ZIP_FL_COMPRESSED;\n    }\n    else {\n        flags &= ~ZIP_FL_COMPRESSED;\n    }\n\n    return zip_source_zip_file_create(srcza, srcidx, flags, start, len, NULL, error);\n}\n\n\nZIP_EXTERN zip_source_t *zip_source_zip(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len) {\n    return zip_source_zip_create(srcza, srcidx, flags, start, len, &za->error);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_source_zip_new.c",
    "content": "/*\n  zip_source_zip_new.c -- prepare data structures for zip_fopen/zip_source_zip\n  Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\nstatic void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de);\n\nZIP_EXTERN zip_source_t *zip_source_zip_file(zip_t* za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password) {\n    return zip_source_zip_file_create(srcza, srcidx, flags, start, len, password, &za->error);\n}\n\n\nZIP_EXTERN zip_source_t *zip_source_zip_file_create(zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_int64_t len, const char *password, zip_error_t *error) {\n    /* TODO: We need to make sure that the returned source is invalidated when srcza is closed. */\n    zip_source_t *src, *s2;\n    zip_stat_t st;\n    zip_file_attributes_t attributes;\n    zip_dirent_t *de;\n    bool partial_data, needs_crc, encrypted, needs_decrypt, compressed, needs_decompress, changed_data, have_size, have_comp_size;\n    zip_flags_t stat_flags;\n    zip_int64_t data_len;\n    bool take_ownership = false;\n    bool empty_data = false;\n\n    if (srcza == NULL || srcidx >= srcza->nentry || len < -1) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if (flags & ZIP_FL_ENCRYPTED) {\n        flags |= ZIP_FL_COMPRESSED;\n    }\n\n    changed_data = false;\n    if ((flags & ZIP_FL_UNCHANGED) == 0) {\n        zip_entry_t *entry = srcza->entry + srcidx;\n        if (ZIP_ENTRY_DATA_CHANGED(entry)) {\n            if ((flags & ZIP_FL_COMPRESSED) || !zip_source_supports_reopen(entry->source)) {\n                zip_error_set(error, ZIP_ER_CHANGED, 0);\n                return NULL;\n            }\n\n            changed_data = true;\n        }\n        else if (entry->deleted) {\n            zip_error_set(error, ZIP_ER_CHANGED, 0);\n            return NULL;\n        }\n    }\n\n    stat_flags = flags;\n    if (!changed_data) {\n        stat_flags |= ZIP_FL_UNCHANGED;\n    }\n\n    if (zip_stat_index(srcza, srcidx, stat_flags, &st) < 0) {\n        zip_error_set(error, ZIP_ER_INTERNAL, 0);\n        return NULL;\n    }\n\n    if ((start > 0 || len >= 0) && (flags & ZIP_FL_COMPRESSED)) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    have_size = (st.valid & ZIP_STAT_SIZE) != 0;\n    /* overflow or past end of file */\n    if (len >= 0 && ((start > 0 && start + len < start) || (have_size && start + len > st.size))) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if (len == -1) {\n        if (have_size) {\n            if (st.size - start > ZIP_INT64_MAX) {\n                zip_error_set(error, ZIP_ER_INVAL, 0);\n                return NULL;\n            }\n            data_len = (zip_int64_t)(st.size - start);\n        }\n        else {\n            data_len = -1;\n        }\n    }\n    else {\n           data_len = len;\n    }\n\n    if (have_size) {\n        partial_data = (zip_uint64_t)(data_len) < st.size;\n    }\n    else {\n        partial_data = true;\n    }\n    encrypted = (st.valid & ZIP_STAT_ENCRYPTION_METHOD) && (st.encryption_method != ZIP_EM_NONE);\n    needs_decrypt = ((flags & ZIP_FL_ENCRYPTED) == 0) && encrypted;\n    compressed = (st.valid & ZIP_STAT_COMP_METHOD) && (st.comp_method != ZIP_CM_STORE);\n    needs_decompress = ((flags & ZIP_FL_COMPRESSED) == 0) && compressed;\n    /* when reading the whole file, check for CRC errors */\n    needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || !compressed) && !partial_data && (st.valid & ZIP_STAT_CRC) != 0;\n\n    if (needs_decrypt) {\n        if (password == NULL) {\n            password = srcza->default_password;\n        }\n        if (password == NULL) {\n            zip_error_set(error, ZIP_ER_NOPASSWD, 0);\n            return NULL;\n        }\n    }\n\n    if ((de = _zip_get_dirent(srcza, srcidx, flags, error)) == NULL) {\n        return NULL;\n    }\n    _zip_file_attributes_from_dirent(&attributes, de);\n\n    have_comp_size = (st.valid & ZIP_STAT_COMP_SIZE) != 0;\n    if (needs_decrypt || needs_decompress) {\n        empty_data = (have_comp_size && st.comp_size == 0);\n    }\n    else {\n        empty_data = (have_size && st.size == 0);\n    }\n    if (empty_data) {\n        src = zip_source_buffer_with_attributes_create(NULL, 0, 0, &attributes, error);\n    }\n    else {\n        src = NULL;\n    }\n\n\n    /* If we created source buffer above, we want the window source to take ownership of it. */\n    take_ownership = src != NULL;\n    /* if we created a buffer source above, then treat it as if\n       reading the changed data - that way we don't need add another\n       special case to the code below that wraps it in the window\n       source */\n    changed_data = changed_data || (src != NULL);\n\n    if (partial_data && !needs_decrypt && !needs_decompress) {\n        struct zip_stat st2;\n        zip_t *source_archive;\n        zip_uint64_t source_index;\n\n        if (changed_data) {\n            if (src == NULL) {\n                src = srcza->entry[srcidx].source;\n            }\n            source_archive = NULL;\n            source_index = 0;\n        }\n        else {\n            src = srcza->src;\n            source_archive = srcza;\n            source_index = srcidx;\n        }\n\n        st2.comp_method = ZIP_CM_STORE;\n        st2.valid = ZIP_STAT_COMP_METHOD;\n        if (data_len >= 0) {\n            st2.size = (zip_uint64_t)data_len;\n            st2.comp_size = (zip_uint64_t)data_len;\n            st2.valid |= ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE;\n        }\n        if (st.valid & ZIP_STAT_MTIME) {\n            st2.mtime = st.mtime;\n            st2.valid |= ZIP_STAT_MTIME;\n        }\n\n        if ((src = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, &attributes, &de->last_mod, source_archive, source_index, take_ownership, error)) == NULL) {\n            return NULL;\n        }\n    }\n    /* here we restrict src to file data, so no point in doing it for\n       source that already represents only the file data */\n    else if (!changed_data) {\n        /* this branch is executed only for archive sources; we know\n           that stat data come from the archive too, so it's safe to\n           assume that st has a comp_size specified */\n        if (st.comp_size > ZIP_INT64_MAX) {\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n        /* despite the fact that we want the whole data file, we still\n           wrap the source into a window source to add st and\n           attributes and to have a source that positions the read\n           offset properly before each read for multiple zip_file_t\n           referring to the same underlying source */\n        if ((src =  _zip_source_window_new(srcza->src, 0, (zip_int64_t)st.comp_size, &st, ZIP_STAT_NAME, &attributes, &de->last_mod, srcza, srcidx, take_ownership, error)) == NULL) {\n            return NULL;\n        }\n    }\n    else {\n        /* this branch gets executed when reading the whole changed\n           data file or when \"reading\" from a zero-sized source buffer\n           that we created above */\n        if (src == NULL) {\n            src = srcza->entry[srcidx].source;\n        }\n        /* despite the fact that we want the whole data file, we still\n           wrap the source into a window source to add st and\n           attributes and to have a source that positions the read\n           offset properly before each read for multiple zip_file_t\n           referring to the same underlying source */\n        if ((src = _zip_source_window_new(src, 0, data_len, &st, ZIP_STAT_NAME, &attributes, &de->last_mod, NULL, 0, take_ownership, error)) == NULL) {\n            return NULL;\n        }\n    }\n\n    /* In all cases, src is a window source and therefore is owned by this function. */\n\n    if (_zip_source_set_source_archive(src, srcza) < 0) {\n        zip_source_free(src);\n        return NULL;\n    }\n\n    /* creating a layered source calls zip_keep() on the lower layer, so we free it */\n\n    if (needs_decrypt) {\n        zip_encryption_implementation enc_impl;\n\n        if ((enc_impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {\n            zip_source_free(src);\n            zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);\n            return NULL;\n        }\n\n        s2 = enc_impl(srcza, src, st.encryption_method, 0, password);\n        if (s2 == NULL) {\n            zip_source_free(src);\n            return NULL;\n        }\n\n        src = s2;\n    }\n    if (needs_decompress) {\n        s2 = zip_source_decompress(srcza, src, st.comp_method);\n        if (s2 == NULL) {\n            zip_source_free(src);\n            return NULL;\n        }\n        src = s2;\n    }\n    if (needs_crc) {\n        s2 = zip_source_crc_create(src, 1, error);\n        if (s2 == NULL) {\n            zip_source_free(src);\n            return NULL;\n        }\n        src = s2;\n    }\n\n    if (partial_data && (needs_decrypt || needs_decompress)) {\n        zip_stat_t st2;\n        zip_stat_init(&st2);\n        if (data_len >= 0) {\n            st2.valid = ZIP_STAT_SIZE;\n            st2.size = (zip_uint64_t)data_len;\n        }\n        s2 = _zip_source_window_new(src, start, data_len, &st2, ZIP_STAT_NAME, NULL, NULL, NULL, 0, true, error);\n        if (s2 == NULL) {\n            zip_source_free(src);\n            return NULL;\n        }\n        src = s2;\n    }\n\n    return src;\n}\n\nstatic void\n_zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de) {\n    zip_file_attributes_init(attributes);\n    attributes->valid = ZIP_FILE_ATTRIBUTES_ASCII | ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;\n    attributes->ascii = de->int_attrib & 1;\n    attributes->host_system = de->version_madeby >> 8;\n    attributes->external_file_attributes = de->ext_attrib;\n    attributes->general_purpose_bit_flags = de->bitflags;\n    attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_stat.c",
    "content": "/*\n  zip_stat.c -- get information about file by name\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_stat(zip_t *za, const char *fname, zip_flags_t flags, zip_stat_t *st) {\n    zip_int64_t idx;\n\n    if ((idx = zip_name_locate(za, fname, flags)) < 0)\n        return -1;\n\n    return zip_stat_index(za, (zip_uint64_t)idx, flags, st);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_stat_index.c",
    "content": "/*\n  zip_stat_index.c -- get information about file by index\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) {\n    const char *name;\n    zip_dirent_t *de;\n    zip_entry_t *entry;\n\n    if ((de = _zip_get_dirent(za, index, flags, NULL)) == NULL) {\n        return -1;\n    }\n\n    if ((name = zip_get_name(za, index, flags)) == NULL) {\n        return -1;\n    }\n\n    entry = za->entry + index;\n\n    if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry + index)) {\n\n        if (zip_source_stat(entry->source, st) < 0) {\n            zip_error_set(&za->error, ZIP_ER_CHANGED, 0);\n            return -1;\n        }\n\n        if (ZIP_CM_IS_DEFAULT(de->comp_method)) {\n            if (!(st->valid & ZIP_STAT_COMP_METHOD) || st->comp_method == ZIP_CM_STORE) {\n                st->valid &= ~(ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD);\n            }\n        }\n        else {\n            if ((st->valid & ZIP_STAT_COMP_METHOD) && st->comp_method != de->comp_method) {\n                st->valid &= ~ZIP_STAT_COMP_SIZE;\n            }\n            st->valid |= ZIP_STAT_COMP_METHOD;\n            st->comp_method = de->comp_method;\n        }\n\n        if (((st->valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) == (ZIP_STAT_COMP_METHOD|ZIP_STAT_SIZE)) && st->comp_method == ZIP_CM_STORE) {\n            st->valid |= ZIP_STAT_COMP_SIZE;\n            st->comp_size = st->size;\n        }\n\n        if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_LAST_MOD) {\n            st->mtime = zip_dirent_get_last_mod_mtime(de);\n            st->valid |= ZIP_STAT_MTIME;\n        }\n    }\n    else {\n        zip_stat_init(st);\n\n        st->crc = de->crc;\n        st->size = de->uncomp_size;\n        st->mtime = zip_dirent_get_last_mod_mtime(de);\n        st->comp_size = de->comp_size;\n        st->comp_method = (zip_uint16_t)de->comp_method;\n        st->encryption_method = de->encryption_method;\n        st->valid = (de->crc_valid ? ZIP_STAT_CRC : 0) | ZIP_STAT_SIZE | ZIP_STAT_MTIME | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;\n        if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_COMP_METHOD) {\n            st->valid &= ~ZIP_STAT_COMP_SIZE;\n        }\n    }\n\n    if ((za->ch_flags & ZIP_AFL_WANT_TORRENTZIP) && (flags & ZIP_FL_UNCHANGED) == 0) {\n        if (za->torrent_mtime == 0) {\n            zip_dostime_t dostime = {0xbc00, 0x2198};\n            za->torrent_mtime = _zip_d2u_time(&dostime);\n        }\n        st->comp_method = ZIP_CM_DEFLATE;\n        st->mtime = za->torrent_mtime;\n        st->valid |= ZIP_STAT_MTIME | ZIP_STAT_COMP_METHOD;\n        st->valid &= ~ZIP_STAT_COMP_SIZE;\n    }\n\n    st->index = index;\n    st->name = name;\n    st->valid |= ZIP_STAT_INDEX | ZIP_STAT_NAME;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_stat_init.c",
    "content": "/*\n  zip_stat_init.c -- initialize struct zip_stat.\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <string.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN void\nzip_stat_init(zip_stat_t *st) {\n    st->valid = 0;\n    st->name = NULL;\n    st->index = ZIP_UINT64_MAX;\n    st->crc = 0;\n    st->mtime = (time_t)-1;\n    st->size = 0;\n    st->comp_size = 0;\n    st->comp_method = ZIP_CM_STORE;\n    st->encryption_method = ZIP_EM_NONE;\n}\n\n\nint\n_zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error) {\n    /* name is not merged, since zip_stat_t doesn't own it, and src may not be valid as long as dst */\n    if (src->valid & ZIP_STAT_INDEX) {\n        dst->index = src->index;\n    }\n    if (src->valid & ZIP_STAT_SIZE) {\n        dst->size = src->size;\n    }\n    if (src->valid & ZIP_STAT_COMP_SIZE) {\n        dst->comp_size = src->comp_size;\n    }\n    if (src->valid & ZIP_STAT_MTIME) {\n        dst->mtime = src->mtime;\n    }\n    if (src->valid & ZIP_STAT_CRC) {\n        dst->crc = src->crc;\n    }\n    if (src->valid & ZIP_STAT_COMP_METHOD) {\n        dst->comp_method = src->comp_method;\n    }\n    if (src->valid & ZIP_STAT_ENCRYPTION_METHOD) {\n        dst->encryption_method = src->encryption_method;\n    }\n    if (src->valid & ZIP_STAT_FLAGS) {\n        dst->flags = src->flags;\n    }\n    dst->valid |= src->valid;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_strerror.c",
    "content": "/*\n  zip_sterror.c -- get string representation of zip error\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN const char *\nzip_strerror(zip_t *za) {\n    return zip_error_strerror(&za->error);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_string.c",
    "content": "/*\n  zip_string.c -- string handling (with encoding)\n  Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n\n#include \"zipint.h\"\n\nzip_uint32_t\n_zip_string_crc32(const zip_string_t *s) {\n    zip_uint32_t crc;\n\n    crc = (zip_uint32_t)crc32(0L, Z_NULL, 0);\n\n    if (s != NULL)\n        crc = (zip_uint32_t)crc32(crc, s->raw, s->length);\n\n    return crc;\n}\n\n\nint\n_zip_string_equal(const zip_string_t *a, const zip_string_t *b) {\n    if (a == NULL || b == NULL)\n        return a == b;\n\n    if (a->length != b->length)\n        return 0;\n\n    /* TODO: encoding */\n\n    return (memcmp(a->raw, b->raw, a->length) == 0);\n}\n\n\nvoid\n_zip_string_free(zip_string_t *s) {\n    if (s == NULL)\n        return;\n\n    free(s->raw);\n    free(s->converted);\n    free(s);\n}\n\n\nconst zip_uint8_t *\n_zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error) {\n    static const zip_uint8_t empty[1] = \"\";\n\n    if (string == NULL) {\n        if (lenp)\n            *lenp = 0;\n        return empty;\n    }\n\n    if ((flags & ZIP_FL_ENC_RAW) == 0) {\n        /* start guessing */\n        if (string->encoding == ZIP_ENCODING_UNKNOWN) {\n            /* guess encoding, sets string->encoding */\n            (void)_zip_guess_encoding(string, ZIP_ENCODING_UNKNOWN);\n        }\n\n        if (((flags & ZIP_FL_ENC_STRICT) && string->encoding != ZIP_ENCODING_ASCII && string->encoding != ZIP_ENCODING_UTF8_KNOWN) || (string->encoding == ZIP_ENCODING_CP437)) {\n            if (string->converted == NULL) {\n                if ((string->converted = _zip_cp437_to_utf8(string->raw, string->length, &string->converted_length, error)) == NULL)\n                    return NULL;\n            }\n            if (lenp)\n                *lenp = string->converted_length;\n            return string->converted;\n        }\n    }\n\n    if (lenp)\n        *lenp = string->length;\n    return string->raw;\n}\n\nbool _zip_string_is_ascii(const zip_string_t *string) {\n    if (string->encoding != ZIP_ENCODING_ASCII) {\n        zip_uint16_t i;\n\n        for (i = 0; i < string->length; i++) {\n            if (string->raw[i] & 0x80) {\n                return false;\n            }\n        }\n    }\n\n    return true;\n}\n\n\nzip_uint16_t\n_zip_string_length(const zip_string_t *s) {\n    if (s == NULL)\n        return 0;\n\n    return s->length;\n}\n\n\nzip_string_t *\n_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error) {\n    zip_string_t *s;\n    zip_encoding_type_t expected_encoding;\n\n    if (length == 0)\n        return NULL;\n\n    switch (flags & ZIP_FL_ENCODING_ALL) {\n    case ZIP_FL_ENC_GUESS:\n        expected_encoding = ZIP_ENCODING_UNKNOWN;\n        break;\n    case ZIP_FL_ENC_UTF_8:\n        expected_encoding = ZIP_ENCODING_UTF8_KNOWN;\n        break;\n    case ZIP_FL_ENC_CP437:\n        expected_encoding = ZIP_ENCODING_CP437;\n        break;\n    default:\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    if ((s = (zip_string_t *)malloc(sizeof(*s))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((s->raw = (zip_uint8_t *)malloc((size_t)length + 1)) == NULL) {\n        free(s);\n        return NULL;\n    }\n\n    (void)memcpy_s(s->raw, length + 1, raw, length);\n    s->raw[length] = '\\0';\n    s->length = length;\n    s->encoding = ZIP_ENCODING_UNKNOWN;\n    s->converted = NULL;\n    s->converted_length = 0;\n\n    if (expected_encoding != ZIP_ENCODING_UNKNOWN) {\n        if (_zip_guess_encoding(s, expected_encoding) == ZIP_ENCODING_ERROR) {\n            _zip_string_free(s);\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n    }\n\n    return s;\n}\n\n\nint\n_zip_string_write(zip_t *za, const zip_string_t *s) {\n    if (s == NULL)\n        return 0;\n\n    return _zip_write(za, s->raw, s->length);\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_unchange.c",
    "content": "/*\n  zip_unchange.c -- undo changes to file in zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_unchange(zip_t *za, zip_uint64_t idx) {\n    return _zip_unchange(za, idx, 0);\n}\n\n\nint\n_zip_unchange(zip_t *za, zip_uint64_t idx, int allow_duplicates) {\n    zip_int64_t i;\n    bool renamed;\n\n    if (idx >= za->nentry) {\n        zip_error_set(&za->error, ZIP_ER_INVAL, 0);\n        return -1;\n    }\n\n    renamed = za->entry[idx].changes && (za->entry[idx].changes->changed & ZIP_DIRENT_FILENAME);\n    if (!allow_duplicates && (renamed || za->entry[idx].deleted)) {\n        const char *orig_name = NULL;\n        const char *changed_name = NULL;\n\n        if (za->entry[idx].orig != NULL) {\n            if ((orig_name = _zip_get_name(za, idx, ZIP_FL_UNCHANGED, &za->error)) == NULL) {\n                return -1;\n            }\n\n            i = _zip_name_locate(za, orig_name, 0, NULL);\n            if (i >= 0 && (zip_uint64_t)i != idx) {\n                zip_error_set(&za->error, ZIP_ER_EXISTS, 0);\n                return -1;\n            }\n        }\n\n        if (renamed) {\n            if ((changed_name = _zip_get_name(za, idx, 0, &za->error)) == NULL) {\n                return -1;\n            }\n        }\n\n        if (orig_name) {\n            if (_zip_hash_add(za->names, (const zip_uint8_t *)orig_name, idx, 0, &za->error) == false) {\n                return -1;\n            }\n        }\n        if (changed_name) {\n            if (_zip_hash_delete(za->names, (const zip_uint8_t *)changed_name, &za->error) == false) {\n                _zip_hash_delete(za->names, (const zip_uint8_t *)orig_name, NULL);\n                return -1;\n            }\n        }\n    }\n\n    _zip_dirent_free(za->entry[idx].changes);\n    za->entry[idx].changes = NULL;\n\n    _zip_unchange_data(za->entry + idx);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_unchange_all.c",
    "content": "/*\n  zip_unchange.c -- undo changes to all files in zip archive\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_unchange_all(zip_t *za) {\n    int ret;\n    zip_uint64_t i;\n\n    if (!_zip_hash_revert(za->names, &za->error)) {\n        return -1;\n    }\n\n    ret = 0;\n    for (i = 0; i < za->nentry; i++)\n        ret |= _zip_unchange(za, i, 1);\n\n    ret |= zip_unchange_archive(za);\n\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_unchange_archive.c",
    "content": "/*\n  zip_unchange_archive.c -- undo global changes to ZIP archive\n  Copyright (C) 2006-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdlib.h>\n\n#include \"zipint.h\"\n\n\nZIP_EXTERN int\nzip_unchange_archive(zip_t *za) {\n    if (za->comment_changed) {\n        _zip_string_free(za->comment_changes);\n        za->comment_changes = NULL;\n        za->comment_changed = 0;\n    }\n\n    za->ch_flags = za->flags;\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_unchange_data.c",
    "content": "/*\n  zip_unchange_data.c -- undo helper function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\nvoid\n_zip_unchange_data(zip_entry_t *ze) {\n    if (ze->source) {\n        zip_source_free(ze->source);\n        ze->source = NULL;\n    }\n\n    if (ze->changes != NULL && (ze->changes->changed & ZIP_DIRENT_COMP_METHOD) && ze->changes->comp_method == ZIP_CM_REPLACED_DEFAULT) {\n        ze->changes->changed &= ~ZIP_DIRENT_COMP_METHOD;\n        if (ze->changes->changed == 0) {\n            _zip_dirent_free(ze->changes);\n            ze->changes = NULL;\n        }\n    }\n\n    ze->deleted = 0;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_utf-8.c",
    "content": "/*\n  zip_utf-8.c -- UTF-8 support functions for libzip\n  Copyright (C) 2011-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"zipint.h\"\n\n#include <stdlib.h>\n\n\nstatic const zip_uint16_t _cp437_to_unicode[256] = {\n    /* 0x00 - 0x0F */\n    0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,\n\n    /* 0x10 - 0x1F */\n    0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,\n\n    /* 0x20 - 0x2F */\n    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,\n\n    /* 0x30 - 0x3F */\n    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,\n\n    /* 0x40 - 0x4F */\n    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,\n\n    /* 0x50 - 0x5F */\n    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,\n\n    /* 0x60 - 0x6F */\n    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,\n\n    /* 0x70 - 0x7F */\n    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302,\n\n    /* 0x80 - 0x8F */\n    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n\n    /* 0x90 - 0x9F */\n    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,\n\n    /* 0xA0 - 0xAF */\n    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\n    /* 0xB0 - 0xBF */\n    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\n    /* 0xC0 - 0xCF */\n    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\n    /* 0xD0 - 0xDF */\n    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\n    /* 0xE0 - 0xEF */\n    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\n    /* 0xF0 - 0xFF */\n    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0};\n\n#define UTF_8_LEN_2_MASK 0xe0\n#define UTF_8_LEN_2_MATCH 0xc0\n#define UTF_8_LEN_3_MASK 0xf0\n#define UTF_8_LEN_3_MATCH 0xe0\n#define UTF_8_LEN_4_MASK 0xf8\n#define UTF_8_LEN_4_MATCH 0xf0\n#define UTF_8_CONTINUE_MASK 0xc0\n#define UTF_8_CONTINUE_MATCH 0x80\n\n\nzip_encoding_type_t\n_zip_guess_encoding(zip_string_t *str, zip_encoding_type_t expected_encoding) {\n    zip_encoding_type_t enc;\n    const zip_uint8_t *name;\n    zip_uint32_t i, j, ulen;\n    bool can_be_ascii = true;\n    bool can_be_utf8 = true;\n    bool has_control_characters = false;\n\n    if (str == NULL) {\n        return ZIP_ENCODING_ASCII;\n    }\n\n    name = str->raw;\n\n    if (str->encoding != ZIP_ENCODING_UNKNOWN) {\n        return str->encoding;\n    }\n\n    for (i = 0; i < str->length; i++) {\n        if (name[i] < 128) {\n            if (name[i] < 32 && name[i] != '\\r' && name[i] != '\\n' && name[i] != '\\t') {\n                has_control_characters = true;\n            }\n            continue;\n        }\n\n        can_be_ascii = false;\n        if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) {\n            ulen = 1;\n        }\n        else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) {\n            ulen = 2;\n        }\n        else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) {\n            ulen = 3;\n        }\n        else {\n            can_be_utf8 = false;\n            break;\n        }\n\n        if (i + ulen >= str->length) {\n            can_be_utf8 = false;\n            break;\n        }\n\n        for (j = 1; j <= ulen; j++) {\n            if ((name[i + j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) {\n                can_be_utf8 = false;\n                goto done;\n            }\n        }\n        i += ulen;\n    }\n\n done:\n    enc = ZIP_ENCODING_CP437;\n\n    switch (expected_encoding) {\n    case ZIP_ENCODING_UTF8_KNOWN:\n    case ZIP_ENCODING_UTF8_GUESSED:\n        if (can_be_utf8) {\n            enc = ZIP_ENCODING_UTF8_KNOWN;\n        }\n        else {\n            enc = ZIP_ENCODING_ERROR;\n        }\n        break;\n\n    case ZIP_ENCODING_ASCII:\n        if (can_be_ascii && !has_control_characters) {\n            enc = ZIP_ENCODING_ASCII;\n        }\n        else {\n            enc = ZIP_ENCODING_ERROR;\n        }\n        break;\n\n    case ZIP_ENCODING_CP437:\n        enc = ZIP_ENCODING_CP437;\n        break;\n\n    case ZIP_ENCODING_UNKNOWN:\n        if (can_be_ascii && !has_control_characters) {\n            /* only bytes from 0x20-0x7F */\n            enc = ZIP_ENCODING_ASCII;\n        }\n        else if (can_be_ascii && has_control_characters) {\n            /* only bytes from 0x00-0x7F */\n            enc = ZIP_ENCODING_CP437;\n        }\n        else if (can_be_utf8) {\n            /* contains bytes from 0x80-0xFF and is valid UTF-8 */\n            enc =  ZIP_ENCODING_UTF8_GUESSED;\n        }\n        else {\n            /* fallback */\n            enc = ZIP_ENCODING_CP437;\n        }\n        break;\n    case ZIP_ENCODING_ERROR:\n        /* invalid, shouldn't happen */\n        enc = ZIP_ENCODING_ERROR;\n        break;\n    }\n\n    str->encoding = enc;\n    return enc;\n}\n\n\nstatic zip_uint32_t\n_zip_unicode_to_utf8_len(zip_uint32_t codepoint) {\n    if (codepoint < 0x0080) {\n        return 1;\n    }\n    if (codepoint < 0x0800) {\n        return 2;\n    }\n    if (codepoint < 0x10000) {\n        return 3;\n    }\n    return 4;\n}\n\n\nstatic zip_uint32_t\n_zip_unicode_to_utf8(zip_uint32_t codepoint, zip_uint8_t *buf) {\n    if (codepoint < 0x0080) {\n        buf[0] = codepoint & 0xff;\n        return 1;\n    }\n    if (codepoint < 0x0800) {\n        buf[0] = (zip_uint8_t)(UTF_8_LEN_2_MATCH | ((codepoint >> 6) & 0x1f));\n        buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f));\n        return 2;\n    }\n    if (codepoint < 0x10000) {\n        buf[0] = (zip_uint8_t)(UTF_8_LEN_3_MATCH | ((codepoint >> 12) & 0x0f));\n        buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f));\n        buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f));\n        return 3;\n    }\n    buf[0] = (zip_uint8_t)(UTF_8_LEN_4_MATCH | ((codepoint >> 18) & 0x07));\n    buf[1] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 12) & 0x3f));\n    buf[2] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | ((codepoint >> 6) & 0x3f));\n    buf[3] = (zip_uint8_t)(UTF_8_CONTINUE_MATCH | (codepoint & 0x3f));\n    return 4;\n}\n\n\nzip_uint8_t *\n_zip_cp437_to_utf8(const zip_uint8_t *const _cp437buf, zip_uint32_t len, zip_uint32_t *utf8_lenp, zip_error_t *error) {\n    zip_uint8_t *cp437buf = (zip_uint8_t *)_cp437buf;\n    zip_uint8_t *utf8buf;\n    zip_uint32_t buflen, i, offset;\n\n    if (len == 0) {\n        if (utf8_lenp) {\n            *utf8_lenp = 0;\n        }\n        return NULL;\n    }\n\n    buflen = 1;\n    for (i = 0; i < len; i++) {\n        buflen += _zip_unicode_to_utf8_len(_cp437_to_unicode[cp437buf[i]]);\n    }\n\n    if ((utf8buf = (zip_uint8_t *)malloc(buflen)) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    offset = 0;\n    for (i = 0; i < len; i++) {\n        offset += _zip_unicode_to_utf8(_cp437_to_unicode[cp437buf[i]], utf8buf + offset);\n    }\n\n    utf8buf[buflen - 1] = 0;\n    if (utf8_lenp) {\n        *utf8_lenp = buflen - 1;\n    }\n    return utf8buf;\n}\n"
  },
  {
    "path": "external/libzip/lib/zip_winzip_aes.c",
    "content": "/*\n  zip_winzip_aes.c -- Winzip AES de/encryption backend routines\n  Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in\n  the documentation and/or other materials provided with the\n  distribution.\n  3. The names of the authors may not be used to endorse or promote\n  products derived from this software without specific prior\n  written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include \"zip_crypto.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\n\n#define MAX_KEY_LENGTH 256\n#define PBKDF2_ITERATIONS 1000\n\nstruct _zip_winzip_aes {\n    _zip_crypto_aes_t *aes;\n    _zip_crypto_hmac_t *hmac;\n    zip_uint8_t counter[ZIP_CRYPTO_AES_BLOCK_LENGTH];\n    zip_uint8_t pad[ZIP_CRYPTO_AES_BLOCK_LENGTH];\n    int pad_offset;\n};\n\nstatic bool\naes_crypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) {\n    zip_uint64_t i, j;\n\n    for (i = 0; i < length; i++) {\n        if (ctx->pad_offset == AES_BLOCK_SIZE) {\n            for (j = 0; j < 8; j++) {\n                ctx->counter[j]++;\n                if (ctx->counter[j] != 0) {\n                    break;\n                }\n            }\n            if (!_zip_crypto_aes_encrypt_block(ctx->aes, ctx->counter, ctx->pad)) {\n                return false;\n            }\n            ctx->pad_offset = 0;\n        }\n        data[i] ^= ctx->pad[ctx->pad_offset++];\n    }\n\n    return true;\n}\n\n\nzip_winzip_aes_t *\n_zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t encryption_method, zip_uint8_t *password_verify, zip_error_t *error) {\n    zip_winzip_aes_t *ctx;\n    zip_uint8_t buffer[2 * (MAX_KEY_LENGTH / 8) + WINZIP_AES_PASSWORD_VERIFY_LENGTH];\n    zip_uint16_t key_size = 0; /* in bits */\n    zip_uint16_t key_length;   /* in bytes */\n\n    switch (encryption_method) {\n    case ZIP_EM_AES_128:\n        key_size = 128;\n        break;\n    case ZIP_EM_AES_192:\n        key_size = 192;\n        break;\n    case ZIP_EM_AES_256:\n        key_size = 256;\n        break;\n    }\n\n    if (key_size == 0 || salt == NULL || password == NULL || password_length == 0) {\n        zip_error_set(error, ZIP_ER_INVAL, 0);\n        return NULL;\n    }\n\n    key_length = key_size / 8;\n\n    if ((ctx = (zip_winzip_aes_t *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    memset(ctx->counter, 0, sizeof(ctx->counter));\n    ctx->pad_offset = ZIP_CRYPTO_AES_BLOCK_LENGTH;\n\n    if (!_zip_crypto_pbkdf2(password, password_length, salt, key_length / 2, PBKDF2_ITERATIONS, buffer, 2 * key_length + WINZIP_AES_PASSWORD_VERIFY_LENGTH)) {\n        free(ctx);\n        return NULL;\n    }\n\n    if ((ctx->aes = _zip_crypto_aes_new(buffer, key_size, error)) == NULL) {\n        _zip_crypto_clear(ctx, sizeof(*ctx));\n        free(ctx);\n        return NULL;\n    }\n    if ((ctx->hmac = _zip_crypto_hmac_new(buffer + key_length, key_length, error)) == NULL) {\n        _zip_crypto_aes_free(ctx->aes);\n        free(ctx);\n        return NULL;\n    }\n\n    if (password_verify) {\n        (void)memcpy_s(password_verify, WINZIP_AES_PASSWORD_VERIFY_LENGTH, buffer + (2 * key_size / 8), WINZIP_AES_PASSWORD_VERIFY_LENGTH);\n    }\n\n    return ctx;\n}\n\n\nbool\n_zip_winzip_aes_encrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) {\n    return aes_crypt(ctx, data, length) && _zip_crypto_hmac(ctx->hmac, data, length);\n}\n\n\nbool\n_zip_winzip_aes_decrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length) {\n    return _zip_crypto_hmac(ctx->hmac, data, length) && aes_crypt(ctx, data, length);\n}\n\n\nbool\n_zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac) {\n    return _zip_crypto_hmac_output(ctx->hmac, hmac);\n}\n\n\nvoid\n_zip_winzip_aes_free(zip_winzip_aes_t *ctx) {\n    if (ctx == NULL) {\n        return;\n    }\n\n    _zip_crypto_aes_free(ctx->aes);\n    _zip_crypto_hmac_free(ctx->hmac);\n    free(ctx);\n}\n"
  },
  {
    "path": "external/libzip/lib/zipint.h",
    "content": "#ifndef _HAD_ZIPINT_H\n#define _HAD_ZIPINT_H\n\n/*\n  zipint.h -- internal declarations.\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"config.h\"\n\n#include \"compat.h\"\n\n#ifdef ZIP_ALLOCATE_BUFFER\n#include <stdlib.h>\n#endif\n\n#ifdef _ZIP_COMPILING_DEPRECATED\n#define ZIP_DEPRECATED(x)\n#else\n#define ZIP_DISABLE_DEPRECATED\n#endif\n\n#include \"zip.h\"\n\n#define CENTRAL_MAGIC \"PK\\1\\2\"\n#define LOCAL_MAGIC \"PK\\3\\4\"\n#define EOCD_MAGIC \"PK\\5\\6\"\n#define DATADES_MAGIC \"PK\\7\\10\"\n#define EOCD64LOC_MAGIC \"PK\\6\\7\"\n#define EOCD64_MAGIC \"PK\\6\\6\"\n#define MAGIC_LEN 4\n#define CDENTRYSIZE 46u\n#define LENTRYSIZE 30\n#define MAXCOMLEN 65536\n#define MAXEXTLEN 65536\n#define EOCDLEN 22\n#define EOCD64LOCLEN 20\n#define EOCD64LEN 56\n#define CDBUFSIZE (MAXCOMLEN + EOCDLEN + EOCD64LOCLEN)\n#define BUFSIZE 8192\n#define EFZIP64SIZE 28\n#define EF_WINZIP_AES_SIZE 7\n#define MAX_DATA_DESCRIPTOR_LENGTH 24\n\n#define TORRENTZIP_SIGNATURE \"TORRENTZIPPED-\"\n#define TORRENTZIP_SIGNATURE_LENGTH 14\n#define TORRENTZIP_CRC_LENGTH 8\n#define TORRENTZIP_MEM_LEVEL 8\n#define TORRENTZIP_COMPRESSION_FLAGS ZIP_UINT16_MAX\n\n#define ZIP_CRYPTO_PKWARE_HEADERLEN 12\n\n#define ZIP_CM_REPLACED_DEFAULT (-2)\n#define ZIP_CM_WINZIP_AES 99 /* Winzip AES encrypted */\n\n#define WINZIP_AES_PASSWORD_VERIFY_LENGTH 2\n#define WINZIP_AES_MAX_HEADER_LENGTH (16 + WINZIP_AES_PASSWORD_VERIFY_LENGTH)\n#define AES_BLOCK_SIZE 16\n#define HMAC_LENGTH 10\n#define SALT_LENGTH(method) ((method) == ZIP_EM_AES_128 ? 8 : ((method) == ZIP_EM_AES_192 ? 12 : 16))\n\n#define ZIP_CM_IS_DEFAULT(x) ((x) == ZIP_CM_DEFAULT || (x) == ZIP_CM_REPLACED_DEFAULT)\n#define ZIP_CM_ACTUAL(x) ((zip_uint16_t)(ZIP_CM_IS_DEFAULT(x) ? ZIP_CM_DEFLATE : (x)))\n\n#define ZIP_EF_UTF_8_COMMENT 0x6375\n#define ZIP_EF_UTF_8_NAME 0x7075\n#define ZIP_EF_WINZIP_AES 0x9901\n#define ZIP_EF_ZIP64 0x0001\n\n#define ZIP_EF_IS_INTERNAL(id) ((id) == ZIP_EF_UTF_8_COMMENT || (id) == ZIP_EF_UTF_8_NAME || (id) == ZIP_EF_WINZIP_AES || (id) == ZIP_EF_ZIP64)\n\n/* according to unzip-6.0's zipinfo.c, this corresponds to a regular file with rw permissions for everyone */\n#define ZIP_EXT_ATTRIB_DEFAULT (0100666u << 16)\n/* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */\n#define ZIP_EXT_ATTRIB_DEFAULT_DIR (0040777u << 16)\n\n/* Allowed: Encryption specific bits, data descriptor, compression specific, UTF-8 filename */\n#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK 0x083e\n\n#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))\n#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define ZIP_REALLOC(memory, alloced_elements, additional_elements, error) zip_realloc((void **)&memory, &alloced_elements, sizeof(*memory), additional_elements, error)\n\n/* This section contains API that won't materialize like this.  It's\n   placed in the internal section, pending cleanup. */\n\n/* flags for compression and encryption sources */\n\n#define ZIP_CODEC_DECODE 0 /* decompress/decrypt (encode flag not set) */\n#define ZIP_CODEC_ENCODE 1 /* compress/encrypt */\n\ntypedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);\n\nzip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t method, int operation);\n\n/* clang-format off */\nenum zip_compression_status {\n    ZIP_COMPRESSION_OK,\n    ZIP_COMPRESSION_END,\n    ZIP_COMPRESSION_ERROR,\n    ZIP_COMPRESSION_NEED_DATA\n};\n/* clang-format on */\ntypedef enum zip_compression_status zip_compression_status_t;\n\nstruct zip_compression_algorithm {\n    /* Return maximum compressed size for uncompressed data of given size. */\n    zip_uint64_t (*maximum_compressed_size)(zip_uint64_t uncompressed_size);\n\n    /* called once to create new context */\n    void *(*allocate)(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error);\n    /* called once to free context */\n    void (*deallocate)(void *ctx);\n\n    /* get compression specific general purpose bitflags */\n    zip_uint16_t (*general_purpose_bit_flags)(void *ctx);\n    /* minimum version needed when using this algorithm */\n    zip_uint8_t version_needed;\n\n    /* start processing */\n    bool (*start)(void *ctx, zip_stat_t *st, zip_file_attributes_t *attributes);\n    /* stop processing */\n    bool (*end)(void *ctx);\n\n    /* provide new input data, remains valid until next call to input or end */\n    bool (*input)(void *ctx, zip_uint8_t *data, zip_uint64_t length);\n\n    /* all input data has been provided */\n    bool (*end_of_input)(void *ctx);\n\n    /* process input data, writing to data, which has room for length bytes, update length to number of bytes written */\n    zip_compression_status_t (*process)(void *ctx, zip_uint8_t *data, zip_uint64_t *length);\n};\ntypedef struct zip_compression_algorithm zip_compression_algorithm_t;\n\nextern zip_compression_algorithm_t zip_algorithm_bzip2_compress;\nextern zip_compression_algorithm_t zip_algorithm_bzip2_decompress;\nextern zip_compression_algorithm_t zip_algorithm_deflate_compress;\nextern zip_compression_algorithm_t zip_algorithm_deflate_decompress;\nextern zip_compression_algorithm_t zip_algorithm_xz_compress;\nextern zip_compression_algorithm_t zip_algorithm_xz_decompress;\nextern zip_compression_algorithm_t zip_algorithm_zstd_compress;\nextern zip_compression_algorithm_t zip_algorithm_zstd_decompress;\n\nzip_compression_algorithm_t *_zip_get_compression_algorithm(zip_int32_t method, bool compress);\n\n/* This API is not final yet, but we need it internally, so it's private for now. */\n\nconst zip_uint8_t *zip_get_extra_field_by_id(zip_t *, int, int, zip_uint16_t, int, zip_uint16_t *);\n\n/* This section contains API that is of limited use until support for\n   user-supplied compression/encryption implementation is finished.\n   Thus we will keep it private for now. */\n\nzip_source_t *zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t cm, zip_uint32_t compression_flags);\nzip_source_t *zip_source_crc_create(zip_source_t *, int, zip_error_t *error);\nzip_source_t *zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t cm);\nzip_source_t *zip_source_pkware_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);\nzip_source_t *zip_source_pkware_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);\nint zip_source_remove(zip_source_t *);\nzip_int64_t zip_source_supports(zip_source_t *src);\nbool zip_source_supports_reopen(zip_source_t *src);\nzip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);\nzip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);\nzip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes);\nzip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);\n\n/* error source for layered sources */\n\nenum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL };\n\n#define ZIP_DETAIL_ET_GLOBAL 0\n#define ZIP_DETAIL_ET_ENTRY  1\n\nstruct _zip_err_info {\n    int type;\n    const char *description;\n};\n\nextern const struct _zip_err_info _zip_err_str[];\nextern const int _zip_err_str_count;\nextern const struct _zip_err_info _zip_err_details[];\nextern const int _zip_err_details_count;\n\n/* macros for libzip-internal errors */\n#define MAX_DETAIL_INDEX 0x7fffff\n#define MAKE_DETAIL_WITH_INDEX(error, index) ((((index) > MAX_DETAIL_INDEX) ? MAX_DETAIL_INDEX : (int)(index)) << 8 | (error))\n#define GET_INDEX_FROM_DETAIL(error) (((error) >> 8) & MAX_DETAIL_INDEX)\n#define GET_ERROR_FROM_DETAIL(error) ((error) & 0xff)\n#define ADD_INDEX_TO_DETAIL(error, index) MAKE_DETAIL_WITH_INDEX(GET_ERROR_FROM_DETAIL(error), (index))\n\n/* error code for libzip-internal errors */\n#define ZIP_ER_DETAIL_NO_DETAIL 0   /* G no detail */\n#define ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD 1  /* G central directory overlaps EOCD, or there is space between them */\n#define ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID 2  /* G archive comment length incorrect */\n#define ZIP_ER_DETAIL_CDIR_LENGTH_INVALID 3  /* G central directory length invalid */\n#define ZIP_ER_DETAIL_CDIR_ENTRY_INVALID 4  /* E central header invalid */\n#define ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT 5  /* G central directory count of entries is incorrect */\n#define ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH 6  /* E local and central headers do not match */\n#define ZIP_ER_DETAIL_EOCD_LENGTH_INVALID 7  /* G wrong EOCD length */\n#define ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD 8  /* G EOCD64 overlaps EOCD, or there is space between them */\n#define ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC 9  /* G EOCD64 magic incorrect */\n#define ZIP_ER_DETAIL_EOCD64_MISMATCH 10  /* G EOCD64 and EOCD do not match */\n#define ZIP_ER_DETAIL_CDIR_INVALID 11  /* G invalid value in central directory */\n#define ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW 12 /* E variable size fields overflow header */\n#define ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME 13 /* E invalid UTF-8 in filename */\n#define ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT 14 /* E invalid UTF-8 in comment */\n#define ZIP_ER_DETAIL_INVALID_ZIP64_EF 15 /* E invalid Zip64 extra field */\n#define ZIP_ER_DETAIL_INVALID_WINZIPAES_EF 16 /* E invalid WinZip AES extra field */\n#define ZIP_ER_DETAIL_EF_TRAILING_GARBAGE 17 /* E garbage at end of extra fields */\n#define ZIP_ER_DETAIL_INVALID_EF_LENGTH 18 /* E extra field length is invalid */\n#define ZIP_ER_DETAIL_INVALID_FILE_LENGTH 19 /* E file length in header doesn't match actual file length */\n#define ZIP_ER_DETAIL_STORED_SIZE_MISMATCH 20 /* E compressed and uncompressed sizes don't match for stored file */\n#define ZIP_ER_DETAIL_DATA_DESCRIPTOR_MISMATCH 21 /* E local header and data descriptor do not match */\n#define ZIP_ER_DETAIL_EOCD64_LOCATOR_MISMATCH 22 /* G EOCD64 and EOCD64 locator do not match */\n#define ZIP_ER_DETAIL_UTF8_FILENAME_MISMATCH 23 /* E UTF-8 filename is ASCII and doesn't match filename */\n#define ZIP_ER_DETAIL_UTF8_COMMENT_MISMATCH 24 /* E UTF-8 comment is ASCII and doesn't match comment */\n#define ZIP_ER_DETAIL_COMPRESSED_DATA_TRAILING_GARBAGE 25 /* G garbage at end of compressed data */\n\n/* directory entry: general purpose bit flags */\n\n#define ZIP_GPBF_ENCRYPTED 0x0001u         /* is encrypted */\n#define ZIP_GPBF_DATA_DESCRIPTOR 0x0008u   /* crc/size after file data */\n#define ZIP_GPBF_STRONG_ENCRYPTION 0x0040u /* uses strong encryption */\n#define ZIP_GPBF_ENCODING_UTF_8 0x0800u    /* file name encoding is UTF-8 */\n\n\n/* extra fields */\n#define ZIP_EF_LOCAL ZIP_FL_LOCAL                   /* include in local header */\n#define ZIP_EF_CENTRAL ZIP_FL_CENTRAL               /* include in central directory */\n#define ZIP_EF_BOTH (ZIP_EF_LOCAL | ZIP_EF_CENTRAL) /* include in both */\n\n#define ZIP_FL_FORCE_ZIP64 1024 /* force zip64 extra field (_zip_dirent_write) */\n\n#define ZIP_FL_ENCODING_ALL (ZIP_FL_ENC_GUESS | ZIP_FL_ENC_CP437 | ZIP_FL_ENC_UTF_8)\n\n\n/* encoding type */\nenum zip_encoding_type {\n    ZIP_ENCODING_UNKNOWN,      /* not yet analyzed */\n    ZIP_ENCODING_ASCII,        /* plain ASCII */\n    ZIP_ENCODING_UTF8_KNOWN,   /* is UTF-8 */\n    ZIP_ENCODING_UTF8_GUESSED, /* possibly UTF-8 */\n    ZIP_ENCODING_CP437,        /* Code Page 437 */\n    ZIP_ENCODING_ERROR         /* should be UTF-8 but isn't */\n};\n\ntypedef enum zip_encoding_type zip_encoding_type_t;\n\nstruct zip_hash;\nstruct zip_progress;\n\ntypedef struct zip_cdir zip_cdir_t;\ntypedef struct zip_dostime zip_dostime_t;\ntypedef struct zip_dirent zip_dirent_t;\ntypedef struct zip_entry zip_entry_t;\ntypedef struct zip_extra_field zip_extra_field_t;\ntypedef struct zip_string zip_string_t;\ntypedef struct zip_buffer zip_buffer_t;\ntypedef struct zip_hash zip_hash_t;\ntypedef struct zip_progress zip_progress_t;\n\n/* zip archive, part of API */\n\nstruct zip {\n    zip_source_t *src;       /* data source for archive */\n    unsigned int open_flags; /* flags passed to zip_open */\n    zip_error_t error;       /* error information */\n\n    unsigned int flags;    /* archive global flags */\n    unsigned int ch_flags; /* changed archive global flags */\n\n    char *default_password; /* password used when no other supplied */\n\n    zip_string_t *comment_orig;    /* archive comment */\n    zip_string_t *comment_changes; /* changed archive comment */\n    bool comment_changed;          /* whether archive comment was changed */\n\n    zip_uint64_t nentry;       /* number of entries */\n    zip_uint64_t nentry_alloc; /* number of entries allocated */\n    zip_entry_t *entry;        /* entries */\n\n    zip_uint64_t nopen_source;       /* number of open sources using archive */\n    zip_uint64_t nopen_source_alloc; /* number of sources allocated */\n    zip_source_t **open_source;      /* open sources using archive */\n\n    zip_hash_t *names; /* hash table for name lookup */\n\n    zip_progress_t *progress; /* progress callback for zip_close() */\n\n    zip_uint32_t* write_crc; /* have _zip_write() compute CRC */\n    time_t torrent_mtime;\n};\n\n/* file in zip archive, part of API */\n\nstruct zip_file {\n    zip_error_t error; /* error information */\n    zip_source_t *src; /* data source */\n};\n\n/* zip archive directory entry (central or local) */\n\n#define ZIP_DIRENT_COMP_METHOD 0x0001u\n#define ZIP_DIRENT_FILENAME 0x0002u\n#define ZIP_DIRENT_COMMENT 0x0004u\n#define ZIP_DIRENT_EXTRA_FIELD 0x0008u\n#define ZIP_DIRENT_ATTRIBUTES 0x0010u\n#define ZIP_DIRENT_LAST_MOD 0x0020u\n#define ZIP_DIRENT_ENCRYPTION_METHOD 0x0040u\n#define ZIP_DIRENT_PASSWORD 0x0080u\n#define ZIP_DIRENT_ALL ZIP_UINT32_MAX\n\nstruct zip_dostime {\n    zip_uint16_t time;\n    zip_uint16_t date;\n};\n\nstruct zip_dirent {\n    zip_uint32_t changed;\n    bool local_extra_fields_read; /*      whether we already read in local header extra fields */\n    bool cloned;                  /*      whether this instance is cloned, and thus shares non-changed strings */\n\n    bool crc_valid; /*      if CRC is valid (sometimes not for encrypted archives) */\n    bool last_mod_mtime_valid;\n\n    zip_uint16_t version_madeby;     /* (c)  version of creator */\n    zip_uint16_t version_needed;     /* (cl) version needed to extract */\n    zip_uint16_t bitflags;           /* (cl) general purpose bit flag */\n    zip_int32_t comp_method;         /* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */\n    zip_dostime_t last_mod;          /* (cl) time of last modification */\n    zip_uint32_t crc;                /* (cl) CRC-32 of uncompressed data */\n    zip_uint64_t comp_size;          /* (cl) size of compressed data */\n    zip_uint64_t uncomp_size;        /* (cl) size of uncompressed data */\n    zip_string_t *filename;          /* (cl) file name (NUL-terminated) */\n    zip_extra_field_t *extra_fields; /* (cl) extra fields, parsed */\n    zip_string_t *comment;           /* (c)  file comment */\n    zip_uint32_t disk_number;        /* (c)  disk number start */\n    zip_uint16_t int_attrib;         /* (c)  internal file attributes */\n    zip_uint32_t ext_attrib;         /* (c)  external file attributes */\n    zip_uint64_t offset;             /* (c)  offset of local header */\n\n    zip_uint32_t compression_level; /*      level of compression to use (never valid in orig) */\n    zip_uint16_t encryption_method; /*      encryption method, computed from other fields */\n    char *password;                 /*      file specific encryption password */\n\n    time_t last_mod_mtime;          /*      cached last_mod in Unix time format */\n};\n\n/* zip archive central directory */\n\nstruct zip_cdir {\n    zip_entry_t *entry;        /* directory entries */\n    zip_uint64_t nentry;       /* number of entries */\n    zip_uint64_t nentry_alloc; /* number of entries allocated */\n\n    zip_uint32_t this_disk;\n    zip_uint32_t eocd_disk;\n    zip_uint64_t disk_entries; /* number of entries on this disk */\n    zip_uint64_t num_entries;  /* number of entries on all disks */\n    zip_uint64_t size;     /* size of central directory */\n    zip_uint64_t offset;   /* offset of central directory in file */\n    zip_uint64_t eocd_offset; /* offset of EOCD in file */\n    zip_string_t *comment; /* zip archive comment */\n    bool is_zip64;         /* central directory in zip64 format */\n};\n\nstruct zip_extra_field {\n    zip_extra_field_t *next;\n    zip_flags_t flags; /* in local/central header */\n    zip_uint16_t id;   /* header id */\n    zip_uint16_t size; /* data size */\n    zip_uint8_t *data;\n};\n\nenum zip_source_write_state {\n    ZIP_SOURCE_WRITE_CLOSED, /* write is not in progress */\n    ZIP_SOURCE_WRITE_OPEN,   /* write is in progress */\n    ZIP_SOURCE_WRITE_FAILED, /* commit failed, only rollback allowed */\n    ZIP_SOURCE_WRITE_REMOVED /* file was removed */\n};\ntypedef enum zip_source_write_state zip_source_write_state_t;\n\nstruct zip_source {\n    zip_source_t *src;\n    union {\n        zip_source_callback f;\n        zip_source_layered_callback l;\n    } cb;\n    void *ud;\n    zip_error_t error;\n    zip_int64_t supports;                 /* supported commands */\n    unsigned int open_count;              /* number of times source was opened (directly or as lower layer) */\n    zip_source_write_state_t write_state; /* whether source is open for writing */\n    bool source_closed;                   /* set if source archive is closed */\n    zip_t *source_archive;                /* zip archive we're reading from, NULL if not from archive */\n    unsigned int refcount;\n    bool eof;                /* EOF reached */\n    bool had_read_error;     /* a previous ZIP_SOURCE_READ reported an error */\n    zip_uint64_t bytes_read; /* for sources that don't support ZIP_SOURCE_TELL. */\n};\n\n#define ZIP_SOURCE_IS_OPEN_READING(src) ((src)->open_count > 0)\n#define ZIP_SOURCE_IS_OPEN_WRITING(src) ((src)->write_state == ZIP_SOURCE_WRITE_OPEN)\n#define ZIP_SOURCE_IS_LAYERED(src) ((src)->src != NULL)\n\n/* entry in zip archive directory */\n\nstruct zip_entry {\n    zip_dirent_t *orig;\n    zip_dirent_t *changes;\n    zip_source_t *source;\n    bool deleted;\n};\n\n\n/* file or archive comment, or filename */\n\nstruct zip_string {\n    zip_uint8_t *raw;                /* raw string */\n    zip_uint16_t length;             /* length of raw string */\n    enum zip_encoding_type encoding; /* autorecognized encoding */\n    zip_uint8_t *converted;          /* autoconverted string */\n    zip_uint32_t converted_length;   /* length of converted */\n};\n\n\n/* byte array */\n\n/* For performance, we usually keep 8k byte arrays on the stack.\n   However, there are (embedded) systems with a stack size of 12k;\n   for those, use malloc()/free() */\n\n#ifdef ZIP_ALLOCATE_BUFFER\n#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t *buf\n#define byte_array_init(buf, size) (((buf) = (zip_uint8_t *)malloc(size)) != NULL)\n#define byte_array_fini(buf) (free(buf))\n#else\n#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t buf[size]\n#define byte_array_init(buf, size) (1)\n#define byte_array_fini(buf) ((void)0)\n#endif\n\n\n/* bounds checked access to memory buffer */\n\nstruct zip_buffer {\n    bool ok;\n    bool free_data;\n\n    zip_uint8_t *data;\n    zip_uint64_t size;\n    zip_uint64_t offset;\n};\n\n/* which files to write in which order */\n\nstruct zip_filelist {\n    zip_uint64_t idx;\n    const char *name;\n};\n\ntypedef struct zip_filelist zip_filelist_t;\n\nstruct _zip_winzip_aes;\ntypedef struct _zip_winzip_aes zip_winzip_aes_t;\n\nstruct _zip_pkware_keys {\n    zip_uint32_t key[3];\n};\ntypedef struct _zip_pkware_keys zip_pkware_keys_t;\n\n#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))\n#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define ZIP_ENTRY_CHANGED(e, f) ((e)->changes && ((e)->changes->changed & (f)))\n#define ZIP_ENTRY_DATA_CHANGED(x) ((x)->source != NULL)\n#define ZIP_ENTRY_HAS_CHANGES(e) (ZIP_ENTRY_DATA_CHANGED(e) || (e)->deleted || ZIP_ENTRY_CHANGED((e), ZIP_DIRENT_ALL))\n\n#define ZIP_IS_RDONLY(za) ((za)->ch_flags & ZIP_AFL_RDONLY)\n#define ZIP_IS_TORRENTZIP(za) ((za)->flags & ZIP_AFL_IS_TORRENTZIP)\n#define ZIP_WANT_TORRENTZIP(za) ((za)->ch_flags & ZIP_AFL_WANT_TORRENTZIP)\n\n\n#ifdef HAVE_EXPLICIT_MEMSET\n#define _zip_crypto_clear(b, l) explicit_memset((b), 0, (l))\n#else\n#ifdef HAVE_EXPLICIT_BZERO\n#define _zip_crypto_clear(b, l) explicit_bzero((b), (l))\n#else\n#include <string.h>\n#define _zip_crypto_clear(b, l) memset((b), 0, (l))\n#endif\n#endif\n\n\nzip_int64_t _zip_add_entry(zip_t *);\n\nzip_uint8_t *_zip_buffer_data(zip_buffer_t *buffer);\nbool _zip_buffer_eof(zip_buffer_t *buffer);\nvoid _zip_buffer_free(zip_buffer_t *buffer);\nzip_uint8_t *_zip_buffer_get(zip_buffer_t *buffer, zip_uint64_t length);\nzip_uint16_t _zip_buffer_get_16(zip_buffer_t *buffer);\nzip_uint32_t _zip_buffer_get_32(zip_buffer_t *buffer);\nzip_uint64_t _zip_buffer_get_64(zip_buffer_t *buffer);\nzip_uint8_t _zip_buffer_get_8(zip_buffer_t *buffer);\nzip_uint64_t _zip_buffer_left(zip_buffer_t *buffer);\nzip_buffer_t *_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size);\nzip_buffer_t *_zip_buffer_new_from_source(zip_source_t *src, zip_uint64_t size, zip_uint8_t *buf, zip_error_t *error);\nzip_uint64_t _zip_buffer_offset(zip_buffer_t *buffer);\nbool _zip_buffer_ok(zip_buffer_t *buffer);\nzip_uint8_t *_zip_buffer_peek(zip_buffer_t *buffer, zip_uint64_t length);\nint _zip_buffer_put(zip_buffer_t *buffer, const void *src, size_t length);\nint _zip_buffer_put_16(zip_buffer_t *buffer, zip_uint16_t i);\nint _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i);\nint _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i);\nint _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i);\nzip_uint64_t _zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);\nint _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length);\nint _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset);\nzip_uint64_t _zip_buffer_size(zip_buffer_t *buffer);\n\nvoid _zip_cdir_free(zip_cdir_t *);\nbool _zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error);\nzip_cdir_t *_zip_cdir_new(zip_error_t *);\nzip_int64_t _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors);\ntime_t _zip_d2u_time(const zip_dostime_t*);\nvoid _zip_deregister_source(zip_t *za, zip_source_t *src);\n\nbool _zip_dirent_apply_attributes(zip_dirent_t *, zip_file_attributes_t *, bool);\nint zip_dirent_check_consistency(zip_dirent_t *dirent);\nzip_dirent_t *_zip_dirent_clone(const zip_dirent_t *);\nvoid _zip_dirent_free(zip_dirent_t *);\nvoid _zip_dirent_finalize(zip_dirent_t *);\ntime_t zip_dirent_get_last_mod_mtime(zip_dirent_t *de);\nvoid _zip_dirent_init(zip_dirent_t *);\nbool _zip_dirent_merge(zip_dirent_t *de, zip_dirent_t *de_orig, bool replacing_data, zip_error_t *error);\nbool _zip_dirent_needs_zip64(const zip_dirent_t *, zip_flags_t);\nzip_dirent_t *_zip_dirent_new(void);\nbool zip_dirent_process_ef_zip64(zip_dirent_t * zde, const zip_uint8_t * ef, zip_uint64_t got_len, bool local, zip_error_t * error);\nzip_int64_t _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_uint64_t central_compressed_size, bool check_consistency, zip_error_t *error);\nvoid _zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64);\nvoid zip_dirent_torrentzip_normalize(zip_dirent_t *de);\n\nzip_int32_t _zip_dirent_size(zip_source_t *src, zip_uint16_t, zip_error_t *);\nint _zip_dirent_write(zip_t *za, zip_dirent_t *dirent, zip_flags_t flags);\n\nzip_extra_field_t *_zip_ef_clone(const zip_extra_field_t *, zip_error_t *);\nzip_extra_field_t *_zip_ef_delete_by_id(zip_extra_field_t *, zip_uint16_t, zip_uint16_t, zip_flags_t);\nvoid _zip_ef_free(zip_extra_field_t *);\nconst zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *, zip_uint16_t *, zip_uint16_t, zip_uint16_t, zip_flags_t, zip_error_t *);\nzip_extra_field_t *_zip_ef_merge(zip_extra_field_t *, zip_extra_field_t *);\nzip_extra_field_t *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_flags_t);\nbool _zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_flags_t, zip_extra_field_t **, zip_error_t *);\nzip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *);\nzip_uint16_t _zip_ef_size(const zip_extra_field_t *, zip_flags_t);\nint _zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags);\n\nvoid _zip_entry_finalize(zip_entry_t *);\nvoid _zip_entry_init(zip_entry_t *);\n\nvoid _zip_error_clear(zip_error_t *);\nvoid _zip_error_get(const zip_error_t *, int *, int *);\n\nvoid _zip_error_copy(zip_error_t *dst, const zip_error_t *src);\n\nconst zip_uint8_t *_zip_extract_extra_field_by_id(zip_error_t *, zip_uint16_t, int, const zip_uint8_t *, zip_uint16_t, zip_uint16_t *);\n\nint _zip_file_extra_field_prepare_for_change(zip_t *, zip_uint64_t);\nint _zip_file_fillbuf(void *, size_t, zip_file_t *);\nzip_uint64_t _zip_file_get_end(const zip_t *za, zip_uint64_t index, zip_error_t *error);\nzip_uint64_t _zip_file_get_offset(const zip_t *, zip_uint64_t, zip_error_t *);\n\nzip_dirent_t *_zip_get_dirent(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *);\n\nenum zip_encoding_type _zip_guess_encoding(zip_string_t *, enum zip_encoding_type);\nzip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t *const, zip_uint32_t, zip_uint32_t *, zip_error_t *);\n\nbool _zip_hash_add(zip_hash_t *hash, const zip_uint8_t *name, zip_uint64_t index, zip_flags_t flags, zip_error_t *error);\nbool _zip_hash_delete(zip_hash_t *hash, const zip_uint8_t *key, zip_error_t *error);\nvoid _zip_hash_free(zip_hash_t *hash);\nzip_int64_t _zip_hash_lookup(zip_hash_t *hash, const zip_uint8_t *name, zip_flags_t flags, zip_error_t *error);\nzip_hash_t *_zip_hash_new(zip_error_t *error);\nbool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error);\nbool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error);\n\nint _zip_mkstempm(char *path, int mode, bool create_file);\n\nzip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);\n\nvoid _zip_progress_end(zip_progress_t *progress);\nvoid _zip_progress_free(zip_progress_t *progress);\nint _zip_progress_start(zip_progress_t *progress);\nint _zip_progress_subrange(zip_progress_t *progress, double start, double end);\nint _zip_progress_update(zip_progress_t *progress, double value);\n\nbool zip_realloc(void **memory, zip_uint64_t *alloced_elements, zip_uint64_t element_size, zip_uint64_t additional_elements, zip_error_t *error);\n\n/* this symbol is extern so it can be overridden for regression testing */\nZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length);\nzip_uint32_t zip_random_uint32(void);\n\nint _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);\nint _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error);\nzip_uint8_t *_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error);\nint _zip_read_local_ef(zip_t *, zip_uint64_t);\nzip_string_t *_zip_read_string(zip_buffer_t *buffer, zip_source_t *src, zip_uint16_t length, bool nulp, zip_error_t *error);\nint _zip_register_source(zip_t *za, zip_source_t *src);\n\nvoid _zip_set_open_error(int *zep, const zip_error_t *err, int ze);\n\nbool zip_source_accept_empty(zip_source_t *src);\nzip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command);\nbool _zip_source_eof(zip_source_t *);\nint zip_source_get_dos_time(zip_source_t *src, zip_dostime_t *dos_time);\n\nzip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error);\nbool _zip_source_had_error(zip_source_t *);\nvoid _zip_source_invalidate(zip_source_t *src);\nzip_source_t *_zip_source_new(zip_error_t *error);\nint _zip_source_set_source_archive(zip_source_t *, zip_t *);\nzip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_uint64_t st_invalid, zip_file_attributes_t *attributes, zip_dostime_t *dostime, zip_t *source_archive, zip_uint64_t source_index, bool take_ownership, zip_error_t *error);\n\nint _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error);\nint _zip_string_equal(const zip_string_t *a, const zip_string_t *b);\nvoid _zip_string_free(zip_string_t *string);\nzip_uint32_t _zip_string_crc32(const zip_string_t *string);\nconst zip_uint8_t *_zip_string_get(zip_string_t *string, zip_uint32_t *lenp, zip_flags_t flags, zip_error_t *error);\nbool _zip_string_is_ascii(const zip_string_t *string);\nzip_uint16_t _zip_string_length(const zip_string_t *string);\nzip_string_t *_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags, zip_error_t *error);\nint _zip_string_write(zip_t *za, const zip_string_t *string);\nbool _zip_winzip_aes_decrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length);\nbool _zip_winzip_aes_encrypt(zip_winzip_aes_t *ctx, zip_uint8_t *data, zip_uint64_t length);\nbool _zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac);\nvoid _zip_winzip_aes_free(zip_winzip_aes_t *ctx);\nzip_winzip_aes_t *_zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t key_size, zip_uint8_t *password_verify, zip_error_t *error);\n\nvoid _zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len);\nvoid _zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len);\nzip_pkware_keys_t *_zip_pkware_keys_new(zip_error_t *error);\nvoid _zip_pkware_keys_free(zip_pkware_keys_t *keys);\nvoid _zip_pkware_keys_reset(zip_pkware_keys_t *keys);\n\nint _zip_changed(const zip_t *, zip_uint64_t *);\nconst char *_zip_get_name(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *);\nint _zip_local_header_read(zip_t *, int);\nvoid *_zip_memdup(const void *, size_t, zip_error_t *);\nzip_int64_t _zip_name_locate(zip_t *, const char *, zip_flags_t, zip_error_t *);\nzip_t *_zip_new(zip_error_t *);\n\nzip_int64_t _zip_file_replace(zip_t *, zip_uint64_t, const char *, zip_source_t *, zip_flags_t);\nint _zip_set_name(zip_t *, zip_uint64_t, const char *, zip_flags_t);\nint _zip_u2d_time(time_t, zip_dostime_t *, zip_error_t *);\nint _zip_unchange(zip_t *, zip_uint64_t, int);\nvoid _zip_unchange_data(zip_entry_t *);\nint _zip_write(zip_t *za, const void *data, zip_uint64_t length);\n\n#endif /* _HAD_ZIPINT_H */\n"
  },
  {
    "path": "external/libzip/libzip-config.cmake.in",
    "content": "@PACKAGE_INIT@\n\n# We need to supply transitive dependencies if this config is for a static library\nset(IS_SHARED @BUILD_SHARED_LIBS@)\nif (NOT IS_SHARED)\n  include(CMakeFindDependencyMacro)\n  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} \"${CMAKE_CURRENT_LIST_DIR}/modules\")\n\n  set(ENABLE_BZIP2 @BZIP2_FOUND@)\n  set(ENABLE_LZMA @LIBLZMA_FOUND@)\n  set(ENABLE_ZSTD @ZSTD_FOUND@)\n  set(ENABLE_GNUTLS @GNUTLS_FOUND@)\n  set(ENABLE_MBEDTLS @MBEDTLS_FOUND@)\n  set(ENABLE_OPENSSL @OPENSSL_FOUND@)\n\n  find_dependency(ZLIB 1.1.2)\n  if(ENABLE_BZIP2)\n    find_dependency(BZip2)\n  endif()\n\n  if(ENABLE_LZMA)\n    find_dependency(LibLZMA 5.2)\n  endif()\n\n  if(ENABLE_ZSTD)\n    find_dependency(zstd 1.3.6)\n  endif()\n\n  if(ENABLE_GNUTLS)\n    find_dependency(Nettle 3.0)\n    find_dependency(GnuTLS)\n  endif()\n  if(ENABLE_MBEDTLS)\n    find_dependency(MbedTLS 1.0)\n  endif()\n  if(ENABLE_OPENSSL)\n    find_dependency(OpenSSL)\n  endif()\nendif()\n\n# Provide all our library targets to users.\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/libzip-targets.cmake\")\n\ncheck_required_components(libzip)\n\n"
  },
  {
    "path": "external/libzip/libzip.pc.in",
    "content": "prefix=@CMAKE_INSTALL_PREFIX@\nexec_prefix=${prefix}\nbindir=@bindir@\nlibdir=@libdir@\nincludedir=@includedir@\n\nzipcmp=${bindir}/zipcmp\n\nName: libzip\nDescription: library for handling zip archives\nVersion: @PROJECT_VERSION@\nLibs: @PKG_CONFIG_RPATH@ -L${libdir} -lzip\nLibs.private: @LIBS@\nCflags: -I${includedir}\n"
  },
  {
    "path": "external/libzip/man/CMakeLists.txt",
    "content": "set(MAN_PAGES\n  ZIP_SOURCE_GET_ARGS.3\n  libzip.3\n  zip.5\n  zip_add.3\n  zip_add_dir.3\n  zip_close.3\n  zip_compression_method_supported.3\n  zip_delete.3\n  zip_dir_add.3\n  zip_discard.3\n  zip_encryption_method_supported.3\n  zip_error.5\n  zip_error_clear.3\n  zip_error_code_system.3\n  zip_error_code_zip.3\n  zip_error_fini.3\n  zip_error_get.3\n  zip_error_get_sys_type.3\n  zip_error_init.3\n  zip_error_set.3\n  zip_error_set_from_source.3\n  zip_error_strerror.3\n  zip_error_system_type.3\n  zip_error_to_data.3\n  zip_error_to_str.3\n  zip_errors.3\n  zip_fclose.3\n  zip_fdopen.3\n  zip_file.5\n  zip_file_add.3\n  zip_file_attributes_init.3\n  zip_file_extra_field_delete.3\n  zip_file_extra_field_get.3\n  zip_file_extra_field_set.3\n  zip_file_extra_fields_count.3\n  zip_file_get_comment.3\n  zip_file_get_error.3\n  zip_file_get_external_attributes.3\n  zip_file_rename.3\n  zip_file_set_comment.3\n  zip_file_set_encryption.3\n  zip_file_set_external_attributes.3\n  zip_file_set_mtime.3\n  zip_file_strerror.3\n  zip_fopen.3\n  zip_fopen_encrypted.3\n  zip_fread.3\n  zip_fseek.3\n  zip_ftell.3\n  zip_get_archive_comment.3\n  zip_get_archive_flag.3\n  zip_get_error.3\n  zip_get_file_comment.3\n  zip_get_name.3\n  zip_get_num_entries.3\n  zip_get_num_files.3\n  zip_libzip_version.3\n  zip_name_locate.3\n  zip_open.3\n  zip_register_cancel_callback_with_state.3\n  zip_register_progress_callback.3\n  zip_register_progress_callback_with_state.3\n  zip_rename.3\n  zip_set_archive_comment.3\n  zip_set_archive_flag.3\n  zip_set_default_password.3\n  zip_set_file_comment.3\n  zip_set_file_compression.3\n  zip_source.5\n  zip_source_begin_write.3\n  zip_source_buffer.3\n  zip_source_buffer_fragment.3\n  zip_source_close.3\n  zip_source_commit_write.3\n  zip_source_error.3\n  zip_source_file.3\n  zip_source_filep.3\n  zip_source_free.3\n  zip_source_function.3\n  zip_source_is_deleted.3\n  zip_source_is_seekable.3\n  zip_source_layered.3\n  zip_source_keep.3\n  zip_source_make_command_bitmap.3\n  zip_source_open.3\n  zip_source_read.3\n  zip_source_rollback_write.3\n  zip_source_seek.3\n  zip_source_seek_compute_offset.3\n  zip_source_seek_write.3\n  zip_source_stat.3\n  zip_source_tell.3\n  zip_source_tell_write.3\n  zip_source_win32a.3\n  zip_source_win32handle.3\n  zip_source_win32w.3\n  zip_source_window_create.3\n  zip_source_write.3\n  zip_source_zip.3\n  zip_source_zip_file.3\n  zip_stat.3\n  zip_stat_init.3\n  zip_unchange.3\n  zip_unchange_all.3\n  zip_unchange_archive.3\n  zipcmp.1\n  zipmerge.1\n  ziptool.1\n)\n\nforeach(MAN_PAGE ${MAN_PAGES})\n  string(REGEX REPLACE \"[1-9]$\" \"${DOCUMENTATION_FORMAT}\" SOURCE_FILE ${MAN_PAGE})\n  if(LIBZIP_DO_INSTALL)\n    if (DOCUMENTATION_FORMAT MATCHES \"html\")\n      install(FILES ${PROJECT_BINARY_DIR}/man/${MAN_PAGE} DESTINATION ${CMAKE_INSTALL_DOCDIR}/${PROJECT_NAME} RENAME ${SOURCE_FILE})\n    else()\n      string(REGEX REPLACE \".*(.)$\" \"man\\\\1\" SUBDIR ${MAN_PAGE})\n      install(FILES ${PROJECT_BINARY_DIR}/man/${MAN_PAGE} DESTINATION ${CMAKE_INSTALL_MANDIR}/${SUBDIR})\n    endif()\n  endif()\n  # configure_file does not find out about updates to the sources, and it does not provide a target\n  #configure_file(${SOURCE_FILE} ${MAN_PAGE} COPYONLY)\n  add_custom_command(OUTPUT ${MAN_PAGE}\n    DEPENDS ${SOURCE_FILE}\n    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE}\n    COMMENT \"Preparing ${MAN_PAGE}\"\n    )\n\n  string(REGEX REPLACE \"[1-9]$\" \"html\" HTML_FILE ${MAN_PAGE})\n  string(REGEX REPLACE \"[1-9]$\" \"man\" MAN_FILE ${MAN_PAGE})\n  string(REGEX REPLACE \"[1-9]$\" \"mdoc\" MDOC_FILE ${MAN_PAGE})\n\n  # html re-generation\n  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE}\n    DEPENDS ${MDOC_FILE}\n    COMMAND ${CMAKE_COMMAND} -DIN=${CMAKE_CURRENT_SOURCE_DIR}/${MDOC_FILE} -DOUT=${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE} -P ${CMAKE_CURRENT_SOURCE_DIR}/update-html.cmake\n    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${HTML_FILE}\n    )\n  list(APPEND UPDATEHTML ${CMAKE_CURRENT_BINARY_DIR}/${HTML_FILE})\n\n  # man re-generation\n  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE}\n    DEPENDS ${MDOC_FILE}\n     COMMAND ${CMAKE_COMMAND} -DIN=${CMAKE_CURRENT_SOURCE_DIR}/${MDOC_FILE} -DOUT=${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE} -P ${CMAKE_CURRENT_SOURCE_DIR}/update-man.cmake\n    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/${MAN_FILE}\n    )\n  list(APPEND UPDATEMAN ${CMAKE_CURRENT_BINARY_DIR}/${MAN_FILE})\nendforeach()\nadd_custom_target(man ALL DEPENDS ${MAN_PAGES})\nadd_custom_target(update-man DEPENDS ${UPDATEMAN})\nadd_custom_target(update-html DEPENDS ${UPDATEHTML})\n\nfile(STRINGS links MANPAGE_LINKS)\nforeach(LINKS_LINE ${MANPAGE_LINKS})\n  if(${LINKS_LINE} MATCHES \"(.*) (.*)\")\n    set(SOURCE ${CMAKE_MATCH_1})\n    set(TARGET ${CMAKE_MATCH_2})\n    if(LIBZIP_DO_INSTALL)\n      if (DOCUMENTATION_FORMAT MATCHES \"html\")\n\tINSTALL(FILES ${PROJECT_BINARY_DIR}/man/${SOURCE}.3 DESTINATION ${CMAKE_INSTALL_DOCDIR}/${PROJECT_NAME} RENAME ${TARGET}.html)\n      else()\n\tINSTALL(FILES ${PROJECT_BINARY_DIR}/man/${SOURCE}.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 RENAME ${TARGET}.3)\n      endif()\n    endif()\n  endif()\nendforeach()\n\nadd_custom_target(update_zip_errors\n  COMMAND sh ${PROJECT_SOURCE_DIR}/man/make_zip_errors.sh ${CMAKE_SOURCE_DIR}/lib/zip.h ${PROJECT_SOURCE_DIR}/man/zip_errors.mdoc\n  DEPENDS ${CMAKE_SOURCE_DIR}/lib/zip.h ${PROJECT_SOURCE_DIR}/man/zip_errors.mdoc\n)\n"
  },
  {
    "path": "external/libzip/man/ZIP_SOURCE_GET_ARGS.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/ZIP_SOURCE_GET_ARGS.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" ZIP_SOURCE_GET_ARGS -- validate and cast arguments to source callback\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_GET_ARGS\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBZIP_SOURCE_GET_ARGS\\fR\n\\- validate and cast arguments to source callback\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fItype *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBZIP_SOURCE_GET_ARGS\\fR(\\fItype\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBZIP_SOURCE_GET_ARGS\\fR()\nmacro casts\n\\fIdata\\fR\nto a pointer to\n\\fItype\\fR.\n.SH \"RETURN VALUES\"\nOn success,\n\\fBZIP_SOURCE_GET_ARGS\\fR()\nreturns\n\\fIdata\\fR.\nIn case of error, it returns\n\\fRNULL\\fR\nand sets\n\\fIerror\\fR.\n.SH \"ERRORS\"\n\\fBZIP_SOURCE_GET_ARGS\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIlen\\fR\nis less than the size of\n\\fItype\\fR\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source_function(3)\n.SH \"HISTORY\"\n\\fBZIP_SOURCE_GET_ARGS\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/ZIP_SOURCE_GET_ARGS.mdoc",
    "content": ".\\\" ZIP_SOURCE_GET_ARGS -- validate and cast arguments to source callback\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_GET_ARGS 3\n.Os\n.Sh NAME\n.Nm ZIP_SOURCE_GET_ARGS\n.Nd validate and cast arguments to source callback\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft type *\n.Fn ZIP_SOURCE_GET_ARGS \"type\" \"void *data\" \"zip_uint64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe\n.Fn ZIP_SOURCE_GET_ARGS\nmacro casts\n.Ar data\nto a pointer to\n.Ar type .\n.Sh RETURN VALUES\nOn success,\n.Fn ZIP_SOURCE_GET_ARGS\nreturns\n.Ar data .\nIn case of error, it returns\n.Dv NULL\nand sets\n.Ar error .\n.Sh ERRORS\n.Fn ZIP_SOURCE_GET_ARGS\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar len\nis less than the size of\n.Ar type\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source_function 3\n.Sh HISTORY\n.Fn ZIP_SOURCE_GET_ARGS\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/handle_links",
    "content": "#!/usr/bin/env perl\n\nuse strict;\n\nmy $operation = shift @ARGV;\n\nif ($operation !~ m/^(install|uninstall)$/) {\n    print STDERR \"$0: unknown operation $operation\\n\";\n    exit(1);\n}\n\nmy %options = ();\n\nfor my $arg (@ARGV) {\n    if ($arg =~ m/([^=]*)=(.*)/) {\n        $options{$1} = $2;\n    }\n    else {\n        print STDERR \"$0: can't parse option [$arg]\\n\";\n        exit(1);\n    }\n}\n\nfor my $option (qw(command directory extension file)) {\n    unless (defined($options{$option})) {\n        print STDERR \"$0: required variable $option not provided\\n\";\n        exit(1);\n    }\n}\n\nmy $fh;\nunless (open $fh, '<', $options{file}) {\n    print STDERR \"$0: can't open links file '$options{file}': $!\";\n    exit(1);\n}\n\nmy @cmd = split /\\s+/, $options{command};\n\nwhile (my $line = <$fh>) {\n    chomp $line;\n    my @args = split /\\s+/, $line;\n\n    process(@args);\n}\n\nsub process {\n    my ($source, @destinations) = @_;\n\n    my @args = (@cmd);\n\n    if ($operation eq 'install') {\n        push @args, \"$options{directory}/$source.$options{extension}\";\n    }\n\n    for my $destination (@destinations) {\n        push @args, \"$options{directory}/$destination.$options{extension}\";\n        run_command(@args);\n        pop @args;\n    }\n}\n\nsub run_command {\n    print (join ' ', @_);\n    print \"\\n\";\n\n    my $ret = system(@_);\n\n    if ($ret != 0) {\n        print STDERR \"$0: command failed: $?\\n\";\n        exit(1);\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "external/libzip/man/libzip.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/libzip.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" libzip.mdoc -- general overview of available functions\n.\\\" Copyright (C) 2005-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"LIBZIP\" \"3\" \"May 5, 2025\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBlibzip\\fR\n\\- library for manipulating zip archives\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.SH \"DESCRIPTION\"\n\\fBlibzip\\fR\nis a library for reading, creating, and modifying zip archives.\n.PP\nThe main design criteria for\n\\fBlibzip\\fR\nwere:\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nMaintain a stable API without breaking backwards compatibility.\n.TP 4n\n\\fB\\(bu\\fR\nDo not create corrupt files, even in case of errors.\n.TP 4n\n\\fB\\(bu\\fR\nDo not delete data.\n.TP 4n\n\\fB\\(bu\\fR\nBe efficient.\n.PD\n.PP\nFor this reason, when modifying zip archives,\n\\fBlibzip\\fR\nwrites to a temporary file and replaces the original\nzip archive atomically.\n.SH \"GENERAL NOTES\"\nWhen adding files to an archive, the file data is only read when the\nnew archive is written.\nTherefore all files added must remain valid until the archive is\nclosed with\nzip_close(3)\nor\nzip_discard(3).\n.PP\nUnless explicitly documented, functions should not be passed\n\\fRNULL\\fR\npointers as arguments.\n.SH \"DATA TYPES\"\nThese data types correspond to central concepts in\n\\fBlibzip\\fR.\nMost of them are private, meaning you can't allocate them or access their members directly.\nThis allows extending the structures in the future without breaking compatibility.\n.SS \"zip_t\"\nThis type represents an opened archive.\nSee\nzip(5).\n.SS \"zip_file_t\"\nThis type represents a file from an archive that has been opened for reading.\nSee\nzip_file(5).\n.SS \"zip_source_t\"\nThis type represents a source (or destination) of data.\nIt is used in\n\\fBlibzip\\fR\nfor providing data when adding or replacing files, accessing data from a file inside an archive, and the data for the archive as a whole.\nSee\nzip_source(5).\n.SS \"zip_error_t\"\nThis type represents information about an error.\nIts type can be checked against pre-defined constants and it can be converted to a human readable string.\nSee\nzip_error(5).\n.SH \"FILE NAMES\"\n.SS \"Encoding\"\nNames of files in the host file system are expected in UTF-8 encoding.\nOn Windows, variants for ASCII and UTF-16 are also available.\n.PP\nNames of files inside archives are by default expected in UTF-8 encoding.\nOther encodings can be requested by using the flags\n\\fRZIP_FL_ENC_CP437\\fR\nand\n\\fRZIP_FL_ENC_RAW\\fR.\n.PP\nFor details see the relevant man pages.\n.SS \"Directory Separator\"\nThe zip format requires the use of forward slash\n(\\(oq/\\(cq)\nas directory separator.\nSince backslash\n(\\(oq\\e\\(cq)\ncan be part of a valid file name on Unix systems,\n\\fBlibzip\\fR\ndoes not automatically convert them, even on Windows.\nIt is the responsibility of the programmer to ensure that all\ndirectory separators are passed as forward slashes to\n\\fBlibzip\\fR.\n.SH \"THREAD SAFETY\"\nIn general, different zip archives opened by\n\\fBlibzip\\fR\nare independent of each other and can be used by parallel-running\nthreads without locking.\nIf you want to use an archive from multiple threads, you have to\nsynchronize access to it yourself.\nIf you use an archive as a source for\nzip_file_add(3)\nor\nzip_file_replace(3),\naccess to the target archive must be synchronized with access to the\nsource archive as well.\n.SH \"READING ZIP ARCHIVES\"\n.SS \"Open Archive\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_open(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_open_from_source(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fdopen(3)\n.PD\n.SS \"Get Archive Attributes\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_get_archive_comment(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_get_archive_flag(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_get_num_entries(3)\n.PD\n.SS \"Find Files\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_name_locate(3)\n.SS \"Read Files\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_fopen(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_fopen_encrypted(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fopen_index(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fopen_index_encrypted(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fread(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_is_seekable(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fseek(3)\n(uncompressed files only)\n.TP 4n\n\\fB\\(bu\\fR\nzip_ftell(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_fclose(3)\n.PD\n.SS \"Close Archive\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_close(3)\n.SS \"Get File Attributes\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_stat(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_get_comment(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_get_external_attributes(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_get_name(3)\n.PD\n.SS \"Miscellaneous\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_compression_method_supported(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_encryption_method_supported(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_set_default_password(3)\n.PD\n.SH \"CREATING/MODIFYING ZIP ARCHIVES\"\n.SS \"Create/Open Archive\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_open(3)\n.SS \"Add/Change Files and Directories\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_dir_add(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_add(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_replace(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_set_comment(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_set_dostime(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_set_external_attributes(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_set_encryption(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_set_mtime(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_set_file_compression(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_buffer(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_file(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_filep(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_zip(3)\n.PD\n.SS \"Rename Files\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_rename(3)\n.SS \"Delete Files\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_delete(3)\n.SS \"Revert Changes\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_unchange(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_unchange_all(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_unchange_archive(3)\n.PD\n.SS \"Read/Modify Extra Fields\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_field_delete(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_field_delete_by_id(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_field_get(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_field_get_by_id(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_field_set(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_fields_count(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_extra_fields_count_by_id(3)\n.PD\n.SS \"Close Archive (Writing)\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_close(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_discard(3)\n.PD\n.SS \"Miscellaneous (Writing)\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_attributes_init(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_libzip_version(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_register_cancel_callback_with_state(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_register_progress_callback_with_state(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_set_archive_comment(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_set_archive_flag(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source(5)\n.PD\n.SH \"SOURCES\"\n.SS \"Create Source\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_buffer(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_file(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_filep(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_function(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_layered(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_zip(3)\n.PD\n.SS \"Using Source\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_add(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_replace(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_open_from_source(3)\n.PD\n.SS \"Implementing Source\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_pass_to_lower_layer(3)\n.SS \"Source Life Cycle\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_free(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_source_keep(3)\n.PD\n.SH \"ERROR HANDLING\"\n.TP 4n\n\\fB\\(bu\\fR\nzip_error_strerror(3)\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\nzip_strerror(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_strerror(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_file_get_error(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_get_error(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_error_init_with_code(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_error_set(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_error_set_from_source(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_error_system_type(3)\n.TP 4n\n\\fB\\(bu\\fR\nzip_errors(3)\n.PD\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/libzip.mdoc",
    "content": ".\\\" libzip.mdoc -- general overview of available functions\n.\\\" Copyright (C) 2005-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt LIBZIP 3\n.Os\n.Sh NAME\n.Nm libzip\n.Nd library for manipulating zip archives\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Sh DESCRIPTION\n.Nm\nis a library for reading, creating, and modifying zip archives.\n.Pp\nThe main design criteria for\n.Nm\nwere:\n.Bl -bullet -compact\n.It\nMaintain a stable API without breaking backwards compatibility.\n.It\nDo not create corrupt files, even in case of errors.\n.It\nDo not delete data.\n.It\nBe efficient.\n.El\n.Pp\nFor this reason, when modifying zip archives,\n.Nm\nwrites to a temporary file and replaces the original\nzip archive atomically.\n.Sh GENERAL NOTES\nWhen adding files to an archive, the file data is only read when the\nnew archive is written.\nTherefore all files added must remain valid until the archive is\nclosed with\n.Xr zip_close 3\nor\n.Xr zip_discard 3 .\n.Pp\nUnless explicitly documented, functions should not be passed\n.Dv NULL\npointers as arguments.\n.Sh DATA TYPES\nThese data types correspond to central concepts in\n.Nm .\nMost of them are private, meaning you can't allocate them or access their members directly.\nThis allows extending the structures in the future without breaking compatibility.\n.Ss zip_t\nThis type represents an opened archive.\nSee\n.Xr zip 5 .\n.Ss zip_file_t\nThis type represents a file from an archive that has been opened for reading.\nSee\n.Xr zip_file 5 .\n.Ss zip_source_t\nThis type represents a source (or destination) of data.\nIt is used in\n.Nm\nfor providing data when adding or replacing files, accessing data from a file inside an archive, and the data for the archive as a whole.\nSee\n.Xr zip_source 5 .\n.Ss zip_error_t\nThis type represents information about an error.\nIts type can be checked against pre-defined constants and it can be converted to a human readable string.\nSee\n.Xr zip_error 5 .\n.Sh FILE NAMES\n.Ss Encoding\nNames of files in the host file system are expected in UTF-8 encoding.\nOn Windows, variants for ASCII and UTF-16 are also available.\n.Pp\nNames of files inside archives are by default expected in UTF-8 encoding.\nOther encodings can be requested by using the flags\n.Dv ZIP_FL_ENC_CP437\nand\n.Dv ZIP_FL_ENC_RAW .\n.Pp\nFor details see the relevant man pages.\n.Ss Directory Separator\nThe zip format requires the use of forward slash\n.Pq Sq /\nas directory separator.\nSince backslash\n.Pq Sq \\e\ncan be part of a valid file name on Unix systems,\n.Nm\ndoes not automatically convert them, even on Windows.\nIt is the responsibility of the programmer to ensure that all\ndirectory separators are passed as forward slashes to\n.Nm .\n.Sh THREAD SAFETY\nIn general, different zip archives opened by\n.Nm\nare independent of each other and can be used by parallel-running\nthreads without locking.\nIf you want to use an archive from multiple threads, you have to\nsynchronize access to it yourself.\nIf you use an archive as a source for\n.Xr zip_file_add 3\nor\n.Xr zip_file_replace 3 ,\naccess to the target archive must be synchronized with access to the\nsource archive as well.\n.Sh READING ZIP ARCHIVES\n.Ss Open Archive\n.Bl -bullet -compact\n.It\n.Xr zip_open 3\n.It\n.Xr zip_open_from_source 3\n.It\n.Xr zip_fdopen 3\n.El\n.Ss Get Archive Attributes\n.Bl -bullet -compact\n.It\n.Xr zip_get_archive_comment 3\n.It\n.Xr zip_get_archive_flag 3\n.It\n.Xr zip_get_num_entries 3\n.El\n.Ss Find Files\n.Bl -bullet -compact\n.It\n.Xr zip_name_locate 3\n.El\n.Ss Read Files\n.Bl -bullet -compact\n.It\n.Xr zip_fopen 3\n.It\n.Xr zip_fopen_encrypted 3\n.It\n.Xr zip_fopen_index 3\n.It\n.Xr zip_fopen_index_encrypted 3\n.It\n.Xr zip_fread 3\n.It\n.Xr zip_file_is_seekable 3\n.It\n.Xr zip_fseek 3\n(uncompressed files only)\n.It\n.Xr zip_ftell 3\n.It\n.Xr zip_fclose 3\n.El\n.Ss Close Archive\n.Bl -bullet -compact\n.It\n.Xr zip_close 3\n.El\n.Ss Get File Attributes\n.Bl -bullet -compact\n.It\n.Xr zip_stat 3\n.It\n.Xr zip_file_get_comment 3\n.It\n.Xr zip_file_get_external_attributes 3\n.It\n.Xr zip_get_name 3\n.El\n.Ss Miscellaneous\n.Bl -bullet -compact\n.It\n.Xr zip_compression_method_supported 3\n.It\n.Xr zip_encryption_method_supported 3\n.It\n.Xr zip_set_default_password 3\n.El\n.Sh CREATING/MODIFYING ZIP ARCHIVES\n.Ss Create/Open Archive\n.Bl -bullet -compact\n.It\n.Xr zip_open 3\n.El\n.Ss Add/Change Files and Directories\n.Bl -bullet -compact\n.It\n.Xr zip_dir_add 3\n.It\n.Xr zip_file_add 3\n.It\n.Xr zip_file_replace 3\n.It\n.Xr zip_file_set_comment 3\n.It\n.Xr zip_file_set_dostime 3\n.It\n.Xr zip_file_set_external_attributes 3\n.It\n.Xr zip_file_set_encryption 3\n.It\n.Xr zip_file_set_mtime 3\n.It\n.Xr zip_set_file_compression 3\n.It\n.Xr zip_source_buffer 3\n.It\n.Xr zip_source_file 3\n.It\n.Xr zip_source_filep 3\n.It\n.Xr zip_source_zip 3\n.El\n.Ss Rename Files\n.Bl -bullet -compact\n.It\n.Xr zip_rename 3\n.El\n.Ss Delete Files\n.Bl -bullet -compact\n.It\n.Xr zip_delete 3\n.El\n.Ss Revert Changes\n.Bl -bullet -compact\n.It\n.Xr zip_unchange 3\n.It\n.Xr zip_unchange_all 3\n.It\n.Xr zip_unchange_archive 3\n.El\n.Ss Read/Modify Extra Fields\n.Bl -bullet -compact\n.It\n.Xr zip_file_extra_field_delete 3\n.It\n.Xr zip_file_extra_field_delete_by_id 3\n.It\n.Xr zip_file_extra_field_get 3\n.It\n.Xr zip_file_extra_field_get_by_id 3\n.It\n.Xr zip_file_extra_field_set 3\n.It\n.Xr zip_file_extra_fields_count 3\n.It\n.Xr zip_file_extra_fields_count_by_id 3\n.El\n.Ss Close Archive (Writing)\n.Bl -bullet -compact\n.It\n.Xr zip_close 3\n.It\n.Xr zip_discard 3\n.El\n.Ss Miscellaneous (Writing)\n.Bl -bullet -compact\n.It\n.Xr zip_file_attributes_init 3\n.It\n.Xr zip_libzip_version 3\n.It\n.Xr zip_register_cancel_callback_with_state 3\n.It\n.Xr zip_register_progress_callback_with_state 3\n.It\n.Xr zip_set_archive_comment 3\n.It\n.Xr zip_set_archive_flag 3\n.It\n.Xr zip_source 5\n.El\n.Sh SOURCES\n.Ss Create Source\n.Bl -bullet -compact\n.It\n.Xr zip_source_buffer 3\n.It\n.Xr zip_source_file 3\n.It\n.Xr zip_source_filep 3\n.It\n.Xr zip_source_function 3\n.It\n.Xr zip_source_layered 3\n.It\n.Xr zip_source_zip 3\n.El\n.Ss Using Source\n.Bl -bullet -compact\n.It\n.Xr zip_file_add 3\n.It\n.Xr zip_file_replace 3\n.It\n.Xr zip_open_from_source 3\n.El\n.Ss Implementing Source\n.Bl -bullet -compact\n.It\n.Xr zip_source_pass_to_lower_layer 3\n.El\n.Ss Source Life Cycle\n.Bl -bullet -compact\n.It\n.Xr zip_source_free 3\n.It\n.Xr zip_source_keep 3\n.El\n.Sh ERROR HANDLING\n.Bl -bullet -compact\n.It\n.Xr zip_error_strerror 3\n.It\n.Xr zip_strerror 3\n.It\n.Xr zip_file_strerror 3\n.It\n.Xr zip_file_get_error 3\n.It\n.Xr zip_get_error 3\n.It\n.Xr zip_error_init_with_code 3\n.It\n.Xr zip_error_set 3\n.It\n.Xr zip_error_set_from_source 3\n.It\n.Xr zip_error_system_type 3\n.It\n.Xr zip_errors 3\n.El\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/links",
    "content": "zip_add zip_replace\nzip_error_clear zip_file_error_clear\nzip_error_get zip_file_error_get\nzip_error_init zip_error_init_with_code\nzip_file_add zip_file_replace\nzip_file_extra_field_delete zip_file_extra_field_delete_by_id\nzip_file_extra_field_get zip_file_extra_field_get_by_id\nzip_file_extra_fields_count zip_file_extra_fields_count_by_id\nzip_file_set_mtime zip_file_set_dostime\nzip_file_strerror zip_strerror\nzip_fopen zip_fopen_index\nzip_fopen_encrypted zip_fopen_index_encrypted\nzip_fseek zip_file_is_seekable\nzip_open zip_open_from_source\nzip_source_begin_write zip_source_begin_write_cloning\nzip_source_buffer zip_source_buffer_create\nzip_source_buffer_fragment zip_source_buffer_fragment_create\nzip_source_file zip_source_file_create\nzip_source_filep zip_source_filep_create\nzip_source_function zip_source_function_create\nzip_source_layered zip_source_layered_create\nzip_source_win32a zip_source_win32a_create\nzip_source_win32handle zip_source_win32handle_create\nzip_source_win32w zip_source_win32w_create\nzip_source_zip zip_source_zip_create\nzip_source_zip_file zip_source_zip_file_create\nzip_stat zip_stat_index\n"
  },
  {
    "path": "external/libzip/man/update-html.cmake",
    "content": "# expect variables IN and OUT\nEXECUTE_PROCESS(COMMAND mandoc -T html -Oman=%N.html,style=../nih-man.css ${IN}\n  OUTPUT_VARIABLE HTML)\nSET(LINKBASE \"http://pubs.opengroup.org/onlinepubs/9699919799/functions/\")\nSTRING(REGEX REPLACE \"(<a class=\\\"Xr\\\" href=\\\")([^\\\"]*)(\\\">)\" \"\\\\1${LINKBASE}\\\\2\\\\3\" HTML \"${HTML}\")\nSTRING(REGEX REPLACE \"${LINKBASE}(libzip|zip)\" \"\\\\1\" HTML \"${HTML}\")\nSTRING(REGEX REPLACE \"NetBSD [0-9.]*\" \"NiH\" HTML \"${HTML}\")\nFILE(WRITE ${OUT}.new \"${HTML}\")\nCONFIGURE_FILE(${OUT}.new ${OUT} COPYONLY)\nFILE(REMOVE ${OUT}.new)\n\n\n"
  },
  {
    "path": "external/libzip/man/update-man.cmake",
    "content": "# expect variables IN and OUT\nEXECUTE_PROCESS(COMMAND mandoc -T man ${IN} OUTPUT_VARIABLE MAN)\nSTRING(REGEX REPLACE \"(NetBSD|macOS) [0-9.]*\" \"NiH\" MAN \"${MAN}\")\nFILE(WRITE ${OUT}.new \"${MAN}\")\nCONFIGURE_FILE(${OUT}.new ${OUT} COPYONLY)\nFILE(REMOVE ${OUT}.new)\n\n"
  },
  {
    "path": "external/libzip/man/zip.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip.mdoc -- description of zip_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP\" \"5\" \"May 5, 2025\" \"NiH\" \"File Formats Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip\\fR\n\\- zip archive structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_t *archive\\fR;\n.SH \"DESCRIPTION\"\nA\n\\fBzip\\fR\nrepresents an open zip archive and is used for all functions accessing and modifying archives.\n.PP\nIt is created with\nzip_open(3),\nzip_open_from_source(3),\nor\nzip_fdopen(3).\n.PP\nIt is closed with\nzip_close(3)\n(keeping changes) or\nzip_discard(3)\n(discarding changes).\n.PP\nAll objects representing parts of an archive (like\n\\fIzip_file_t\\fR)\nare only valid while the archive remains open.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3),\nzip_discard(3),\nzip_fopen(3),\nzip_open(3),\nzip_open_from_source(3)\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip.mdoc",
    "content": ".\\\" zip.mdoc -- description of zip_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt ZIP 5\n.Os\n.Sh NAME\n.Nm zip\n.Nd zip archive structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt zip_t *archive ;\n.Sh DESCRIPTION\nA\n.Nm\nrepresents an open zip archive and is used for all functions accessing and modifying archives.\n.Pp\nIt is created with\n.Xr zip_open 3 ,\n.Xr zip_open_from_source 3 ,\nor\n.Xr zip_fdopen 3 .\n.Pp\nIt is closed with\n.Xr zip_close 3\n(keeping changes) or\n.Xr zip_discard 3\n(discarding changes).\n.Pp\nAll objects representing parts of an archive (like\n.Vt zip_file_t )\nare only valid while the archive remains open.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3 ,\n.Xr zip_discard 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_open 3 ,\n.Xr zip_open_from_source 3\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_add.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_add.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_add.mdoc -- add files to zip archive\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ADD\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_add\\fR,\n\\fBzip_replace\\fR\n\\- add file to zip archive or replace file in zip archive (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_add\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *name\\fR, \\fIzip_source_t\\ *source\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_replace\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_add\\fR()\nis the obsolete version of\nzip_file_add(3).\nIt is the same as calling\nzip_file_add(3)\nwith an empty\n\\fIflags\\fR\nargument.\nSimilarly, the\n\\fBzip_replace\\fR()\nfunction is the obsolete version of\nzip_file_replace(3).\nIt is the same as calling\nzip_file_replace(3)\nwith an empty\n\\fIflags\\fR\nargument.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3)\n.SH \"HISTORY\"\n\\fBzip_add\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the return type was changed from\n\\fIint\\fR\nto\n\\fIzip_int64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_file_add\\fR()\ninstead.\n.PP\n\\fBzip_replace\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_file_replace\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_add.mdoc",
    "content": ".\\\" zip_add.mdoc -- add files to zip archive\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ADD 3\n.Os\n.Sh NAME\n.Nm zip_add ,\n.Nm zip_replace\n.Nd add file to zip archive or replace file in zip archive (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_add \"zip_t *archive\" \"const char *name\" \"zip_source_t *source\"\n.Ft int\n.Fn zip_replace \"zip_t *archive\" \"zip_uint64_t index\" \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_add\nis the obsolete version of\n.Xr zip_file_add 3 .\nIt is the same as calling\n.Xr zip_file_add 3\nwith an empty\n.Ar flags\nargument.\nSimilarly, the\n.Fn zip_replace\nfunction is the obsolete version of\n.Xr zip_file_replace 3 .\nIt is the same as calling\n.Xr zip_file_replace 3\nwith an empty\n.Ar flags\nargument.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3\n.Sh HISTORY\n.Fn zip_add\nwas added in libzip 0.6.\nIn libzip 0.10 the return type was changed from\n.Vt int\nto\n.Vt zip_int64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_file_add\ninstead.\n.Pp\n.Fn zip_replace\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_file_replace\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_add_dir.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_add_dir.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_add_dir.mdoc -- add directory to zip archive\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ADD_DIR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_add_dir\\fR\n\\- add directory to zip archive (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_add_dir\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *name\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_add_dir\\fR()\nis the obsolete version of\nzip_dir_add(3).\nIt is the same as calling\nzip_dir_add(3)\nwith an empty flags argument.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_dir_add(3)\n.SH \"HISTORY\"\n\\fBzip_add_dir\\fR()\nwas added in libzip 0.8.\nIn libzip 0.10 the return type was changed from\n\\fIint\\fR\nto\n\\fIzip_int64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_dir_add\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_add_dir.mdoc",
    "content": ".\\\" zip_add_dir.mdoc -- add directory to zip archive\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ADD_DIR 3\n.Os\n.Sh NAME\n.Nm zip_add_dir\n.Nd add directory to zip archive (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_add_dir \"zip_t *archive\" \"const char *name\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_add_dir\nis the obsolete version of\n.Xr zip_dir_add 3 .\nIt is the same as calling\n.Xr zip_dir_add 3\nwith an empty flags argument.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_dir_add 3\n.Sh HISTORY\n.Fn zip_add_dir\nwas added in libzip 0.8.\nIn libzip 0.10 the return type was changed from\n.Vt int\nto\n.Vt zip_int64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_dir_add\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_close.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_close.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_close.mdoc -- close zip archive\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_CLOSE\" \"3\" \"January 23, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_close\\fR\n\\- close zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_close\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_close\\fR()\nfunction writes any changes made to\n\\fIarchive\\fR\nto disk.\nIf\n\\fIarchive\\fR\ncontains no files, the file is completely removed (no empty archive is\nwritten), unless the archive flag\n\\fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\\fR\nis set.\nIf successful,\n\\fIarchive\\fR\nis freed.\nOtherwise\n\\fIarchive\\fR\nis left unchanged and must still be freed.\n.PP\nTo close and free a zip archive without saving changes, use\nzip_discard(3).\n.PP\nProgress updates for GUIs can be implemented using\nzip_register_progress_callback_with_state(3).\nCancelling the write of an archive during\n\\fBzip_close\\fR\ncan be implemented using\nzip_register_cancel_callback_with_state(3).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_close\\fR()\nwill fail if:\n.TP 19n\n[\\fRZIP_ER_EOF\\fR]\nUnexpected end-of-file found while reading from a file.\n.TP 19n\n[\\fRZIP_ER_INTERNAL\\fR]\nThe callback function of an added or replaced file returned an\nerror but failed to report which.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nThe\n\\fIpath\\fR\nargument is\n\\fRNULL\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOZIP\\fR]\nFile is not a zip archive.\n.TP 19n\n[\\fRZIP_ER_READ\\fR]\nA file read failed.\n.TP 19n\n[\\fRZIP_ER_RENAME\\fR]\nA temporary file could not be renamed to its final name.\n.TP 19n\n[\\fRZIP_ER_SEEK\\fR]\nA file seek failed.\n.TP 19n\n[\\fRZIP_ER_TMPOPEN\\fR]\nA temporary file could not be created.\n.TP 19n\n[\\fRZIP_ER_WRITE\\fR]\nA file write failed.\n.TP 19n\n[\\fRZIP_ER_ZLIB\\fR]\nAn error occurred while (de)compressing a stream with\nzlib(3).\n.PD 0\n.PP\nAdditionally, any errors returned by the callback function\nfor added or replaced files will be passed back.\n.PD\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_discard(3),\nzip_fdopen(3),\nzip_get_error(3),\nzip_open(3),\nzip_register_cancel_callback_with_state(3),\nzip_register_progress_callback_with_state(3),\nzip_set_archive_flag(3),\nzip_strerror(3)\n.SH \"HISTORY\"\n\\fBzip_close\\fR()\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n.SH \"CAVEATS\"\nPlease note that all indices,\nzip_stat(3)\ninformation and other data about the archive is invalid after\n\\fBzip_close\\fR.\nWhen you open the same file again, it will be a completely new\n\\fIzip_t\\fR\nstructure.\n"
  },
  {
    "path": "external/libzip/man/zip_close.mdoc",
    "content": ".\\\" zip_close.mdoc -- close zip archive\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 23, 2023\n.Dt ZIP_CLOSE 3\n.Os\n.Sh NAME\n.Nm zip_close\n.Nd close zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_close \"zip_t *archive\"\n.Sh DESCRIPTION\nThe\n.Fn zip_close\nfunction writes any changes made to\n.Ar archive\nto disk.\nIf\n.Ar archive\ncontains no files, the file is completely removed (no empty archive is\nwritten), unless the archive flag\n.Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\nis set.\nIf successful,\n.Ar archive\nis freed.\nOtherwise\n.Ar archive\nis left unchanged and must still be freed.\n.Pp\nTo close and free a zip archive without saving changes, use\n.Xr zip_discard 3 .\n.Pp\nProgress updates for GUIs can be implemented using\n.Xr zip_register_progress_callback_with_state 3 .\nCancelling the write of an archive during\n.Nm\ncan be implemented using\n.Xr zip_register_cancel_callback_with_state 3 .\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_close\nwill fail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_EOF\nUnexpected end-of-file found while reading from a file.\n.It Bq Er ZIP_ER_INTERNAL\nThe callback function of an added or replaced file returned an\nerror but failed to report which.\n.It Bq Er ZIP_ER_INVAL\nThe\n.Ar path\nargument is\n.Dv NULL .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOZIP\nFile is not a zip archive.\n.It Bq Er ZIP_ER_READ\nA file read failed.\n.It Bq Er ZIP_ER_RENAME\nA temporary file could not be renamed to its final name.\n.It Bq Er ZIP_ER_SEEK\nA file seek failed.\n.It Bq Er ZIP_ER_TMPOPEN\nA temporary file could not be created.\n.It Bq Er ZIP_ER_WRITE\nA file write failed.\n.It Bq Er ZIP_ER_ZLIB\nAn error occurred while (de)compressing a stream with\n.Xr zlib 3 .\n.El\nAdditionally, any errors returned by the callback function\nfor added or replaced files will be passed back.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_discard 3 ,\n.Xr zip_fdopen 3 ,\n.Xr zip_get_error 3 ,\n.Xr zip_open 3 ,\n.Xr zip_register_cancel_callback_with_state 3 ,\n.Xr zip_register_progress_callback_with_state 3 ,\n.Xr zip_set_archive_flag 3 ,\n.Xr zip_strerror 3\n.Sh HISTORY\n.Fn zip_close\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n.Sh CAVEATS\nPlease note that all indices,\n.Xr zip_stat 3\ninformation and other data about the archive is invalid after\n.Nm .\nWhen you open the same file again, it will be a completely new\n.Vt zip_t\nstructure.\n"
  },
  {
    "path": "external/libzip/man/zip_compression_method_supported.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_compression_method_supported.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_compression_method_supported.mdoc -- return if compression method is supported\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_COMPRESSION_METHOD_SUPPORTED\" \"3\" \"April 2, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_compression_method_supported\\fR\n\\- return if a compression method is supported\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_compression_method_supported\\fR(\\fIzip_int32_t\\ method\\fR, \\fIint\\ compress\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_compression_method_supported\\fR()\nreturns if the compression method\n\\fImethod\\fR\nis supported for compression (if\n\\fIcompress\\fR\nis zero) or decompression (otherwise).\n.SH \"RETURN VALUES\"\nReturns 1 if the method is supported, 0 otherwise.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_encryption_method_supported(3),\nzip_set_file_compression(3)\n.SH \"HISTORY\"\n\\fBzip_compression_method_supported\\fR()\nwas added in libzip 1.7.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_compression_method_supported.mdoc",
    "content": ".\\\" zip_compression_method_supported.mdoc -- return if compression method is supported\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd April 2, 2020\n.Dt ZIP_COMPRESSION_METHOD_SUPPORTED 3\n.Os\n.Sh NAME\n.Nm zip_compression_method_supported\n.Nd return if a compression method is supported\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_compression_method_supported \"zip_int32_t method\" \"int compress\"\n.Sh DESCRIPTION\nThe\n.Fn zip_compression_method_supported\nreturns if the compression method\n.Ar method\nis supported for compression (if\n.Ar compress\nis zero) or decompression (otherwise).\n.Sh RETURN VALUES\nReturns 1 if the method is supported, 0 otherwise.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_encryption_method_supported 3 ,\n.Xr zip_set_file_compression 3\n.Sh HISTORY\n.Fn zip_compression_method_supported\nwas added in libzip 1.7.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_delete.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_delete.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_delete.mdoc -- delete files from zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_DELETE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_delete\\fR\n\\- delete file from zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_delete\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe file at position\n\\fIindex\\fR\nin the zip archive\n\\fIarchive\\fR\nis marked as deleted.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_delete\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_unchange(3)\n.SH \"HISTORY\"\n\\fBzip_delete\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_delete.mdoc",
    "content": ".\\\" zip_delete.mdoc -- delete files from zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_DELETE 3\n.Os\n.Sh NAME\n.Nm zip_delete\n.Nd delete file from zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_delete \"zip_t *archive\" \"zip_uint64_t index\"\n.Sh DESCRIPTION\nThe file at position\n.Ar index\nin the zip archive\n.Ar archive\nis marked as deleted.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_delete\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_unchange 3\n.Sh HISTORY\n.Fn zip_delete\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_dir_add.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_dir_add.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_dir_add.mdoc -- add directory to zip archive\n.\\\" Copyright (C) 2006-2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_DIR_ADD\" \"3\" \"September 20, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_dir_add\\fR\n\\- add directory to zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_dir_add\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *name\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_dir_add\\fR()\nadds a directory to a zip archive.\nThe argument\n\\fIarchive\\fR\nspecifies the zip archive to which the directory should be added.\n\\fIname\\fR\nis the directory's name in the zip archive.\n.PP\nThis function adds an entry to the archive.\nIt does not check whether a directory with that name exists in the\nfile system, nor does it add its contents if it does.\nThe\n\\fIflags\\fR\nargument can be any of:\n.TP 22n\n\\fRZIP_FL_ENC_GUESS\\fR\nGuess encoding of\n\\fIname\\fR\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.TP 22n\n\\fRZIP_FL_ENC_UTF_8\\fR\nInterpret\n\\fIname\\fR\nas UTF-8.\n.TP 22n\n\\fRZIP_FL_ENC_CP437\\fR\nInterpret\n\\fIname\\fR\nas code page 437 (CP-437).\n.SH \"RETURN VALUES\"\nUpon successful completion, the index of the new entry in the archive\nis returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_dir_add\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_EXISTS\\fR]\nThere is already an entry called\n\\fIname\\fR\nin the archive.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIarchive\\fR\nor\n\\fIname\\fR\nare\n\\fRNULL\\fR,\nor invalid UTF-8 encoded file names.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3)\n.SH \"HISTORY\"\n\\fBzip_dir_add\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_dir_add.mdoc",
    "content": ".\\\" zip_dir_add.mdoc -- add directory to zip archive\n.\\\" Copyright (C) 2006-2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 20, 2020\n.Dt ZIP_DIR_ADD 3\n.Os\n.Sh NAME\n.Nm zip_dir_add\n.Nd add directory to zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_dir_add \"zip_t *archive\" \"const char *name\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_dir_add\nadds a directory to a zip archive.\nThe argument\n.Ar archive\nspecifies the zip archive to which the directory should be added.\n.Ar name\nis the directory's name in the zip archive.\n.Pp\nThis function adds an entry to the archive.\nIt does not check whether a directory with that name exists in the\nfile system, nor does it add its contents if it does.\nThe\n.Ar flags\nargument can be any of:\n.Bl -tag -width XZIPXFLXENCXSTRICTXX\n.It Dv ZIP_FL_ENC_GUESS\nGuess encoding of\n.Ar name\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_UTF_8\nInterpret\n.Ar name\nas UTF-8.\n.It Dv ZIP_FL_ENC_CP437\nInterpret\n.Ar name\nas code page 437 (CP-437).\n.El\n.Sh RETURN VALUES\nUpon successful completion, the index of the new entry in the archive\nis returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_dir_add\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_EXISTS\nThere is already an entry called\n.Ar name\nin the archive.\n.It Bq Er ZIP_ER_INVAL\n.Ar archive\nor\n.Ar name\nare\n.Dv NULL ,\nor invalid UTF-8 encoded file names.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3\n.Sh HISTORY\n.Fn zip_dir_add\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_discard.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_discard.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_discard.mdoc -- close zip archive and discard changes\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_DISCARD\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_discard\\fR\n\\- close zip archive and discard changes\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_discard\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_discard\\fR()\nfunction closes\n\\fIarchive\\fR\nand frees the memory allocated for it.\nAny changes to the archive are not written to disk and discarded.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3)\n.SH \"HISTORY\"\n\\fBzip_discard\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_discard.mdoc",
    "content": ".\\\" zip_discard.mdoc -- close zip archive and discard changes\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_DISCARD 3\n.Os\n.Sh NAME\n.Nm zip_discard\n.Nd close zip archive and discard changes\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_discard \"zip_t *archive\"\n.Sh DESCRIPTION\nThe\n.Fn zip_discard\nfunction closes\n.Ar archive\nand frees the memory allocated for it.\nAny changes to the archive are not written to disk and discarded.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3\n.Sh HISTORY\n.Fn zip_discard\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_encryption_method_supported.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_encryption_method_supported.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_encryption_method_supported.mdoc -- return if encryption method is supported\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ENCRYPTION_METHOD_SUPPORTED\" \"3\" \"April 2, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_encryption_method_supported\\fR\n\\- return if an encryption method is supported\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_encryption_method_supported\\fR(\\fIzip_int16_t\\ method\\fR, \\fIint\\ encrypt\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_encryption_method_supported\\fR()\nreturns if the encryption method\n\\fImethod\\fR\nis supported for encryption (if\n\\fIencrypt\\fR\nis zero) or decryption (otherwise).\n.SH \"RETURN VALUES\"\nReturns 1 if the method is supported, 0 otherwise.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_compression_method_supported(3),\nzip_file_set_encryption(3)\n.SH \"HISTORY\"\n\\fBzip_encryption_method_supported\\fR()\nwas added in libzip 1.7.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_encryption_method_supported.mdoc",
    "content": ".\\\" zip_encryption_method_supported.mdoc -- return if encryption method is supported\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd April 2, 2020\n.Dt ZIP_ENCRYPTION_METHOD_SUPPORTED 3\n.Os\n.Sh NAME\n.Nm zip_encryption_method_supported\n.Nd return if an encryption method is supported\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_encryption_method_supported \"zip_int16_t method\" \"int encrypt\"\n.Sh DESCRIPTION\nThe\n.Fn zip_encryption_method_supported\nreturns if the encryption method\n.Ar method\nis supported for encryption (if\n.Ar encrypt\nis zero) or decryption (otherwise).\n.Sh RETURN VALUES\nReturns 1 if the method is supported, 0 otherwise.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_compression_method_supported 3 ,\n.Xr zip_file_set_encryption 3\n.Sh HISTORY\n.Fn zip_encryption_method_supported\nwas added in libzip 1.7.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error.mdoc -- description of zip_error_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR\" \"5\" \"May 5, 2025\" \"NiH\" \"File Formats Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error\\fR\n\\- error information\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_error_t error\\fR;\n.SH \"DESCRIPTION\"\nA\n\\fBzip_error\\fR\nrepresents information about an error.\nIt is usually allocated directly on the stack or as member of another structure, not via a pointer.\n.PP\nIt is initialized with\nzip_error_init(3)\nor\nzip_error_init_with_code(3).\n.PP\nThe type of error can be accessed with\nzip_error_code_zip(3)\nand\nzip_error_code_system(3).\nIt can be converted to a human readable string with\nzip_error_strerror(3).\n.PP\nAfter use, it should be cleaned up with\nzip_error_fini(3).\n.SH \"SEE ALSO\"\nzip_error_code_system(3),\nzip_error_code_zip(3),\nzip_error_fini(3),\nzip_error_init(3),\nzip_error_init_with_code(3),\nzip_error_strerror(3)\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error.mdoc",
    "content": ".\\\" zip_error.mdoc -- description of zip_error_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt ZIP_ERROR 5\n.Os\n.Sh NAME\n.Nm zip_error\n.Nd error information\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt zip_error_t error ;\n.Sh DESCRIPTION\nA\n.Nm\nrepresents information about an error.\nIt is usually allocated directly on the stack or as member of another structure, not via a pointer.\n.Pp\nIt is initialized with\n.Xr zip_error_init 3\nor\n.Xr zip_error_init_with_code 3 .\n.Pp\nThe type of error can be accessed with\n.Xr zip_error_code_zip 3\nand\n.Xr zip_error_code_system 3 .\nIt can be converted to a human readable string with\n.Xr zip_error_strerror 3 .\n.Pp\nAfter use, it should be cleaned up with\n.Xr zip_error_fini 3 .\n.Sh SEE ALSO\n.Xr zip_error_code_system 3 ,\n.Xr zip_error_code_zip 3 ,\n.Xr zip_error_fini 3 ,\n.Xr zip_error_init 3 ,\n.Xr zip_error_init_with_code 3 ,\n.Xr zip_error_strerror 3\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_clear.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_clear.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_clear.mdoc -- clear error state for archive or file\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_CLEAR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_clear\\fR,\n\\fBzip_file_error_clear\\fR\n\\- clear error state for archive or file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_clear\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.PP\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_error_clear\\fR(\\fIzip_file_t\\ *file\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_clear\\fR()\nfunction clears the error state for the zip archive\n\\fIarchive\\fR.\n.PP\nThe\n\\fBzip_file_error_clear\\fR()\nfunction does the same for the zip file\n\\fIfile\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_get_error(3)\n.SH \"HISTORY\"\n\\fBzip_error_clear\\fR()\nand\n\\fBzip_file_error_clear\\fR()\nwere added in libzip 0.8.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_clear.mdoc",
    "content": ".\\\" zip_error_clear.mdoc -- clear error state for archive or file\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_CLEAR 3\n.Os\n.Sh NAME\n.Nm zip_error_clear ,\n.Nm zip_file_error_clear\n.Nd clear error state for archive or file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_clear \"zip_t *archive\"\n.Ft void\n.Fn zip_file_error_clear \"zip_file_t *file\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_clear\nfunction clears the error state for the zip archive\n.Ar archive .\n.Pp\nThe\n.Fn zip_file_error_clear\nfunction does the same for the zip file\n.Ar file .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_get_error 3\n.Sh HISTORY\n.Fn zip_error_clear\nand\n.Fn zip_file_error_clear\nwere added in libzip 0.8.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_code_system.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_code_system.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_code_system.mdoc -- get system error part of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_CODE_SYSTEM\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_code_system\\fR\n\\- get operating system error part of zip_error\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_code_system\\fR(\\fIconst\\ zip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_code_system\\fR()\nfunction returns the system specific part of the error from the\nzip_error error\n\\fIze\\fR.\nFor finding out what system reported the error, use\nzip_error_system_type(3).\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_zip(3),\nzip_error_system_type(3)\n.SH \"HISTORY\"\n\\fBzip_error_code_system\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_code_system.mdoc",
    "content": ".\\\" zip_error_code_system.mdoc -- get system error part of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_CODE_SYSTEM 3\n.Os\n.Sh NAME\n.Nm zip_error_code_system\n.Nd get operating system error part of zip_error\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_error_code_system \"const zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_code_system\nfunction returns the system specific part of the error from the\nzip_error error\n.Ar ze .\nFor finding out what system reported the error, use\n.Xr zip_error_system_type 3 .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_zip 3 ,\n.Xr zip_error_system_type 3\n.Sh HISTORY\n.Fn zip_error_code_system\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_code_zip.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_code_zip.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_code_zip.mdoc -- get libzip error part of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_CODE_ZIP\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_code_zip\\fR\n\\- get libzip error part of zip_error\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_code_zip\\fR(\\fIconst\\ zip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_code_zip\\fR()\nfunction returns the libzip specific part of the error from the\nzip_error error\n\\fIze\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_system(3)\n.SH \"HISTORY\"\n\\fBzip_error_code_zip\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_code_zip.mdoc",
    "content": ".\\\" zip_error_code_zip.mdoc -- get libzip error part of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_CODE_ZIP 3\n.Os\n.Sh NAME\n.Nm zip_error_code_zip\n.Nd get libzip error part of zip_error\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_error_code_zip \"const zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_code_zip\nfunction returns the libzip specific part of the error from the\nzip_error error\n.Ar ze .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_system 3\n.Sh HISTORY\n.Fn zip_error_code_zip\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_fini.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_fini.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_fini.mdoc -- clean up zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_FINI\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_fini\\fR\n\\- clean up zip_error structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_fini\\fR(\\fIzip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_fini\\fR()\nfunction cleans up and frees internally allocated memory of the\nzip_error pointed to by\n\\fIze\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_init(3)\n.SH \"HISTORY\"\n\\fBzip_error_fini\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_fini.mdoc",
    "content": ".\\\" zip_error_fini.mdoc -- clean up zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_FINI 3\n.Os\n.Sh NAME\n.Nm zip_error_fini\n.Nd clean up zip_error structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_fini \"zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_fini\nfunction cleans up and frees internally allocated memory of the\nzip_error pointed to by\n.Ar ze .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_init 3\n.Sh HISTORY\n.Fn zip_error_fini\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_get.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_get.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_get.mdoc -- get error codes for archive or file\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_GET\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_get\\fR,\n\\fBzip_file_error_get\\fR\n\\- get error codes for archive or file (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_get\\fR(\\fIzip_t\\ *archive\\fR, \\fIint\\ *zep\\fR, \\fIint\\ *sep\\fR);\n.PD\n.PP\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_error_get\\fR(\\fIzip_file_t\\ *file\\fR, \\fIint\\ *zep\\fR, \\fIint\\ *sep\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_error_get\\fR()\nand\n\\fBzip_file_error_get\\fR()\nare deprecated.\nUse\nzip_error_code_system(3),\nzip_error_code_zip(3),\nzip_file_get_error(3),\nand\nzip_get_error(3)\ninstead.\n.PP\nFor\n\\fBzip_error_get\\fR(),\nreplace\n.nf\n.sp\n.RS 6n\nint ze, se;\nzip_error_get(za, &ze, &se);\n.RE\n.fi\nwith\n.nf\n.sp\n.RS 6n\nint ze, se;\nzip_error_t *error = zip_get_error(za);\nze = zip_error_code_zip(error);\nse = zip_error_code_system(error);\n.RE\n.fi\nFor\n\\fBzip_file_error_get\\fR(),\nreplace\n.nf\n.sp\n.RS 6n\nint ze, se;\nzip_file_error_get(zf, &ze, &se);\n.RE\n.fi\nwith\n.nf\n.sp\n.RS 6n\nint ze, se;\nzip_error_t *error = zip_file_get_error(zf);\nze = zip_error_code_zip(error);\nse = zip_error_code_system(error);\n.RE\n.fi\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_system(3),\nzip_error_code_zip(3),\nzip_file_get_error(3),\nzip_get_error(3)\n.SH \"HISTORY\"\n\\fBzip_error_get\\fR()\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n\\fBzip_get_error\\fR(),\n\\fBzip_error_code_zip\\fR(),\n/\n\\fBzip_error_code_system\\fR()\ninstead.\n.PP\n\\fBzip_file_error_get\\fR()\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n\\fBzip_file_get_error\\fR(),\n\\fBzip_error_code_zip\\fR(),\n/\n\\fBzip_error_code_system\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_get.mdoc",
    "content": ".\\\" zip_error_get.mdoc -- get error codes for archive or file\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_GET 3\n.Os\n.Sh NAME\n.Nm zip_error_get ,\n.Nm zip_file_error_get\n.Nd get error codes for archive or file (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_get \"zip_t *archive\" \"int *zep\" \"int *sep\"\n.Ft void\n.Fn zip_file_error_get \"zip_file_t *file\" \"int *zep\" \"int *sep\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_error_get\nand\n.Fn zip_file_error_get\nare deprecated.\nUse\n.Xr zip_error_code_system 3 ,\n.Xr zip_error_code_zip 3 ,\n.Xr zip_file_get_error 3 ,\nand\n.Xr zip_get_error 3\ninstead.\n.Pp\nFor\n.Fn zip_error_get ,\nreplace\n.Bd -literal -offset indent\nint ze, se;\nzip_error_get(za, &ze, &se);\n.Ed\nwith\n.Bd -literal -offset indent\nint ze, se;\nzip_error_t *error = zip_get_error(za);\nze = zip_error_code_zip(error);\nse = zip_error_code_system(error);\n.Ed\nFor\n.Fn zip_file_error_get ,\nreplace\n.Bd -literal -offset indent\nint ze, se;\nzip_file_error_get(zf, &ze, &se);\n.Ed\nwith\n.Bd -literal -offset indent\nint ze, se;\nzip_error_t *error = zip_file_get_error(zf);\nze = zip_error_code_zip(error);\nse = zip_error_code_system(error);\n.Ed\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_system 3 ,\n.Xr zip_error_code_zip 3 ,\n.Xr zip_file_get_error 3 ,\n.Xr zip_get_error 3\n.Sh HISTORY\n.Fn zip_error_get\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n.Fn zip_get_error ,\n.Fn zip_error_code_zip ,\n/\n.Fn zip_error_code_system\ninstead.\n.Pp\n.Fn zip_file_error_get\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n.Fn zip_file_get_error ,\n.Fn zip_error_code_zip ,\n/\n.Fn zip_error_code_system\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_get_sys_type.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_get_sys_type.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_get_sys_type.mdoc -- get type of error\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_GET_SYS_TYPE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_get_sys_type\\fR\n\\- get type of system error code (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_get_sys_type\\fR(\\fIint\\ ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_error_get_sys_type\\fR()\nis deprecated; use\nzip_error_init_with_code(3)\nand\nzip_error_system_type(3)\ninstead.\n.PP\nReplace\n.nf\n.sp\n.RS 6n\nint i = zip_error_get_sys_type(ze);\n.RE\n.fi\nwith\n.nf\n.sp\n.RS 6n\nzip_error_t error;\nzip_error_init_with_code(&error, ze);\nint i = zip_error_system_type(&error);\n.RE\n.fi\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_init_with_code(3),\nzip_error_system_type(3)\n.SH \"HISTORY\"\n\\fBzip_error_get_sys_type\\fR()\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n\\fBzip_error_system_type\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_get_sys_type.mdoc",
    "content": ".\\\" zip_error_get_sys_type.mdoc -- get type of error\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_GET_SYS_TYPE 3\n.Os\n.Sh NAME\n.Nm zip_error_get_sys_type\n.Nd get type of system error code (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_error_get_sys_type \"int ze\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_error_get_sys_type\nis deprecated; use\n.Xr zip_error_init_with_code 3\nand\n.Xr zip_error_system_type 3\ninstead.\n.Pp\nReplace\n.Bd -literal -offset indent\nint i = zip_error_get_sys_type(ze);\n.Ed\nwith\n.Bd -literal -offset indent\nzip_error_t error;\nzip_error_init_with_code(&error, ze);\nint i = zip_error_system_type(&error);\n.Ed\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_init_with_code 3 ,\n.Xr zip_error_system_type 3\n.Sh HISTORY\n.Fn zip_error_get_sys_type\nwas added in libzip 0.6.\nIt was deprecated in libzip 1.0, use\n.Fn zip_error_system_type\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_init.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_init.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_init.mdoc -- initialize zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_INIT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_init\\fR,\n\\fBzip_error_init_with_code\\fR\n\\- initialize zip_error structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_init\\fR(\\fIzip_error_t\\ *error\\fR);\n.PD\n.PP\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_init_with_code\\fR(\\fIzip_error_t\\ *error\\fR, \\fIint\\ ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_init\\fR()\nfunction initializes the zip_error pointed to by\n\\fIerror\\fR.\n\\fI*error\\fR\nmust be allocated before calling\n\\fBzip_error_init\\fR().\n.PP\nThe\n\\fBzip_error_init_with_code\\fR()\nfunction does the same, but additionally sets the zip error code to\n\\fIze\\fR\nand sets the system error code to the current\nerrno(3)\nvalue, if appropriate.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_fini(3)\n.SH \"HISTORY\"\n\\fBzip_error_init\\fR()\nand\n\\fBzip_error_init_with_code\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_init.mdoc",
    "content": ".\\\" zip_error_init.mdoc -- initialize zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_INIT 3\n.Os\n.Sh NAME\n.Nm zip_error_init ,\n.Nm zip_error_init_with_code\n.Nd initialize zip_error structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_init \"zip_error_t *error\"\n.Ft void\n.Fn zip_error_init_with_code \"zip_error_t *error\" \"int ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_init\nfunction initializes the zip_error pointed to by\n.Ar error .\n.Ar *error\nmust be allocated before calling\n.Fn zip_error_init .\n.Pp\nThe\n.Fn zip_error_init_with_code\nfunction does the same, but additionally sets the zip error code to\n.Ar ze\nand sets the system error code to the current\n.Xr errno 3\nvalue, if appropriate.\n.\\\" TODO: describe when you would need to call this at all\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_fini 3\n.Sh HISTORY\n.Fn zip_error_init\nand\n.Fn zip_error_init_with_code\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_set.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_set.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_set.mdoc -- set zip_error\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_SET\" \"3\" \"December 5, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_set\\fR\n\\- fill in zip_error structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_set\\fR(\\fIzip_error_t\\ *ze\\fR, \\fIint\\ le\\fR, \\fIint\\ se\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_set\\fR()\nfunction sets the zip_error pointed to by\n\\fIze\\fR\nto the libzip error code\n\\fIle\\fR\nand the system error code\n\\fIse\\fR.\n.PP\n\\fIze\\fR\nmust be allocated and initialized with\nzip_error_init(3)\nbefore calling\n\\fBzip_error_set\\fR().\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_init(3),\nzip_error_set_from_source(3)\n.SH \"HISTORY\"\n\\fBzip_error_set\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_set.mdoc",
    "content": ".\\\" zip_error_set.mdoc -- set zip_error\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 5, 2022\n.Dt ZIP_ERROR_SET 3\n.Os\n.Sh NAME\n.Nm zip_error_set\n.Nd fill in zip_error structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_set \"zip_error_t *ze\" \"int le\" \"int se\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_set\nfunction sets the zip_error pointed to by\n.Ar ze\nto the libzip error code\n.Ar le\nand the system error code\n.Ar se .\n.Pp\n.Ar ze\nmust be allocated and initialized with\n.Xr zip_error_init 3\nbefore calling\n.Fn zip_error_set .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_init 3 ,\n.Xr zip_error_set_from_source 3\n.Sh HISTORY\n.Fn zip_error_set\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_set_from_source.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_set_from_source.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_set_from_source.mdoc -- set zip_error from source\n.\\\" Copyright (C) 2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_SET_FROM_SOURCE\" \"3\" \"December 5, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_set_from_source\\fR\n\\- fill in zip_error structure from source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_set_from_source\\fR(\\fIzip_error_t\\ *ze\\fR, \\fIzip_source_t\\ *src\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_set_from_source\\fR()\nfunction sets the zip_error pointed to by\n\\fIze\\fR\nto the error reported by\n\\fIsrc\\fR\nas returned by\nzip_error_source(3).\n\\fIze\\fR\nmust be allocated and initialized with\nzip_error_init(3)\nbefore calling\n\\fBzip_error_set_from_source\\fR().\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_init(3),\nzip_error_set(3)\n.SH \"HISTORY\"\n\\fBzip_error_set_from_source\\fR()\nwas added in libzip 1.10.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_set_from_source.mdoc",
    "content": ".\\\" zip_error_set_from_source.mdoc -- set zip_error from source\n.\\\" Copyright (C) 2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 5, 2022\n.Dt ZIP_ERROR_SET_FROM_SOURCE 3\n.Os\n.Sh NAME\n.Nm zip_error_set_from_source\n.Nd fill in zip_error structure from source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_error_set_from_source \"zip_error_t *ze\" \"zip_source_t *src\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_set_from_source\nfunction sets the zip_error pointed to by\n.Ar ze\nto the error reported by\n.Ar src\nas returned by\n.Xr zip_error_source 3 .\n.Ar ze\nmust be allocated and initialized with\n.Xr zip_error_init 3\nbefore calling\n.Fn zip_error_set_from_source .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_init 3 ,\n.Xr zip_error_set 3\n.Sh HISTORY\n.Fn zip_error_set_from_source\nwas added in libzip 1.10.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_strerror.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_strerror.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_strerror.mdoc -- create human-readable version of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_STRERROR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_strerror\\fR\n\\- create human-readable string for zip_error\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_strerror\\fR(\\fIzip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_strerror\\fR()\nfunction returns an error message string corresponding to\n\\fIze\\fR\nlike\nstrerror(3).\nThis string will stay valid until the next call to\n\\fBzip_error_strerror\\fR()\nor until\nzip_error_fini(3)\nis called.\n.SH \"SEE ALSO\"\nlibzip(3),\nstrerror(3),\nzip_error_fini(3)\n.SH \"HISTORY\"\n\\fBzip_error_strerror\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_strerror.mdoc",
    "content": ".\\\" zip_error_strerror.mdoc -- create human-readable version of zip_error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_STRERROR 3\n.Os\n.Sh NAME\n.Nm zip_error_strerror\n.Nd create human-readable string for zip_error\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_error_strerror \"zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_strerror\nfunction returns an error message string corresponding to\n.Ar ze\nlike\n.Xr strerror 3 .\nThis string will stay valid until the next call to\n.Fn zip_error_strerror\nor until\n.Xr zip_error_fini 3\nis called.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr strerror 3 ,\n.Xr zip_error_fini 3\n.Sh HISTORY\n.Fn zip_error_strerror\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_system_type.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_system_type.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_system_type.mdoc -- return system type for error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_SYSTEM_TYPE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_system_type\\fR\n\\- return type of system error\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_system_type\\fR(\\fIconst\\ zip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_error_system_type\\fR()\nfunction returns the type of the system specific part for the zip_error\n\\fIze\\fR.\nCurrently, the following system types are defined:\n.TP 13n\n\\fRZIP_ET_NONE\\fR\nSystem specific part of\n\\fIze\\fR\nis unused.\n.TP 13n\n\\fRZIP_ET_SYS\\fR\nSystem specific part of\n\\fIze\\fR\nis an\nerrno(2).\n.TP 13n\n\\fRZIP_ET_ZLIB\\fR\nSystem specific part of\n\\fIze\\fR\nis a\nzlib(3)\nerror.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_system(3)\n.SH \"HISTORY\"\n\\fBzip_error_system_type\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_system_type.mdoc",
    "content": ".\\\" zip_error_system_type.mdoc -- return system type for error\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_SYSTEM_TYPE 3\n.Os\n.Sh NAME\n.Nm zip_error_system_type\n.Nd return type of system error\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_error_system_type \"const zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_error_system_type\nfunction returns the type of the system specific part for the zip_error\n.Ar ze .\nCurrently, the following system types are defined:\n.Bl -tag -width ZIP_ET_NONE\n.It Dv ZIP_ET_NONE\nSystem specific part of\n.Ar ze\nis unused.\n.It Dv ZIP_ET_SYS\nSystem specific part of\n.Ar ze\nis an\n.Xr errno 2 .\n.It Dv ZIP_ET_ZLIB\nSystem specific part of\n.Ar ze\nis a\n.Xr zlib 3\nerror.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_system 3\n.Sh HISTORY\n.Fn zip_error_system_type\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_to_data.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_to_data.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_to_data.mdoc -- create error data for ZIP_SOURCE_ERROR\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_TO_DATA\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_to_data\\fR\n\\- convert zip_error to return value suitable for ZIP_SOURCE_ERROR\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_to_data\\fR(\\fIconst\\ zip_error_t\\ *ze\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR);\n.PD\n.SH \"DESCRIPTION\"\n\\fBzip_error_to_data\\fR()\nfunction converts the zip_error\n\\fIze\\fR\ninto data suitable as return value for\n\\fRZIP_SOURCE_ERROR\\fR.\nThe data is written into the buffer\n\\fIdata\\fR\nof size\n\\fIlen\\fR.\nIf the buffer is not large enough to hold 2 ints, an error is\nreturned.\n.SH \"RETURN VALUES\"\n\\fBzip_error_to_data\\fR()\nreturns 2*(sizeof int) on success, and \\-1 on error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source_function(3)\n.SH \"HISTORY\"\n\\fBzip_error_to_data\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_to_data.mdoc",
    "content": ".\\\" zip_error_to_data.mdoc -- create error data for ZIP_SOURCE_ERROR\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_TO_DATA 3\n.Os\n.Sh NAME\n.Nm zip_error_to_data\n.Nd convert zip_error to return value suitable for ZIP_SOURCE_ERROR\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_error_to_data \"const zip_error_t *ze\" \"void *data\" \"zip_uint64_t len\"\n.Sh DESCRIPTION\n.Fn zip_error_to_data\nfunction converts the zip_error\n.Ar ze\ninto data suitable as return value for\n.Dv ZIP_SOURCE_ERROR .\nThe data is written into the buffer\n.Ar data\nof size\n.Ar len .\nIf the buffer is not large enough to hold 2 ints, an error is\nreturned.\n.Sh RETURN VALUES\n.Fn zip_error_to_data\nreturns 2*(sizeof int) on success, and \\-1 on error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source_function 3\n.Sh HISTORY\n.Fn zip_error_to_data\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_error_to_str.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_error_to_str.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_error_to_str.mdoc -- get string representation of zip error code\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_ERROR_TO_STR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_error_to_str\\fR\n\\- get string representation of zip error (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_error_to_str\\fR(\\fIchar\\ *buf\\fR, \\fIzip_uint64_t\\ len\\fR, \\fIint\\ ze\\fR, \\fIint\\ se\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_error_to_str\\fR()\nis deprecated; use\nzip_error_init_with_code(3)\nand\nzip_error_strerror(3)\ninstead.\n.PP\nReplace\n.nf\n.sp\n.RS 6n\nchar buf[BUFSIZE];\nzip_error_to_str(buf, sizeof(buf), ze, se);\nprintf(\"%s\", buf);\n.RE\n.fi\nwith\n.nf\n.sp\n.RS 6n\nzip_error_t error;\nzip_error_init_with_code(&error, ze);\nprintf(\"%s\", zip_error_strerror(&error));\nzip_error_fini(&error);\n.RE\n.fi\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_init_with_code(3),\nzip_error_strerror(3)\n.SH \"HISTORY\"\n\\fBzip_error_to_str\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIlen\\fR\nwas changed from\n\\fIsize_t\\fR\nto\n\\fIzip_uint64_t\\fR.\nIt was deprecated in libzip 1.0, use\n\\fBzip_error_init_with_code\\fR()\nand\n\\fBzip_error_strerror\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_error_to_str.mdoc",
    "content": ".\\\" zip_error_to_str.mdoc -- get string representation of zip error code\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_ERROR_TO_STR 3\n.Os\n.Sh NAME\n.Nm zip_error_to_str\n.Nd get string representation of zip error (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_error_to_str \"char *buf\" \"zip_uint64_t len\" \"int ze\" \"int se\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_error_to_str\nis deprecated; use\n.Xr zip_error_init_with_code 3\nand\n.Xr zip_error_strerror 3\ninstead.\n.Pp\nReplace\n.Bd -literal -offset indent\nchar buf[BUFSIZE];\nzip_error_to_str(buf, sizeof(buf), ze, se);\nprintf(\"%s\", buf);\n.Ed\nwith\n.Bd -literal -offset indent\nzip_error_t error;\nzip_error_init_with_code(&error, ze);\nprintf(\"%s\", zip_error_strerror(&error));\nzip_error_fini(&error);\n.Ed\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_init_with_code 3 ,\n.Xr zip_error_strerror 3\n.Sh HISTORY\n.Fn zip_error_to_str\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar len\nwas changed from\n.Vt size_t\nto\n.Vt zip_uint64_t .\nIt was deprecated in libzip 1.0, use\n.Fn zip_error_init_with_code\nand\n.Fn zip_error_strerror\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_errors.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_errors.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_errors.mdoc -- list of all libzip error codes\n.\\\" Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.\\\"   This file was generated automatically by ./make_zip_errors.sh\n.\\\"   from ../lib/zip.h; make changes there.\n.\\\"\n.TH \"ZIP_ERRORS\" \"3\" \"March 15, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_errors\\fR\n\\- list of all libzip error codes\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.SH \"DESCRIPTION\"\nThe following error codes are used by libzip:\n.TP 23n\n[\\fRZIP_ER_CANCELLED\\fR]\nOperation cancelled.\n.TP 23n\n[\\fRZIP_ER_CHANGED\\fR]\nEntry has been changed.\n.TP 23n\n[\\fRZIP_ER_CLOSE\\fR]\nClosing zip archive failed.\n.TP 23n\n[\\fRZIP_ER_COMPNOTSUPP\\fR]\nCompression method not supported.\n.TP 23n\n[\\fRZIP_ER_COMPRESSED_DATA\\fR]\nCompressed data invalid.\n.TP 23n\n[\\fRZIP_ER_CRC\\fR]\nCRC error.\n.TP 23n\n[\\fRZIP_ER_DATA_LENGTH\\fR]\nUnexpected length of data.\n.TP 23n\n[\\fRZIP_ER_DELETED\\fR]\nEntry has been deleted.\n.TP 23n\n[\\fRZIP_ER_ENCRNOTSUPP\\fR]\nEncryption method not supported.\n.TP 23n\n[\\fRZIP_ER_EOF\\fR]\nPremature end of file.\n.TP 23n\n[\\fRZIP_ER_EXISTS\\fR]\nFile already exists.\n.TP 23n\n[\\fRZIP_ER_INCONS\\fR]\nZip archive inconsistent.\n.TP 23n\n[\\fRZIP_ER_INTERNAL\\fR]\nInternal error.\n.TP 23n\n[\\fRZIP_ER_INUSE\\fR]\nResource still in use.\n.TP 23n\n[\\fRZIP_ER_INVAL\\fR]\nInvalid argument.\n.TP 23n\n[\\fRZIP_ER_MEMORY\\fR]\nMalloc failure.\n.TP 23n\n[\\fRZIP_ER_MULTIDISK\\fR]\nMulti-disk zip archives not supported.\n.TP 23n\n[\\fRZIP_ER_NOENT\\fR]\nNo such file.\n.TP 23n\n[\\fRZIP_ER_NOPASSWD\\fR]\nNo password provided.\n.TP 23n\n[\\fRZIP_ER_NOT_ALLOWED\\fR]\nNot allowed in torrentzip.\n.TP 23n\n[\\fRZIP_ER_NOZIP\\fR]\nNot a zip archive.\n.TP 23n\n[\\fRZIP_ER_OK\\fR]\nNo error.\n.TP 23n\n[\\fRZIP_ER_OPEN\\fR]\nCan't open file.\n.TP 23n\n[\\fRZIP_ER_OPNOTSUPP\\fR]\nOperation not supported.\n.TP 23n\n[\\fRZIP_ER_RDONLY\\fR]\nRead-only archive.\n.TP 23n\n[\\fRZIP_ER_READ\\fR]\nRead error.\n.TP 23n\n[\\fRZIP_ER_REMOVE\\fR]\nCan't remove file.\n.TP 23n\n[\\fRZIP_ER_RENAME\\fR]\nRenaming temporary file failed.\n.TP 23n\n[\\fRZIP_ER_SEEK\\fR]\nSeek error.\n.TP 23n\n[\\fRZIP_ER_TELL\\fR]\nTell error.\n.TP 23n\n[\\fRZIP_ER_TMPOPEN\\fR]\nFailure to create temporary file.\n.TP 23n\n[\\fRZIP_ER_TRUNCATED_ZIP\\fR]\n.br\nPossibly truncated or corrupted zip archive.\n.TP 23n\n[\\fRZIP_ER_WRITE\\fR]\nWrite error.\n.TP 23n\n[\\fRZIP_ER_WRONGPASSWD\\fR]\nWrong password provided.\n.TP 23n\n[\\fRZIP_ER_ZIPCLOSED\\fR]\nContaining zip archive was closed.\n.TP 23n\n[\\fRZIP_ER_ZLIB\\fR]\nZlib error.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_errors.mdoc",
    "content": ".\\\" zip_errors.mdoc -- list of all libzip error codes\n.\\\" Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.\\\"   This file was generated automatically by ./make_zip_errors.sh\n.\\\"   from ../lib/zip.h; make changes there.\n.\\\"\n.Dd March 15, 2024\n.Dt ZIP_ERRORS 3\n.Os\n.Sh NAME\n.Nm zip_errors\n.Nd list of all libzip error codes\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Sh DESCRIPTION\nThe following error codes are used by libzip:\n.Bl -tag -width XZIPXERXCOMPNOTSUPPXX\n.It Bq Er ZIP_ER_CANCELLED\nOperation cancelled.\n.It Bq Er ZIP_ER_CHANGED\nEntry has been changed.\n.It Bq Er ZIP_ER_CLOSE\nClosing zip archive failed.\n.It Bq Er ZIP_ER_COMPNOTSUPP\nCompression method not supported.\n.It Bq Er ZIP_ER_COMPRESSED_DATA\nCompressed data invalid.\n.It Bq Er ZIP_ER_CRC\nCRC error.\n.It Bq Er ZIP_ER_DATA_LENGTH\nUnexpected length of data.\n.It Bq Er ZIP_ER_DELETED\nEntry has been deleted.\n.It Bq Er ZIP_ER_ENCRNOTSUPP\nEncryption method not supported.\n.It Bq Er ZIP_ER_EOF\nPremature end of file.\n.It Bq Er ZIP_ER_EXISTS\nFile already exists.\n.It Bq Er ZIP_ER_INCONS\nZip archive inconsistent.\n.It Bq Er ZIP_ER_INTERNAL\nInternal error.\n.It Bq Er ZIP_ER_INUSE\nResource still in use.\n.It Bq Er ZIP_ER_INVAL\nInvalid argument.\n.It Bq Er ZIP_ER_MEMORY\nMalloc failure.\n.It Bq Er ZIP_ER_MULTIDISK\nMulti-disk zip archives not supported.\n.It Bq Er ZIP_ER_NOENT\nNo such file.\n.It Bq Er ZIP_ER_NOPASSWD\nNo password provided.\n.It Bq Er ZIP_ER_NOT_ALLOWED\nNot allowed in torrentzip.\n.It Bq Er ZIP_ER_NOZIP\nNot a zip archive.\n.It Bq Er ZIP_ER_OK\nNo error.\n.It Bq Er ZIP_ER_OPEN\nCan't open file.\n.It Bq Er ZIP_ER_OPNOTSUPP\nOperation not supported.\n.It Bq Er ZIP_ER_RDONLY\nRead-only archive.\n.It Bq Er ZIP_ER_READ\nRead error.\n.It Bq Er ZIP_ER_REMOVE\nCan't remove file.\n.It Bq Er ZIP_ER_RENAME\nRenaming temporary file failed.\n.It Bq Er ZIP_ER_SEEK\nSeek error.\n.It Bq Er ZIP_ER_TELL\nTell error.\n.It Bq Er ZIP_ER_TMPOPEN\nFailure to create temporary file.\n.It Bq Er ZIP_ER_TRUNCATED_ZIP\nPossibly truncated or corrupted zip archive.\n.It Bq Er ZIP_ER_WRITE\nWrite error.\n.It Bq Er ZIP_ER_WRONGPASSWD\nWrong password provided.\n.It Bq Er ZIP_ER_ZIPCLOSED\nContaining zip archive was closed.\n.It Bq Er ZIP_ER_ZLIB\nZlib error.\n.El\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_fclose.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fclose.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fclose.mdoc -- close file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FCLOSE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fclose\\fR\n\\- close file in zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fclose\\fR(\\fIzip_file_t\\ *file\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_fclose\\fR()\nfunction closes\n\\fIfile\\fR\nand frees the memory allocated for it.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, the error code is returned.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fopen(3),\nzip_fread(3),\nzip_fseek(3)\n.SH \"HISTORY\"\n\\fBzip_fclose\\fR()\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_fclose.mdoc",
    "content": ".\\\" zip_fclose.mdoc -- close file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FCLOSE 3\n.Os\n.Sh NAME\n.Nm zip_fclose\n.Nd close file in zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_fclose \"zip_file_t *file\"\n.Sh DESCRIPTION\nThe\n.Fn zip_fclose\nfunction closes\n.Ar file\nand frees the memory allocated for it.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, the error code is returned.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fread 3 ,\n.Xr zip_fseek 3\n.Sh HISTORY\n.Fn zip_fclose\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_fdopen.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fdopen.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fdopen.mdoc -- open zip archive using existing file descriptor\n.\\\" Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FDOPEN\" \"3\" \"September 23, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fdopen\\fR\n\\- open zip archive using open file descriptor\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fdopen\\fR(\\fIint\\ fd\\fR, \\fIint\\ flags\\fR, \\fIint\\ *errorp\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe zip archive specified by the open file descriptor\n\\fIfd\\fR\nis opened and a pointer to a\n\\fIstruct zip\\fR,\nused to manipulate the archive, is returned.\nIn contrast to\nzip_open(3),\nusing\n\\fBzip_fdopen\\fR\nthe archive can only be opened in read-only mode.\nThe\n\\fIfd\\fR\nargument may not be used any longer after calling\n\\fBzip_fdopen\\fR.\nThe\n\\fIflags\\fR\nare specified by\n\\fIor\\fR'ing\nthe following values, or 0 for none of them.\n.RS 6n\n.TP 15n\n\\fRZIP_CHECKCONS\\fR\nPerform additional stricter consistency checks on the archive, and\nerror if they fail.\n.RE\n.PP\nIf an error occurs and\n\\fIerrorp\\fR\nis\nnon-\\fRNULL\\fR,\nit will be set to the corresponding error code.\n.SH \"RETURN VALUES\"\nUpon successful completion\n\\fBzip_fdopen\\fR()\nreturns a\n\\fIstruct zip\\fR\npointer, and\n\\fIfd\\fR\nshould not be used any longer, nor passed to\nclose(2).\nOtherwise,\n\\fRNULL\\fR\nis returned and\n\\fI*errorp\\fR\nis set to indicate the error.\nIn the error case,\n\\fIfd\\fR\nremains unchanged.\n.SH \"ERRORS\"\nThe file specified by\n\\fIfd\\fR\nis prepared for use by\nlibzip(3)\nunless:\n.TP 19n\n[\\fRZIP_ER_INCONS\\fR]\nInconsistencies were found in the file specified by\n\\fIpath\\fR.\nThis error is often caused by specifying\n\\fRZIP_CHECKCONS\\fR\nbut can also happen without it.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nThe\n\\fIflags\\fR\nargument is invalid.\nNot all\nzip_open(3)\nflags are allowed for\n\\fBzip_fdopen\\fR,\nsee\n\\fIDESCRIPTION\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOZIP\\fR]\nThe file specified by\n\\fIfd\\fR\nis not a zip archive.\n.TP 19n\n[\\fRZIP_ER_OPEN\\fR]\nThe file specified by\n\\fIfd\\fR\ncould not be prepared for use by\nlibzip(3).\n.TP 19n\n[\\fRZIP_ER_OPNOTSUPP\\fR]\n.br\nThis functionality has been disabled at compile time.\n.TP 19n\n[\\fRZIP_ER_READ\\fR]\nA read error occurred; see\n\\fIerrno\\fR\nfor details.\n.TP 19n\n[\\fRZIP_ER_SEEK\\fR]\nThe file specified by\n\\fIfd\\fR\ndoes not allow seeks.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3),\nzip_error_strerror(3),\nzip_open(3)\n.SH \"HISTORY\"\n\\fBzip_fdopen\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_fdopen.mdoc",
    "content": ".\\\" zip_fdopen.mdoc -- open zip archive using existing file descriptor\n.\\\" Copyright (C) 2009-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 23, 2022\n.Dt ZIP_FDOPEN 3\n.Os\n.Sh NAME\n.Nm zip_fdopen\n.Nd open zip archive using open file descriptor\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_t *\n.Fn zip_fdopen \"int fd\" \"int flags\" \"int *errorp\"\n.Sh DESCRIPTION\nThe zip archive specified by the open file descriptor\n.Ar fd\nis opened and a pointer to a\n.Ft struct zip ,\nused to manipulate the archive, is returned.\nIn contrast to\n.Xr zip_open 3 ,\nusing\n.Nm zip_fdopen\nthe archive can only be opened in read-only mode.\nThe\n.Ar fd\nargument may not be used any longer after calling\n.Nm zip_fdopen .\nThe\n.Fa flags\nare specified by\n.Em or Ns No 'ing\nthe following values, or 0 for none of them.\n.Bl -tag -offset indent -width ZIP_CHECKCONS\n.It Dv ZIP_CHECKCONS\nPerform additional stricter consistency checks on the archive, and\nerror if they fail.\n.El\n.Pp\nIf an error occurs and\n.Ar errorp\nis\n.No non- Ns Dv NULL ,\nit will be set to the corresponding error code.\n.Sh RETURN VALUES\nUpon successful completion\n.Fn zip_fdopen\nreturns a\n.Ft struct zip\npointer, and\n.Ar fd\nshould not be used any longer, nor passed to\n.Xr close 2 .\nOtherwise,\n.Dv NULL\nis returned and\n.Ar *errorp\nis set to indicate the error.\nIn the error case,\n.Ar fd\nremains unchanged.\n.Sh ERRORS\nThe file specified by\n.Ar fd\nis prepared for use by\n.Xr libzip 3\nunless:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INCONS\nInconsistencies were found in the file specified by\n.Ar path .\nThis error is often caused by specifying\n.Dv ZIP_CHECKCONS\nbut can also happen without it.\n.It Bq Er ZIP_ER_INVAL\nThe\n.Ar flags\nargument is invalid.\nNot all\n.Xr zip_open 3\nflags are allowed for\n.Nm zip_fdopen ,\nsee\n.Sx DESCRIPTION .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOZIP\nThe file specified by\n.Ar fd\nis not a zip archive.\n.It Bq Er ZIP_ER_OPEN\nThe file specified by\n.Ar fd\ncould not be prepared for use by\n.Xr libzip 3 .\n.It Bq Er ZIP_ER_OPNOTSUPP\nThis functionality has been disabled at compile time.\n.It Bq Er ZIP_ER_READ\nA read error occurred; see\n.Va errno\nfor details.\n.It Bq Er ZIP_ER_SEEK\nThe file specified by\n.Ar fd\ndoes not allow seeks.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3 ,\n.Xr zip_error_strerror 3 ,\n.Xr zip_open 3\n.Sh HISTORY\n.Fn zip_fdopen\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file.mdoc -- description of zip_file_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE\" \"5\" \"May 5, 2025\" \"NiH\" \"File Formats Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file\\fR\n\\- file in archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_file_t *file\\fR;\n.SH \"DESCRIPTION\"\nA\n\\fBzip_file\\fR\nrepresents a file inside an archive, opened for reading.\nIt is created with\nzip_fopen(3),\nzip_fopen_index(3),\nzip_fopen_encrypted(3),\nor\nzip_fopen_index_encrypted(3).\n.PP\nData is accessed with\nzip_fread(3),\nzip_file_is_seekable(3),\nzip_ftell(3),\nor\nzip_fseek(3).\n.PP\nIt is closed with\nzip_fclose(3).\n.PP\nIf the containing\n\\fIzip_t\\fR\nis closed, all further uses of the\n\\fIzip_file_t\\fR\nreturn an error.\nIt is a convenience wrapper around a\n\\fIzip_source_t\\fR\nas created by\nzip_source_zip(3).\n.SH \"SEE ALSO\"\nzip_fclose(3),\nzip_file_is_seekable(3),\nzip_fopen(3),\nzip_fopen_encrypted(3),\nzip_fopen_index(3),\nzip_fopen_index_encrypted(3,)\nzip_fread(3),\nzip_fseek(3),\nzip_ftell(3),\nzip_source_zip(3),\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file.mdoc",
    "content": ".\\\" zip_file.mdoc -- description of zip_file_t\n.\\\" Copyright (C) 2025 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt ZIP_FILE 5\n.Os\n.Sh NAME\n.Nm zip_file\n.Nd file in archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt zip_file_t *file ;\n.Sh DESCRIPTION\nA\n.Nm\nrepresents a file inside an archive, opened for reading.\nIt is created with\n.Xr zip_fopen 3 ,\n.Xr zip_fopen_index 3 ,\n.Xr zip_fopen_encrypted 3 ,\nor\n.Xr zip_fopen_index_encrypted 3 .\n.Pp\nData is accessed with\n.Xr zip_fread 3 ,\n.Xr zip_file_is_seekable 3 ,\n.Xr zip_ftell 3 ,\nor\n.Xr zip_fseek 3 .\n.Pp\nIt is closed with\n.Xr zip_fclose 3 .\n.Pp\nIf the containing\n.Vt zip_t\nis closed, all further uses of the\n.Vt zip_file_t\nreturn an error.\nIt is a convenience wrapper around a\n.Vt zip_source_t\nas created by\n.Xr zip_source_zip 3 .\n.Sh SEE ALSO\n.Xr zip_fclose 3 ,\n.Xr zip_file_is_seekable 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fopen_encrypted 3 ,\n.Xr zip_fopen_index 3 ,\n.Xr zip_fopen_index_encrypted 3,\n.Xr zip_fread 3 ,\n.Xr zip_fseek 3 ,\n.Xr zip_ftell 3 ,\n.Xr zip_source_zip 3 ,\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_add.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_add.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_add.mdoc -- add files to zip archive\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_ADD\" \"3\" \"March 18, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_add\\fR,\n\\fBzip_file_replace\\fR\n\\- add file to zip archive or replace file in zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_add\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *name\\fR, \\fIzip_source_t\\ *source\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_replace\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_source_t\\ *source\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_file_add\\fR()\nadds a file to a zip archive, while\n\\fBzip_file_replace\\fR()\nreplaces an existing file in a zip archive.\nThe argument\n\\fIarchive\\fR\nspecifies the zip archive to which the file should be added.\n\\fIname\\fR\nis the file's name in the zip archive (for\n\\fBzip_file_add\\fR()),\nwhile\n\\fIindex\\fR\nspecifies which file should be replaced (for\n\\fBzip_file_replace\\fR()).\nThe\n\\fIflags\\fR\nargument can be any combination of\n\\fRZIP_FL_OVERWRITE\\fR\nwith one of\n\\fRZIP_FL_ENC_*\\fR:\n.TP 22n\n\\fRZIP_FL_OVERWRITE\\fR\nOverwrite any existing file of the same name.\nFor\n\\fBzip_file_add\\fR\nonly.\n.TP 22n\n\\fRZIP_FL_ENC_GUESS\\fR\nGuess encoding of\n\\fIname\\fR\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.TP 22n\n\\fRZIP_FL_ENC_UTF_8\\fR\nInterpret\n\\fIname\\fR\nas UTF-8.\n.TP 22n\n\\fRZIP_FL_ENC_CP437\\fR\nInterpret\n\\fIname\\fR\nas code page 437 (CP-437).\n.PD 0\n.PP\nThe data is obtained from the\n\\fIsource\\fR\nargument, see\nzip_source(5).\n.PD\n.PP\n\\fINOTE\\fR:\nzip_source_free(3)\nshould not be called on a\n\\fIsource\\fR\nafter it was used successfully in a\n\\fBzip_file_add\\fR\nor\n\\fBzip_file_replace\\fR\ncall.\n.PP\nPlease also note that when using\n\\fBzip_replace\\fR,\nthe target file's extra field information will be deleted since this\nusually is dependent on the file contents.\nIf you want to keep them, query them beforehand with\nzip_file_extra_field_get(3)\nand restore them after\n\\fBzip_replace\\fR\nwith\nzip_file_extra_field_set(3).\n.SH \"RETURN VALUES\"\nUpon successful completion,\n\\fBzip_file_add\\fR()\nreturns the index of the new file in the archive, and\n\\fBzip_file_replace\\fR()\nreturns 0.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"EXAMPLES\"\n.nf\n.RS 6n\nzip_source_t *s;\nconst char buf[]=\"teststring\";\n\nif ((s=zip_source_buffer(archive, buf, sizeof(buf), 0)) == NULL ||\n    zip_file_add(archive, name, s, ZIP_FL_ENC_UTF_8) < 0) {\n    zip_source_free(s);\n    printf(\"error adding file: %s\\en\", zip_strerror(archive));\n}\n.RE\n.fi\n.SH \"ERRORS\"\n\\fBzip_file_add\\fR()\nand\n\\fBzip_file_replace\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_EXISTS\\fR]\nThere is already a file called\n\\fIname\\fR\nin the archive.\n(Only applies to\n\\fBzip_file_add\\fR(),\nand only if\n\\fRZIP_FL_OVERWRITE\\fR\nis not provided).\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIsource\\fR\nor\n\\fIname\\fR\nare\n\\fRNULL\\fR,\nor\n\\fIindex\\fR\nis invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nArchive was opened in read-only mode.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_file_add\\fR()\nand\n\\fBzip_file_replace\\fR()\nwere added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_add.mdoc",
    "content": ".\\\" zip_file_add.mdoc -- add files to zip archive\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 18, 2024\n.Dt ZIP_FILE_ADD 3\n.Os\n.Sh NAME\n.Nm zip_file_add ,\n.Nm zip_file_replace\n.Nd add file to zip archive or replace file in zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_file_add \"zip_t *archive\" \"const char *name\" \"zip_source_t *source\" \"zip_flags_t flags\"\n.Ft int\n.Fn zip_file_replace \"zip_t *archive\" \"zip_uint64_t index\" \"zip_source_t *source\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_file_add\nadds a file to a zip archive, while\n.Fn zip_file_replace\nreplaces an existing file in a zip archive.\nThe argument\n.Ar archive\nspecifies the zip archive to which the file should be added.\n.Ar name\nis the file's name in the zip archive (for\n.Fn zip_file_add ) ,\nwhile\n.Ar index\nspecifies which file should be replaced (for\n.Fn zip_file_replace ) .\nThe\n.Ar flags\nargument can be any combination of\n.Dv ZIP_FL_OVERWRITE\nwith one of\n.Dv ZIP_FL_ENC_* :\n.Bl -tag -width XZIPXFLXENCXSTRICTXX\n.It Dv ZIP_FL_OVERWRITE\nOverwrite any existing file of the same name.\nFor\n.Nm zip_file_add\nonly.\n.It Dv ZIP_FL_ENC_GUESS\nGuess encoding of\n.Ar name\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_UTF_8\nInterpret\n.Ar name\nas UTF-8.\n.It Dv ZIP_FL_ENC_CP437\nInterpret\n.Ar name\nas code page 437 (CP-437).\n.El\nThe data is obtained from the\n.Ar source\nargument, see\n.Xr zip_source 5 .\n.Pp\n.Em NOTE :\n.Xr zip_source_free 3\nshould not be called on a\n.Ar source\nafter it was used successfully in a\n.Nm zip_file_add\nor\n.Nm zip_file_replace\ncall.\n.Pp\nPlease also note that when using\n.Nm zip_replace ,\nthe target file's extra field information will be deleted since this\nusually is dependent on the file contents.\nIf you want to keep them, query them beforehand with\n.Xr zip_file_extra_field_get 3\nand restore them after\n.Nm zip_replace\nwith\n.Xr zip_file_extra_field_set 3 .\n.Sh RETURN VALUES\nUpon successful completion,\n.Fn zip_file_add\nreturns the index of the new file in the archive, and\n.Fn zip_file_replace\nreturns 0.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh EXAMPLES\n.Bd -literal -offset indent\nzip_source_t *s;\nconst char buf[]=\"teststring\";\n\nif ((s=zip_source_buffer(archive, buf, sizeof(buf), 0)) == NULL ||\n    zip_file_add(archive, name, s, ZIP_FL_ENC_UTF_8) < 0) {\n    zip_source_free(s);\n    printf(\"error adding file: %s\\en\", zip_strerror(archive));\n}\n.Ed\n.Sh ERRORS\n.Fn zip_file_add\nand\n.Fn zip_file_replace\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_EXISTS\nThere is already a file called\n.Ar name\nin the archive.\n(Only applies to\n.Fn zip_file_add ,\nand only if\n.Dv ZIP_FL_OVERWRITE\nis not provided).\n.It Bq Er ZIP_ER_INVAL\n.Ar source\nor\n.Ar name\nare\n.Dv NULL ,\nor\n.Ar index\nis invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_RDONLY\nArchive was opened in read-only mode.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_file_add\nand\n.Fn zip_file_replace\nwere added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_attributes_init.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_attributes_init.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_attributes_init.mdoc -- initialize attributes structure\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_ATTRIBUTES_INIT\" \"3\" \"April 17, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_attributes_init\\fR\n\\- initialize zip file attributes structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_attributes_init\\fR(\\fIzip_file_attributes_t\\ *attributes\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_attributes_init\\fR()\ninitializes a\n\\fIzip_file_attributes_t\\fR\nstructure with default values.\nIt must be called before modifying such a structure for the first time.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source_function(3)\n.SH \"HISTORY\"\n\\fBzip_file_attributes_init\\fR()\nwas added in libzip 1.7.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_attributes_init.mdoc",
    "content": ".\\\" zip_file_attributes_init.mdoc -- initialize attributes structure\n.\\\" Copyright (C) 2020 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd April 17, 2020\n.Dt ZIP_FILE_ATTRIBUTES_INIT 3\n.Os\n.Sh NAME\n.Nm zip_file_attributes_init\n.Nd initialize zip file attributes structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_file_attributes_init \"zip_file_attributes_t *attributes\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_attributes_init\ninitializes a\n.Vt zip_file_attributes_t\nstructure with default values.\nIt must be called before modifying such a structure for the first time.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source_function 3\n.Sh HISTORY\n.Fn zip_file_attributes_init\nwas added in libzip 1.7.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_delete.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_delete.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_extra_field_delete.mdoc -- delete extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_EXTRA_FIELD_DELETE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_extra_field_delete\\fR,\n\\fBzip_file_extra_field_delete_by_id\\fR\n\\- delete extra field for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_field_delete\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_index\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_field_delete_by_id\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_id\\fR, \\fIzip_uint16_t\\ extra_field_index\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_extra_field_delete\\fR()\nfunction deletes the extra field with index\n\\fIextra_field_index\\fR\nfor the file at position\n\\fIindex\\fR\nin the zip archive.\n.PP\nIf\n\\fIextra_field_index\\fR\nis\n\\fRZIP_EXTRA_FIELD_ALL\\fR,\nthen all extra fields will be deleted.\n.PP\nThe following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 18n\n\\fRZIP_FL_CENTRAL\\fR\nDelete extra fields from the archive's central directory.\n.TP 18n\n\\fRZIP_FL_LOCAL\\fR\nDelete extra fields from the local file headers.\n.RE\n.PP\nThe\n\\fBzip_file_extra_field_delete_by_id\\fR()\nfunction deletes the extra field with ID (two-byte signature)\n\\fIextra_field_id\\fR\nand index\n\\fIextra_field_index\\fR\n(in other words, the\n\\fIextra_field_index\\fR'th\nextra field with ID\n\\fIextra_field_id\\fR)\nThe other arguments are the same as for\n\\fBzip_file_extra_field_delete\\fR()\n(\\fRZIP_EXTRA_FIELD_ALL\\fR\nwill delete all extra fields of the specified ID).\n.PP\nPlease note that due to the library design, the index of an extra\nfield may be different between central directory and local file\nheaders.\nFor this reason, it is not allowed to specify both\n\\fRZIP_FL_CENTRAL\\fR\nand\n\\fRZIP_FL_LOCAL\\fR\nin\n\\fIflags\\fR,\nexcept when deleting all extra fields (i.e.,\n\\fIextra_field_index\\fR\nbeing\n\\fRZIP_EXTRA_FIELD_ALL\\fR).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_extra_field_delete\\fR()\nand\n\\fBzip_file_extra_field_delete_by_id\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_extra_field_get(3),\nzip_file_extra_field_set(3),\nzip_file_extra_fields_count(3)\n.SH \"HISTORY\"\n\\fBzip_file_extra_field_delete\\fR()\nand\n\\fBzip_file_extra_field_delete_by_id\\fR()\nwere added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_delete.mdoc",
    "content": ".\\\" zip_file_extra_field_delete.mdoc -- delete extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_EXTRA_FIELD_DELETE 3\n.Os\n.Sh NAME\n.Nm zip_file_extra_field_delete ,\n.Nm zip_file_extra_field_delete_by_id\n.Nd delete extra field for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_extra_field_delete \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_index\" \"zip_flags_t flags\"\n.Ft int\n.Fn zip_file_extra_field_delete_by_id \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_id\" \"zip_uint16_t extra_field_index\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_extra_field_delete\nfunction deletes the extra field with index\n.Ar extra_field_index\nfor the file at position\n.Ar index\nin the zip archive.\n.Pp\nIf\n.Ar extra_field_index\nis\n.Dv ZIP_EXTRA_FIELD_ALL ,\nthen all extra fields will be deleted.\n.Pp\nThe following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_CENTRALXX -offset indent\n.It Dv ZIP_FL_CENTRAL\nDelete extra fields from the archive's central directory.\n.It Dv ZIP_FL_LOCAL\nDelete extra fields from the local file headers.\n.El\n.Pp\nThe\n.Fn zip_file_extra_field_delete_by_id\nfunction deletes the extra field with ID (two-byte signature)\n.Ar extra_field_id\nand index\n.Ar extra_field_index\n(in other words, the\n.Ar extra_field_index Ns No 'th\nextra field with ID\n.Ar extra_field_id )\nThe other arguments are the same as for\n.Fn zip_file_extra_field_delete\n.Dv ( ZIP_EXTRA_FIELD_ALL\nwill delete all extra fields of the specified ID).\n.Pp\nPlease note that due to the library design, the index of an extra\nfield may be different between central directory and local file\nheaders.\nFor this reason, it is not allowed to specify both\n.Dv ZIP_FL_CENTRAL\nand\n.Dv ZIP_FL_LOCAL\nin\n.Ar flags ,\nexcept when deleting all extra fields (i.e.,\n.Ar extra_field_index\nbeing\n.Dv ZIP_EXTRA_FIELD_ALL ) .\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_extra_field_delete\nand\n.Fn zip_file_extra_field_delete_by_id\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_NOENT\n.Ar index\nis not a valid file index in\n.Ar archive .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_extra_field_get 3 ,\n.Xr zip_file_extra_field_set 3 ,\n.Xr zip_file_extra_fields_count 3\n.Sh HISTORY\n.Fn zip_file_extra_field_delete\nand\n.Fn zip_file_extra_field_delete_by_id\nwere added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_get.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_get.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_extra_field_get.mdoc -- get extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_EXTRA_FIELD_GET\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_extra_field_get\\fR,\n\\fBzip_file_extra_field_get_by_id\\fR\n\\- get extra field for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst zip_uint8_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_field_get\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_index\\fR, \\fIzip_uint16_t\\ *idp\\fR, \\fIzip_uint16_t\\ *lenp\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIconst zip_uint8_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_field_get_by_id\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_id\\fR, \\fIzip_uint16_t\\ extra_field_index\\fR, \\fIzip_uint16_t\\ *lenp\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_extra_field_get\\fR()\nfunction returns the extra field with index\n\\fIextra_field_index\\fR\nfor the file at position\n\\fIindex\\fR\nin the zip archive.\nThis pointer should not be modified or\nfree(3)'d,\nand becomes invalid when\n\\fIarchive\\fR\nis closed.\nIf\n\\fIidp\\fR\nis not\n\\fRNULL\\fR,\nthe integer to which it points will be set to the ID (two-byte\nsignature) of the selected extra field.\nIf\n\\fIlenp\\fR\nis not\n\\fRNULL\\fR,\nthe integer to which it points will be set to the length of the\nextra field.\nGenerally speaking,\n\\fIlenp\\fR\nand\n\\fIidp\\fR\nshould be passed since only the extra field data is returned (i.e.,\nneither the ID nor the length, if the\n\\fIidp\\fR\nand\n\\fIlenp\\fR\narguments are not provided).\n.PP\nThe following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 20n\n\\fRZIP_FL_CENTRAL\\fR\nReturn extra fields from the archive's central directory.\n.TP 20n\n\\fRZIP_FL_LOCAL\\fR\nReturn extra fields from the local file headers.\n.TP 20n\n\\fRZIP_FL_UNCHANGED\\fR\nReturn the original unchanged extra fields, ignoring any changes made.\n.RE\n.PP\nThe\n\\fBzip_file_extra_field_get_by_id\\fR()\nfunction returns the extra field with ID (two-byte signature)\n\\fIextra_field_id\\fR\nand index\n\\fIextra_field_index\\fR\n(in other words, the\n\\fIextra_field_index\\fR'th\nextra field with ID\n\\fIextra_field_id\\fR)\nThe other arguments are the same as for\n\\fBzip_file_extra_field_get\\fR().\n.SH \"RETURN VALUES\"\nUpon successful completion, a pointer to an extra field is returned,\nor\n\\fRNULL\\fR\nif there is no extra field with that\n\\fIextra_field_index\\fR\nfor the file with index\n\\fIindex\\fR.\nIn case of an error,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_extra_field_get\\fR()\nand\n\\fBzip_file_extra_field_get_by_id\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\nor\n\\fIextra_field_index\\fR\nis not a valid extra file index (for ID\n\\fIextra_field_id\\fR).\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_extra_field_delete(3),\nzip_file_extra_field_set(3),\nzip_file_extra_fields_count(3)\n.SH \"HISTORY\"\n\\fBzip_file_extra_field_get\\fR()\nand\n\\fBzip_file_extra_field_get_by_id\\fR()\nwere added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n.SH \"CAVEATS\"\nPlease note that the extra field IDs 0x0001 (ZIP64 extension),\n0x6375 (Infozip UTF-8 comment), and\n0x7075 (Infozip UTF-8 file name) can not be read using\n\\fBzip_file_extra_field_get\\fR()\nsince they are used by\nlibzip(3)\ninternally.\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_get.mdoc",
    "content": ".\\\" zip_file_extra_field_get.mdoc -- get extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_EXTRA_FIELD_GET 3\n.Os\n.Sh NAME\n.Nm zip_file_extra_field_get ,\n.Nm zip_file_extra_field_get_by_id\n.Nd get extra field for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const zip_uint8_t *\n.Fn zip_file_extra_field_get \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_index\" \"zip_uint16_t *idp\" \"zip_uint16_t *lenp\" \"zip_flags_t flags\"\n.Ft const zip_uint8_t *\n.Fn zip_file_extra_field_get_by_id \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_id\" \"zip_uint16_t extra_field_index\" \"zip_uint16_t *lenp\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_extra_field_get\nfunction returns the extra field with index\n.Ar extra_field_index\nfor the file at position\n.Ar index\nin the zip archive.\nThis pointer should not be modified or\n.Xr free 3 Ap d ,\nand becomes invalid when\n.Ar archive\nis closed.\nIf\n.Ar idp\nis not\n.Dv NULL ,\nthe integer to which it points will be set to the ID (two-byte\nsignature) of the selected extra field.\nIf\n.Ar lenp\nis not\n.Dv NULL ,\nthe integer to which it points will be set to the length of the\nextra field.\nGenerally speaking,\n.Ar lenp\nand\n.Ar idp\nshould be passed since only the extra field data is returned (i.e.,\nneither the ID nor the length, if the\n.Ar idp\nand\n.Ar lenp\narguments are not provided).\n.Pp\nThe following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_UNCHANGEDXX -offset indent\n.It Dv ZIP_FL_CENTRAL\nReturn extra fields from the archive's central directory.\n.It Dv ZIP_FL_LOCAL\nReturn extra fields from the local file headers.\n.It Dv ZIP_FL_UNCHANGED\nReturn the original unchanged extra fields, ignoring any changes made.\n.El\n.Pp\nThe\n.Fn zip_file_extra_field_get_by_id\nfunction returns the extra field with ID (two-byte signature)\n.Ar extra_field_id\nand index\n.Ar extra_field_index\n(in other words, the\n.Ar extra_field_index Ns No 'th\nextra field with ID\n.Ar extra_field_id )\nThe other arguments are the same as for\n.Fn zip_file_extra_field_get .\n.Sh RETURN VALUES\nUpon successful completion, a pointer to an extra field is returned,\nor\n.Dv NULL\nif there is no extra field with that\n.Ar extra_field_index\nfor the file with index\n.Ar index .\nIn case of an error,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_extra_field_get\nand\n.Fn zip_file_extra_field_get_by_id\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_NOENT\n.Ar index\nis not a valid file index in\n.Ar archive ,\nor\n.Ar extra_field_index\nis not a valid extra file index (for ID\n.Ar extra_field_id ) .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_extra_field_delete 3 ,\n.Xr zip_file_extra_field_set 3 ,\n.Xr zip_file_extra_fields_count 3\n.Sh HISTORY\n.Fn zip_file_extra_field_get\nand\n.Fn zip_file_extra_field_get_by_id\nwere added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n.Sh CAVEATS\nPlease note that the extra field IDs 0x0001 (ZIP64 extension),\n0x6375 (Infozip UTF-8 comment), and\n0x7075 (Infozip UTF-8 file name) can not be read using\n.Fn zip_file_extra_field_get\nsince they are used by\n.Xr libzip 3\ninternally.\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_set.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_set.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_extra_field_set.mdoc -- set extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_EXTRA_FIELD_SET\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_extra_field_set\\fR\n\\- set extra field for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_field_set\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_id\\fR, \\fIzip_uint16_t\\ extra_field_index\\fR, \\fIconst\\ zip_uint8_t\\ *extra_field_data\\fR, \\fIzip_uint16_t\\ len\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_extra_field_set\\fR()\nfunction sets the extra field with ID (two-byte signature)\n\\fIextra_field_id\\fR\nand index\n\\fIextra_field_index\\fR\nfor the file at position\n\\fIindex\\fR\nin the zip archive.\nThe extra field's data will be set to\n\\fIextra_field_data\\fR\nand length\n\\fIlen\\fR.\nIf a new entry shall be appended, set\n\\fIextra_field_index\\fR\nto\n\\fRZIP_EXTRA_FIELD_NEW\\fR.\n.PP\nAt least one of the following\n\\fIflags\\fR\nmust be set:\n.RS 6n\n.TP 18n\n\\fRZIP_FL_CENTRAL\\fR\nSet extra field in the archive's central directory.\n.TP 18n\n\\fRZIP_FL_LOCAL\\fR\nSet extra field in the local file headers.\n.RE\n.PP\nPlease note that the extra field IDs 0x0001 (ZIP64 extension),\n0x6375 (Infozip UTF-8 comment), and\n0x7075 (Infozip UTF-8 file name) can not be set using\n\\fBzip_file_extra_field_set\\fR()\nsince they are set by\nlibzip(3)\nautomatically when needed.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_extra_field_set\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nThe extra field size is too large (ID and length need 4 bytes; the\nmaximum length of all extra fields for one file combined is 65536\nbytes).\nThis error also occurs if\n\\fIextra_field_index\\fR\nis too large.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_extra_field_delete(3),\nzip_file_extra_field_get(3),\nzip_file_extra_fields_count(3)\n.SH \"HISTORY\"\n\\fBzip_file_extra_field_set\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_field_set.mdoc",
    "content": ".\\\" zip_file_extra_field_set.mdoc -- set extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_EXTRA_FIELD_SET 3\n.Os\n.Sh NAME\n.Nm zip_file_extra_field_set\n.Nd set extra field for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_extra_field_set \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_id\" \"zip_uint16_t extra_field_index\" \"const zip_uint8_t *extra_field_data\" \"zip_uint16_t len\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_extra_field_set\nfunction sets the extra field with ID (two-byte signature)\n.Ar extra_field_id\nand index\n.Ar extra_field_index\nfor the file at position\n.Ar index\nin the zip archive.\nThe extra field's data will be set to\n.Ar extra_field_data\nand length\n.Ar len .\nIf a new entry shall be appended, set\n.Ar extra_field_index\nto\n.Dv ZIP_EXTRA_FIELD_NEW .\n.Pp\nAt least one of the following\n.Ar flags\nmust be set:\n.Bl -tag -width ZIP_FL_CENTRALXX -offset indent\n.It Dv ZIP_FL_CENTRAL\nSet extra field in the archive's central directory.\n.It Dv ZIP_FL_LOCAL\nSet extra field in the local file headers.\n.El\n.Pp\nPlease note that the extra field IDs 0x0001 (ZIP64 extension),\n0x6375 (Infozip UTF-8 comment), and\n0x7075 (Infozip UTF-8 file name) can not be set using\n.Fn zip_file_extra_field_set\nsince they are set by\n.Xr libzip 3\nautomatically when needed.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_extra_field_set\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\nThe extra field size is too large (ID and length need 4 bytes; the\nmaximum length of all extra fields for one file combined is 65536\nbytes).\nThis error also occurs if\n.Ar extra_field_index\nis too large.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOENT\n.Ar index\nis not a valid file index in\n.Ar archive .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_extra_field_delete 3 ,\n.Xr zip_file_extra_field_get 3 ,\n.Xr zip_file_extra_fields_count 3\n.Sh HISTORY\n.Fn zip_file_extra_field_set\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_fields_count.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_extra_fields_count.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_extra_fields_count.mdoc -- count extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_EXTRA_FIELDS_COUNT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_extra_fields_count\\fR,\n\\fBzip_file_extra_fields_count_by_id\\fR\n\\- count extra fields for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int16_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_fields_count\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIzip_int16_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_extra_fields_count_by_id\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ extra_field_id\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_extra_fields_count\\fR()\nfunction counts the extra fields for the file at position\n\\fIindex\\fR\nin the zip archive.\n.PP\nThe following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 18n\n\\fRZIP_FL_CENTRAL\\fR\nCount extra fields from the archive's central directory.\n.TP 18n\n\\fRZIP_FL_LOCAL\\fR\nCount extra fields from the local file headers.\n.TP 18n\n\\fRZIP_FL_UNCHANGED\\fR\nCount the original unchanged extra fields, ignoring any changes made.\n.RE\n.PP\nThe\n\\fBzip_file_extra_fields_count_by_id\\fR()\nfunction counts the extra fields with ID (two-byte signature)\n\\fIextra_field_id\\fR.\nThe other arguments are the same as for\n\\fBzip_file_extra_fields_count\\fR().\n.PP\nExtra fields that are the same in the central directory and the local file\nheader are merged into one.\nTherefore, the counts with\n\\fRZIP_FL_CENTRAL\\fR\nand\n\\fRZIP_FL_LOCAL\\fR\ndo not need to add up to the same value as when given\n\\fRZIP_FL_CENTRAL|ZIP_FL_LOCAL\\fR\nat the same time.\n.SH \"RETURN VALUES\"\nUpon successful completion, the requested number of extra fields is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_extra_fields_count\\fR()\nand\n\\fBzip_file_extra_fields_count_by_id\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_extra_field_delete(3),\nzip_file_extra_field_get(3),\nzip_file_extra_field_set(3)\n.SH \"HISTORY\"\n\\fBzip_file_extra_fields_count\\fR()\nand\n\\fBzip_file_extra_fields_count_by_id\\fR()\nwere added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_extra_fields_count.mdoc",
    "content": ".\\\" zip_file_extra_fields_count.mdoc -- count extra field for file in zip\n.\\\" Copyright (C) 2012-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_EXTRA_FIELDS_COUNT 3\n.Os\n.Sh NAME\n.Nm zip_file_extra_fields_count ,\n.Nm zip_file_extra_fields_count_by_id\n.Nd count extra fields for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int16_t\n.Fn zip_file_extra_fields_count \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\"\n.Ft zip_int16_t\n.Fn zip_file_extra_fields_count_by_id \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t extra_field_id\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_extra_fields_count\nfunction counts the extra fields for the file at position\n.Ar index\nin the zip archive.\n.Pp\nThe following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_CENTRALXX -offset indent\n.It Dv ZIP_FL_CENTRAL\nCount extra fields from the archive's central directory.\n.It Dv ZIP_FL_LOCAL\nCount extra fields from the local file headers.\n.It Dv ZIP_FL_UNCHANGED\nCount the original unchanged extra fields, ignoring any changes made.\n.El\n.Pp\nThe\n.Fn zip_file_extra_fields_count_by_id\nfunction counts the extra fields with ID (two-byte signature)\n.Ar extra_field_id .\nThe other arguments are the same as for\n.Fn zip_file_extra_fields_count .\n.Pp\nExtra fields that are the same in the central directory and the local file\nheader are merged into one.\nTherefore, the counts with\n.Dv ZIP_FL_CENTRAL\nand\n.Dv ZIP_FL_LOCAL\ndo not need to add up to the same value as when given\n.Dv ZIP_FL_CENTRAL|ZIP_FL_LOCAL\nat the same time.\n.Sh RETURN VALUES\nUpon successful completion, the requested number of extra fields is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_extra_fields_count\nand\n.Fn zip_file_extra_fields_count_by_id\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_NOENT\n.Ar index\nis not a valid file index in\n.Ar archive .\n.\\\" TODO: _zip_read_local_ef errors\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_extra_field_delete 3 ,\n.Xr zip_file_extra_field_get 3 ,\n.Xr zip_file_extra_field_set 3\n.Sh HISTORY\n.Fn zip_file_extra_fields_count\nand\n.Fn zip_file_extra_fields_count_by_id\nwere added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_get_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_get_comment.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_GET_COMMENT\" \"3\" \"September 22, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_get_comment\\fR\n\\- get comment for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_get_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint32_t\\ *lenp\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_get_comment\\fR()\nfunction returns the comment for the file at position\n\\fIindex\\fR\nin the zip archive.\nThe name is in UTF-8 encoding unless\n\\fRZIP_FL_ENC_RAW\\fR\nwas specified (see below).\nThis pointer should not be modified or\nfree(3)'d,\nand becomes invalid when\n\\fIarchive\\fR\nis closed.\nIf\n\\fIlenp\\fR\nis not\n\\fRNULL\\fR,\nthe integer to which it points will be set to the length of the\ncomment.\nIf\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original unchanged comment is returned.\n.PP\nAdditionally, the following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 21n\n\\fRZIP_FL_ENC_RAW\\fR\nReturn the unmodified comment as it is in the ZIP archive.\n.TP 21n\n\\fRZIP_FL_ENC_GUESS\\fR\n(Default.)\nGuess the encoding of the comment in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.TP 21n\n\\fRZIP_FL_ENC_STRICT\\fR\nFollow the ZIP specification for file names and extend it to file\ncomments, expecting them to be encoded in CP-437 in the ZIP archive\n(except if it is a UTF-8 comment from the special extra field).\nConvert it to UTF-8.\n.RE\n\\fINote\\fR:\nASCII is a subset of both CP-437 and UTF-8.\n.SH \"RETURN VALUES\"\nUpon successful completion, a pointer to the comment is returned,\nor\n\\fRNULL\\fR\nif there is no comment.\nIn case of an error,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_get_comment\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_set_comment(3),\nzip_get_archive_comment(3)\n.SH \"HISTORY\"\n\\fBzip_file_get_comment\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_comment.mdoc",
    "content": ".\\\" zip_file_get_comment.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 22, 2020\n.Dt ZIP_FILE_GET_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_file_get_comment\n.Nd get comment for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_file_get_comment \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint32_t *lenp\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_get_comment\nfunction returns the comment for the file at position\n.Ar index\nin the zip archive.\nThe name is in UTF-8 encoding unless\n.Dv ZIP_FL_ENC_RAW\nwas specified (see below).\nThis pointer should not be modified or\n.Xr free 3 Ap d ,\nand becomes invalid when\n.Ar archive\nis closed.\nIf\n.Ar lenp\nis not\n.Dv NULL ,\nthe integer to which it points will be set to the length of the\ncomment.\nIf\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original unchanged comment is returned.\n.Pp\nAdditionally, the following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent\n.It Dv ZIP_FL_ENC_RAW\nReturn the unmodified comment as it is in the ZIP archive.\n.It Dv ZIP_FL_ENC_GUESS\n(Default.)\nGuess the encoding of the comment in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_STRICT\nFollow the ZIP specification for file names and extend it to file\ncomments, expecting them to be encoded in CP-437 in the ZIP archive\n(except if it is a UTF-8 comment from the special extra field).\nConvert it to UTF-8.\n.El\n.Em Note :\nASCII is a subset of both CP-437 and UTF-8.\n.Sh RETURN VALUES\nUpon successful completion, a pointer to the comment is returned,\nor\n.Dv NULL\nif there is no comment.\nIn case of an error,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_get_comment\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_set_comment 3 ,\n.Xr zip_get_archive_comment 3\n.Sh HISTORY\n.Fn zip_file_get_comment\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_error.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_get_error.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_get_error.mdoc -- extract zip_error from zip_file\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_GET_ERROR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_get_error\\fR\n\\- extract zip_error from zip_file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_error_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_get_error\\fR(\\fIzip_file_t\\ *zf\\fR);\n.PD\n.SH \"DESCRIPTION\"\n\\fBzip_file_get_error\\fR()\nfunction returns the zip_error associated with the zip_file\n\\fIzf\\fR.\n.SH \"SEE ALSO\"\nlibzip(3)\n.SH \"HISTORY\"\n\\fBzip_file_get_error\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_error.mdoc",
    "content": ".\\\" zip_file_get_error.mdoc -- extract zip_error from zip_file\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_GET_ERROR 3\n.Os\n.Sh NAME\n.Nm zip_file_get_error\n.Nd extract zip_error from zip_file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_error_t *\n.Fn zip_file_get_error \"zip_file_t *zf\"\n.Sh DESCRIPTION\n.Fn zip_file_get_error\nfunction returns the zip_error associated with the zip_file\n.Ar zf .\n.Sh SEE ALSO\n.Xr libzip 3\n.Sh HISTORY\n.Fn zip_file_get_error\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_external_attributes.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_get_external_attributes.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_get_external_attributes.mdoc -- get external attributes for file in zip\n.\\\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_GET_EXTERNAL_ATTRIBUTES\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_get_external_attributes\\fR\n\\- get external attributes for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_get_external_attributes\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint8_t\\ *opsys\\fR, \\fIzip_uint32_t\\ *attributes\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_get_external_attributes\\fR()\nfunction returns the operating system and external attributes for the\nfile at position\n\\fIindex\\fR\nin the zip archive.\nThe external attributes usually contain the operating system-specific\nfile permissions.\nIf\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original unchanged values are returned.\nIf\n\\fIopsys\\fR\nor\n\\fIattributes\\fR\nare\n\\fRNULL\\fR,\nthey are not filled in.\n.PP\nThe following operating systems are defined by the zip specification:\n.RS 6n\n.PD 0\n.PP\n\\fRZIP_OPSYS_ACORN_RISC\\fR\n.PP\n\\fRZIP_OPSYS_ALTERNATE_MVS\\fR\n.PP\n\\fRZIP_OPSYS_AMIGA\\fR\n.PP\n\\fRZIP_OPSYS_ATARI_ST\\fR\n.PP\n\\fRZIP_OPSYS_BEOS\\fR\n.PP\n\\fRZIP_OPSYS_CPM\\fR\n.PP\n\\fRZIP_OPSYS_DOS\\fR\n.PP\n\\fRZIP_OPSYS_MACINTOSH\\fR\n.PP\n\\fRZIP_OPSYS_MVS\\fR\n.PP\n\\fRZIP_OPSYS_OPENVMS\\fR\n.PP\n\\fRZIP_OPSYS_OS_2\\fR\n.PP\n\\fRZIP_OPSYS_OS_400\\fR\n.PP\n\\fRZIP_OPSYS_OS_X\\fR\n.PP\n\\fRZIP_OPSYS_TANDEM\\fR\n.PP\n\\fRZIP_OPSYS_UNIX\\fR\n.PP\n\\fRZIP_OPSYS_VFAT\\fR\n.PP\n\\fRZIP_OPSYS_VM_CMS\\fR\n.PP\n\\fRZIP_OPSYS_VSE\\fR\n.PP\n\\fRZIP_OPSYS_WINDOWS_NTFS\\fR\n(uncommon, use\n\\fRZIP_OPSYS_DOS\\fR\ninstead)\n.PP\n\\fRZIP_OPSYS_Z_SYSTEM\\fR\n.RE\n.PD\n.PP\nThe defines above follow the PKWARE Inc. Appnote; please note that\nthe InfoZIP Appnote has a slightly different mapping.\n.SH \"RETURN VALUES\"\nUpon successful completion, 0 is returned.\nIn case of an error,\n\\fR\\-1\\fR\nis returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"EXAMPLES\"\nThe following code can be used to expand\n\\fIattributes\\fR\nif the operating system is\n\\fRZIP_OPSYS_DOS\\fR.\n.nf\n.sp\n.RS 0n\n#include <sys/stat.h>\n\n#define FA_RDONLY       0x01            // FILE_ATTRIBUTE_READONLY\n#define FA_DIREC        0x10            // FILE_ATTRIBUTE_DIRECTORY\n\nstatic mode_t\n_zip_dos_attr2mode(zip_uint32_t attr)\n{\n   mode_t m = S_IRUSR | S_IRGRP | S_IROTH;\n   if (0 == (attr & FA_RDONLY))\n      m |= S_IWUSR | S_IWGRP | S_IWOTH;\n\n   if (attr & FA_DIREC)\n      m = (S_IFDIR | (m & ~S_IFMT)) | S_IXUSR | S_IXGRP | S_IXOTH;\n\n   return m;\n}\n.RE\n.fi\n.SH \"ERRORS\"\n\\fBzip_file_get_external_attributes\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_set_external_attributes(3)\n.SH \"HISTORY\"\n\\fBzip_file_get_external_attributes\\fR()\nwas added in libzip 0.11.2.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_get_external_attributes.mdoc",
    "content": ".\\\" zip_file_get_external_attributes.mdoc -- get external attributes for file in zip\n.\\\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_GET_EXTERNAL_ATTRIBUTES 3\n.Os\n.Sh NAME\n.Nm zip_file_get_external_attributes\n.Nd get external attributes for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_get_external_attributes \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\" \"zip_uint8_t *opsys\" \"zip_uint32_t *attributes\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_get_external_attributes\nfunction returns the operating system and external attributes for the\nfile at position\n.Ar index\nin the zip archive.\nThe external attributes usually contain the operating system-specific\nfile permissions.\nIf\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original unchanged values are returned.\nIf\n.Ar opsys\nor\n.Ar attributes\nare\n.Dv NULL ,\nthey are not filled in.\n.Pp\nThe following operating systems are defined by the zip specification:\n.Bl -item -compact -offset indent\n.It\n.Dv ZIP_OPSYS_ACORN_RISC\n.It\n.Dv ZIP_OPSYS_ALTERNATE_MVS\n.It\n.Dv ZIP_OPSYS_AMIGA\n.It\n.Dv ZIP_OPSYS_ATARI_ST\n.It\n.Dv ZIP_OPSYS_BEOS\n.It\n.Dv ZIP_OPSYS_CPM\n.It\n.Dv ZIP_OPSYS_DOS\n.It\n.Dv ZIP_OPSYS_MACINTOSH\n.It\n.Dv ZIP_OPSYS_MVS\n.It\n.Dv ZIP_OPSYS_OPENVMS\n.It\n.Dv ZIP_OPSYS_OS_2\n.It\n.Dv ZIP_OPSYS_OS_400\n.It\n.Dv ZIP_OPSYS_OS_X\n.It\n.Dv ZIP_OPSYS_TANDEM\n.It\n.Dv ZIP_OPSYS_UNIX\n.It\n.Dv ZIP_OPSYS_VFAT\n.It\n.Dv ZIP_OPSYS_VM_CMS\n.It\n.Dv ZIP_OPSYS_VSE\n.It\n.Dv ZIP_OPSYS_WINDOWS_NTFS\n(uncommon, use\n.Dv ZIP_OPSYS_DOS\ninstead)\n.It\n.Dv ZIP_OPSYS_Z_SYSTEM\n.El\n.Pp\nThe defines above follow the PKWARE Inc. Appnote; please note that\nthe InfoZIP Appnote has a slightly different mapping.\n.Sh RETURN VALUES\nUpon successful completion, 0 is returned.\nIn case of an error,\n.Dv \\-1\nis returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh EXAMPLES\nThe following code can be used to expand\n.Ar attributes\nif the operating system is\n.Dv ZIP_OPSYS_DOS .\n.Bd -literal\n#include <sys/stat.h>\n\n#define FA_RDONLY       0x01            // FILE_ATTRIBUTE_READONLY\n#define FA_DIREC        0x10            // FILE_ATTRIBUTE_DIRECTORY\n\nstatic mode_t\n_zip_dos_attr2mode(zip_uint32_t attr)\n{\n   mode_t m = S_IRUSR | S_IRGRP | S_IROTH;\n   if (0 == (attr & FA_RDONLY))\n      m |= S_IWUSR | S_IWGRP | S_IWOTH;\n\n   if (attr & FA_DIREC)\n      m = (S_IFDIR | (m & ~S_IFMT)) | S_IXUSR | S_IXGRP | S_IXOTH;\n\n   return m;\n}\n.Ed\n.Sh ERRORS\n.Fn zip_file_get_external_attributes\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_set_external_attributes 3\n.Sh HISTORY\n.Fn zip_file_get_external_attributes\nwas added in libzip 0.11.2.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_rename.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_rename.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_rename.mdoc -- rename file in zip archive\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_RENAME\" \"3\" \"September 22, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_rename\\fR\n\\- rename file in zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_rename\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIconst\\ char\\ *name\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe file at position\n\\fIindex\\fR\nin the zip archive\n\\fIarchive\\fR\nis renamed to\n\\fIname\\fR.\nThe\n\\fIflags\\fR\nargument can be any of:\n.TP 22n\n\\fRZIP_FL_ENC_GUESS\\fR\nGuess encoding of\n\\fIname\\fR\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.TP 22n\n\\fRZIP_FL_ENC_UTF_8\\fR\nInterpret\n\\fIname\\fR\nas UTF-8.\n.TP 22n\n\\fRZIP_FL_ENC_CP437\\fR\nInterpret\n\\fIname\\fR\nas code page 437 (CP-437).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_rename\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_DELETED\\fR]\nThe file to be renamed has been deleted from the archive.\n.TP 19n\n[\\fRZIP_ER_EXISTS\\fR]\nThere is already a file called\n\\fIname\\fR\nin the archive.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\n\\fIname is\\fR\n\\fRNULL\\fR,\nthe empty string, or not a valid UTF-8 encoded string.\nAlso a file cannot be renamed to a directory or vice versa.\nDirectories are denoted by a trailing slash.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_unchange(3)\n.SH \"HISTORY\"\n\\fBzip_file_rename\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_rename.mdoc",
    "content": ".\\\" zip_file_rename.mdoc -- rename file in zip archive\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 22, 2020\n.Dt ZIP_FILE_RENAME 3\n.Os\n.Sh NAME\n.Nm zip_file_rename\n.Nd rename file in zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_rename \"zip_t *archive\" \"zip_uint64_t index\" \"const char *name\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe file at position\n.Ar index\nin the zip archive\n.Ar archive\nis renamed to\n.Ar name .\nThe\n.Ar flags\nargument can be any of:\n.Bl -tag -width XZIPXFLXENCXSTRICTXX\n.It Dv ZIP_FL_ENC_GUESS\nGuess encoding of\n.Ar name\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_UTF_8\nInterpret\n.Ar name\nas UTF-8.\n.It Dv ZIP_FL_ENC_CP437\nInterpret\n.Ar name\nas code page 437 (CP-437).\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_rename\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_DELETED\nThe file to be renamed has been deleted from the archive.\n.It Bq Er ZIP_ER_EXISTS\nThere is already a file called\n.Ar name\nin the archive.\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive ,\n.Ar name is\n.Dv NULL ,\nthe empty string, or not a valid UTF-8 encoded string.\nAlso a file cannot be renamed to a directory or vice versa.\nDirectories are denoted by a trailing slash.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_unchange 3\n.Sh HISTORY\n.Fn zip_file_rename\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_set_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_set_comment.mdoc -- set comment for file in zip\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_SET_COMMENT\" \"3\" \"September 22, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_set_comment\\fR\n\\- set comment for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_set_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIconst\\ char\\ *comment\\fR, \\fIzip_uint16_t\\ len\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_set_comment\\fR()\nfunction sets the comment for the file at position\n\\fIindex\\fR\nin the zip archive to\n\\fIcomment\\fR\nof length\n\\fIlen\\fR.\nIf\n\\fIcomment\\fR\nis\n\\fRNULL\\fR\nand\n\\fIlen\\fR\nis 0, the file comment will be removed.\nThe\n\\fIflags\\fR\nargument can be any of:\n.TP 22n\n\\fRZIP_FL_ENC_GUESS\\fR\nGuess encoding of\n\\fIcomment\\fR\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.TP 22n\n\\fRZIP_FL_ENC_UTF_8\\fR\nInterpret\n\\fIcomment\\fR\nas UTF-8.\n.TP 22n\n\\fRZIP_FL_ENC_CP437\\fR\nInterpret\n\\fIcomment\\fR\nas code page 437 (CP-437).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_set_comment\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\nor\n\\fIlen\\fR\nis less than 0 or longer than the maximum comment length in a zip file\n(65535), or\n\\fIcomment\\fR\nis not a valid UTF-8 encoded string.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nThe\n\\fIarchive\\fR\nwas opened in read-only mode.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_get_comment(3),\nzip_get_archive_comment(3),\nzip_set_archive_comment(3)\n.SH \"HISTORY\"\n\\fBzip_file_set_comment\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_comment.mdoc",
    "content": ".\\\" zip_file_set_comment.mdoc -- set comment for file in zip\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 22, 2020\n.Dt ZIP_FILE_SET_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_file_set_comment\n.Nd set comment for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_set_comment \"zip_t *archive\" \"zip_uint64_t index\" \"const char *comment\" \"zip_uint16_t len\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_set_comment\nfunction sets the comment for the file at position\n.Ar index\nin the zip archive to\n.Ar comment\nof length\n.Ar len .\nIf\n.Ar comment\nis\n.Dv NULL\nand\n.Ar len\nis 0, the file comment will be removed.\nThe\n.Ar flags\nargument can be any of:\n.Bl -tag -width XZIPXFLXENCXSTRICTXX\n.It Dv ZIP_FL_ENC_GUESS\nGuess encoding of\n.Ar comment\n(default).\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_UTF_8\nInterpret\n.Ar comment\nas UTF-8.\n.It Dv ZIP_FL_ENC_CP437\nInterpret\n.Ar comment\nas code page 437 (CP-437).\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_set_comment\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive ,\nor\n.Ar len\nis less than 0 or longer than the maximum comment length in a zip file\n(65535), or\n.Ar comment\nis not a valid UTF-8 encoded string.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_RDONLY\nThe\n.Ar archive\nwas opened in read-only mode.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_get_comment 3 ,\n.Xr zip_get_archive_comment 3 ,\n.Xr zip_set_archive_comment 3\n.Sh HISTORY\n.Fn zip_file_set_comment\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_encryption.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_set_encryption.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_set_encryption.mdoc -- set encryption method for file\n.\\\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_SET_ENCRYPTION\" \"3\" \"April 2, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_set_encryption\\fR\n\\- set encryption method for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_set_encryption\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ method\\fR, \\fIconst\\ char\\ *password\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_set_encryption\\fR()\nfunction sets the encryption method for the file at position\n\\fIindex\\fR\nin the zip archive to\n\\fImethod\\fR\nusing the password\n\\fIpassword\\fR.\nThe\n\\fImethod\\fR\nis the same as returned by\nzip_stat(3).\nFor the\n\\fImethod\\fR\nargument, currently only the following values are supported:\n.TP 19n\n\\fRZIP_EM_NONE\\fR\nNo encryption.\n.TP 19n\n\\fRZIP_EM_AES_128\\fR\nWinzip AES-128 encryption.\n.TP 19n\n\\fRZIP_EM_AES_192\\fR\nWinzip AES-192 encryption.\n.TP 19n\n\\fRZIP_EM_AES_256\\fR\nWinzip AES-256 encryption.\n.TP 19n\n\\fRZIP_EM_TRAD_PKWARE\\fR\n.br\nTraditional PKWare encryption.\nDo not use this method, it is not secure.\nIt is only provided for backwards compatibility.\n.PP\nIf\n\\fIpassword\\fR\nis\n\\fRNULL\\fR,\nthe default password provided by\nzip_set_default_password(3)\nis used.\n.PP\nThe current encryption method for a file in a zip archive can be\ndetermined using\nzip_stat(3).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_set_encryption\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_ENCRNOTSUPP\\fR]\nUnsupported compression method requested.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\nor the argument combination is invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nRead-only zip file, no changes allowed.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_encryption_method_supported(3),\nzip_fopen_encrypted(3),\nzip_fopen_index_encrypted(3),\nzip_set_default_password(3),\nzip_stat(3)\n.SH \"HISTORY\"\n\\fBzip_file_set_encryption\\fR()\nwas added in libzip 1.2.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_encryption.mdoc",
    "content": ".\\\" zip_file_set_encryption.mdoc -- set encryption method for file\n.\\\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd April 2, 2020\n.Dt ZIP_FILE_SET_ENCRYPTION 3\n.Os\n.Sh NAME\n.Nm zip_file_set_encryption\n.Nd set encryption method for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_set_encryption \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t method\" \"const char *password\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_set_encryption\nfunction sets the encryption method for the file at position\n.Ar index\nin the zip archive to\n.Ar method\nusing the password\n.Ar password .\nThe\n.Ar method\nis the same as returned by\n.Xr zip_stat 3 .\nFor the\n.Ar method\nargument, currently only the following values are supported:\n.Bl -tag -width ZIP_CM_DEFLATE_XX\n.It Dv ZIP_EM_NONE\nNo encryption.\n.It Dv ZIP_EM_AES_128\nWinzip AES-128 encryption.\n.It Dv ZIP_EM_AES_192\nWinzip AES-192 encryption.\n.It Dv ZIP_EM_AES_256\nWinzip AES-256 encryption.\n.It Dv ZIP_EM_TRAD_PKWARE\nTraditional PKWare encryption.\nDo not use this method, it is not secure.\nIt is only provided for backwards compatibility.\n.El\n.Pp\nIf\n.Ar password\nis\n.Dv NULL ,\nthe default password provided by\n.Xr zip_set_default_password 3\nis used.\n.Pp\nThe current encryption method for a file in a zip archive can be\ndetermined using\n.Xr zip_stat 3 .\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_set_encryption\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_ENCRNOTSUPP\nUnsupported compression method requested.\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive ,\nor the argument combination is invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_RDONLY\nRead-only zip file, no changes allowed.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_encryption_method_supported 3 ,\n.Xr zip_fopen_encrypted 3 ,\n.Xr zip_fopen_index_encrypted 3 ,\n.Xr zip_set_default_password 3 ,\n.Xr zip_stat 3\n.Sh HISTORY\n.Fn zip_file_set_encryption\nwas added in libzip 1.2.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_external_attributes.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_set_external_attributes.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_set_external_attributes.mdoc -- set external attributes for file in zip\n.\\\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_SET_EXTERNAL_ATTRIBUTES\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_set_external_attributes\\fR\n\\- set external attributes for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_set_external_attributes\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint8_t\\ opsys\\fR, \\fIzip_uint32_t\\ attributes\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_set_external_attributes\\fR()\nfunction sets the operating system and external attributes for the\nfile at position\n\\fIindex\\fR\nin the zip archive.\nCurrently, no\n\\fIflags\\fR\nare supported.\n.PP\nFor a list of known\n\\fIopsys\\fR\nvalues, see\nzip_file_get_external_attributes(3).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_set_external_attributes\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nThe\n\\fIarchive\\fR\nwas opened in read-only mode.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_get_external_attributes(3)\n.SH \"HISTORY\"\n\\fBzip_file_set_external_attributes\\fR()\nwas added in libzip 0.11.2.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_external_attributes.mdoc",
    "content": ".\\\" zip_file_set_external_attributes.mdoc -- set external attributes for file in zip\n.\\\" Copyright (C) 2013-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_SET_EXTERNAL_ATTRIBUTES 3\n.Os\n.Sh NAME\n.Nm zip_file_set_external_attributes\n.Nd set external attributes for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_set_external_attributes \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\" \"zip_uint8_t opsys\" \"zip_uint32_t attributes\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_set_external_attributes\nfunction sets the operating system and external attributes for the\nfile at position\n.Ar index\nin the zip archive.\nCurrently, no\n.Ar flags\nare supported.\n.Pp\nFor a list of known\n.Ar opsys\nvalues, see\n.Xr zip_file_get_external_attributes 3 .\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_set_external_attributes\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_RDONLY\nThe\n.Ar archive\nwas opened in read-only mode.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_get_external_attributes 3\n.Sh HISTORY\n.Fn zip_file_set_external_attributes\nwas added in libzip 0.11.2.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_mtime.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_set_mtime.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_set_mtime.mdoc -- set mtime for file in zip\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_SET_MTIME\" \"3\" \"June 18, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_set_dostime\\fR,\n\\fBzip_file_set_mtime\\fR\n\\- set last modification time (mtime) for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_set_dostime\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_uint16_t\\ dostime\\fR, \\fIzip_uint16_t\\ dosdate\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_set_mtime\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fItime_t\\ mtime\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_file_set_mtime\\fR()\nfunction sets the last modification time (mtime) for the file at\nposition\n\\fIindex\\fR\nin the zip archive to\n\\fImtime\\fR.\nCurrently, no support for any\n\\fIflags\\fR\nis implemented.\n.PP\nIn the zip archive, the time and date are saved as two 16-bit integers.\nTo set the values directly, call the\n\\fBzip_file_set_dostime\\fR()\nfunction.\nThe values of the time bytes are defined as follows:\n.RS 6n\n.TP 7n\n0-4\nseconds divided by two (1-2 = 1, 3-4 = 2, ...)\n.TP 7n\n5-10\nminute (0-59)\n.TP 7n\n11-15\nhour (0-23)\n.RE\n.PP\nThe values of the date bytes are defined as follows:\n.RS 6n\n.TP 7n\n0-4\nday of the month (1-31)\n.TP 7n\n5-8\nmonth (January = 1, February = 2, ...)\n.TP 7n\n9-15\nyear offset from 1980 (1980 = 0, 1981 = 1, ...)\n.RE\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_file_set_dostime\\fR()\nand\n\\fBzip_file_set_mtime\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_OPNOTSUPP\\fR]\n.br\nTraditional PKWare encryption uses the file's mtime, therefore it cannot be changed without re-encrypting the data.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nThe\n\\fIarchive\\fR\nwas opened in read-only mode.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_stat(3)\n.SH \"HISTORY\"\n\\fBzip_file_set_mtime\\fR()\nwas added in libzip 1.0.\n\\fBzip_file_set_dostime\\fR()\nwas added in libzip 1.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n.SH \"CAVEATS\"\nFollowing historical practice, the\n\\fBzip_file_set_mtime\\fR()\nfunction translates the time from the zip archive into the local time\nzone.\nIf you want to avoid this, use the\n\\fBzip_file_set_dostime\\fR()\nfunction instead.\n"
  },
  {
    "path": "external/libzip/man/zip_file_set_mtime.mdoc",
    "content": ".\\\" zip_file_set_mtime.mdoc -- set mtime for file in zip\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 18, 2022\n.Dt ZIP_FILE_SET_MTIME 3\n.Os\n.Sh NAME\n.Nm zip_file_set_dostime ,\n.Nm zip_file_set_mtime\n.Nd set last modification time (mtime) for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_file_set_dostime \"zip_t *archive\" \"zip_uint64_t index\" \"zip_uint16_t dostime\" \"zip_uint16_t dosdate\" \"zip_flags_t flags\"\n.Ft int\n.Fn zip_file_set_mtime \"zip_t *archive\" \"zip_uint64_t index\" \"time_t mtime\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_file_set_mtime\nfunction sets the last modification time (mtime) for the file at\nposition\n.Ar index\nin the zip archive to\n.Ar mtime .\nCurrently, no support for any\n.Ar flags\nis implemented.\n.Pp\nIn the zip archive, the time and date are saved as two 16-bit integers.\nTo set the values directly, call the\n.Fn zip_file_set_dostime\nfunction.\nThe values of the time bytes are defined as follows:\n.Bl -tag -width 5n -offset indent\n.It 0-4\nseconds divided by two (1-2 = 1, 3-4 = 2, ...)\n.It 5-10\nminute (0-59)\n.It 11-15\nhour (0-23)\n.El\n.Pp\nThe values of the date bytes are defined as follows:\n.Bl -tag -width 5n -offset indent\n.It 0-4\nday of the month (1-31)\n.It 5-8\nmonth (January = 1, February = 2, ...)\n.It 9-15\nyear offset from 1980 (1980 = 0, 1981 = 1, ...)\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_file_set_dostime\nand\n.Fn zip_file_set_mtime\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_OPNOTSUPP\nTraditional PKWare encryption uses the file's mtime, therefore it cannot be changed without re-encrypting the data.\n.It Bq Er ZIP_ER_RDONLY\nThe\n.Ar archive\nwas opened in read-only mode.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_stat 3\n.Sh HISTORY\n.Fn zip_file_set_mtime\nwas added in libzip 1.0.\n.Fn zip_file_set_dostime\nwas added in libzip 1.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n.Sh CAVEATS\nFollowing historical practice, the\n.Fn zip_file_set_mtime\nfunction translates the time from the zip archive into the local time\nzone.\nIf you want to avoid this, use the\n.Fn zip_file_set_dostime\nfunction instead.\n"
  },
  {
    "path": "external/libzip/man/zip_file_strerror.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_file_strerror.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_file_strerror.mdoc -- get string representation for a zip error\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FILE_STRERROR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_file_strerror\\fR,\n\\fBzip_strerror\\fR\n\\- get string representation for a zip error\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_strerror\\fR(\\fIzip_file_t\\ *file\\fR);\n.PD\n.PP\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_strerror\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_strerror\\fR()\nfunction returns a string describing the last error for the zip archive\n\\fIarchive\\fR,\nwhile the\n\\fBzip_file_strerror\\fR()\nfunction does the same for a zip file\n\\fIfile\\fR\n(one file in an archive).\nThe returned string must not be modified or freed, and becomes invalid when\n\\fIarchive\\fR\nor\n\\fIfile\\fR,\nrespectively,\nis closed or on the next call to\n\\fBzip_strerror\\fR()\nor\n\\fBzip_file_strerror\\fR(),\nrespectively,\nfor the same archive.\n.SH \"RETURN VALUES\"\n\\fBzip_file_strerror\\fR()\nand\n\\fBzip_strerror\\fR()\nreturn a pointer to the error string.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_strerror(3)\n.SH \"HISTORY\"\n\\fBzip_file_strerror\\fR()\nand\n\\fBzip_strerror\\fR()\nwere added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_file_strerror.mdoc",
    "content": ".\\\" zip_file_strerror.mdoc -- get string representation for a zip error\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FILE_STRERROR 3\n.Os\n.Sh NAME\n.Nm zip_file_strerror ,\n.Nm zip_strerror\n.Nd get string representation for a zip error\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_file_strerror \"zip_file_t *file\"\n.Ft const char *\n.Fn zip_strerror \"zip_t *archive\"\n.Sh DESCRIPTION\nThe\n.Fn zip_strerror\nfunction returns a string describing the last error for the zip archive\n.Ar archive ,\nwhile the\n.Fn zip_file_strerror\nfunction does the same for a zip file\n.Ar file\n(one file in an archive).\nThe returned string must not be modified or freed, and becomes invalid when\n.Ar archive\nor\n.Ar file ,\nrespectively,\nis closed or on the next call to\n.Fn zip_strerror\nor\n.Fn zip_file_strerror ,\nrespectively,\nfor the same archive.\n.Sh RETURN VALUES\n.Fn zip_file_strerror\nand\n.Fn zip_strerror\nreturn a pointer to the error string.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_strerror 3\n.Sh HISTORY\n.Fn zip_file_strerror\nand\n.Fn zip_strerror\nwere added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_fopen.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fopen.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fopen.mdoc -- open file in zip archive for reading\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FOPEN\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fopen\\fR,\n\\fBzip_fopen_index\\fR\n\\- open file in zip archive for reading\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_file_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fopen\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.PP\n\\fIzip_file_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fopen_index\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_fopen\\fR()\nfunction opens the file name\n\\fIfname\\fR\nin\n\\fIarchive\\fR.\nThe\n\\fIflags\\fR\nargument specifies how the name lookup should be done, according to\nthe values are described in\nzip_name_locate(3).\nAlso, the following values may be\n\\fIor\\fR'ed\nto it.\n.RS 6n\n.TP 19n\n\\fRZIP_FL_COMPRESSED\\fR\nRead the compressed data.\nOtherwise the data is uncompressed by\n\\fBzip_fread\\fR().\n.TP 19n\n\\fRZIP_FL_UNCHANGED\\fR\nRead the original data from the zip archive, ignoring any changes made\nto the file; this is not supported by all data sources.\n.RE\n.PP\nThe\n\\fBzip_fopen_index\\fR()\nfunction opens the file at position\n\\fIindex\\fR.\n.PP\nIf encrypted data is encountered, the functions call\nzip_fopen_encrypted(3)\nor\nzip_fopen_index_encrypted(3)\nrespectively, using the default password set with\nzip_set_default_password(3).\n.SH \"RETURN VALUES\"\nUpon successful completion, a\n\\fIstruct zip_file\\fR\npointer is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n.TP 19n\n[\\fRZIP_ER_CHANGED\\fR]\nThe file data has been changed and the data source does\nnot support rereading data.\n.TP 19n\n[\\fRZIP_ER_COMPNOTSUPP\\fR]\nThe compression method used is not supported.\n.TP 19n\n[\\fRZIP_ER_ENCRNOTSUPP\\fR]\nThe encryption method used is not supported.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOPASSWD\\fR]\nThe file is encrypted, but no password has been provided.\n.TP 19n\n[\\fRZIP_ER_READ\\fR]\nA file read error occurred.\n.TP 19n\n[\\fRZIP_ER_SEEK\\fR]\nA file seek error occurred.\n.TP 19n\n[\\fRZIP_ER_WRONGPASSWD\\fR]\nThe provided password does not match the password used for encryption.\nNote that some incorrect passwords are not detected by the check done by\n\\fBzip_fopen\\fR().\n.TP 19n\n[\\fRZIP_ER_ZLIB\\fR]\nInitializing the zlib stream failed.\n.PP\nThe function\n\\fBzip_fopen\\fR()\nmay also fail and set\n\\fIzip_err\\fR\nfor any of the errors specified for the routine\nzip_name_locate(3).\n.PP\nThe function\n\\fBzip_fopen_index\\fR()\nmay also fail with\n\\fRZIP_ER_INVAL\\fR\nif\n\\fIindex\\fR\nis invalid.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fclose(3),\nzip_fread(3),\nzip_fseek(3),\nzip_get_num_entries(3),\nzip_name_locate(3),\nzip_set_default_password(3)\n.SH \"HISTORY\"\n\\fBzip_fopen\\fR()\nand\n\\fBzip_fopen_index\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_fopen.mdoc",
    "content": ".\\\" zip_fopen.mdoc -- open file in zip archive for reading\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_FOPEN 3\n.Os\n.Sh NAME\n.Nm zip_fopen ,\n.Nm zip_fopen_index\n.Nd open file in zip archive for reading\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_file_t *\n.Fn zip_fopen \"zip_t *archive\" \"const char *fname\" \"zip_flags_t flags\"\n.Ft zip_file_t *\n.Fn zip_fopen_index \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_fopen\nfunction opens the file name\n.Ar fname\nin\n.Ar archive .\nThe\n.Ar flags\nargument specifies how the name lookup should be done, according to\nthe values are described in\n.Xr zip_name_locate 3 .\nAlso, the following values may be\n.Em or Ns No 'ed\nto it.\n.Bl -tag -offset indent -width ZIP_FL_COMPRESSED\n.It Dv ZIP_FL_COMPRESSED\nRead the compressed data.\nOtherwise the data is uncompressed by\n.Fn zip_fread .\n.It Dv ZIP_FL_UNCHANGED\nRead the original data from the zip archive, ignoring any changes made\nto the file; this is not supported by all data sources.\n.El\n.Pp\nThe\n.Fn zip_fopen_index\nfunction opens the file at position\n.Ar index .\n.Pp\nIf encrypted data is encountered, the functions call\n.Xr zip_fopen_encrypted 3\nor\n.Xr zip_fopen_index_encrypted 3\nrespectively, using the default password set with\n.Xr zip_set_default_password 3 .\n.Sh RETURN VALUES\nUpon successful completion, a\n.Ft struct zip_file\npointer is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_CHANGED\nThe file data has been changed and the data source does\nnot support rereading data.\n.It Bq Er ZIP_ER_COMPNOTSUPP\nThe compression method used is not supported.\n.It Bq Er ZIP_ER_ENCRNOTSUPP\nThe encryption method used is not supported.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOPASSWD\nThe file is encrypted, but no password has been provided.\n.It Bq Er ZIP_ER_READ\nA file read error occurred.\n.It Bq Er ZIP_ER_SEEK\nA file seek error occurred.\n.It Bq Er ZIP_ER_WRONGPASSWD\nThe provided password does not match the password used for encryption.\nNote that some incorrect passwords are not detected by the check done by\n.Fn zip_fopen .\n.It Bq Er ZIP_ER_ZLIB\nInitializing the zlib stream failed.\n.El\n.Pp\nThe function\n.Fn zip_fopen\nmay also fail and set\n.Va zip_err\nfor any of the errors specified for the routine\n.Xr zip_name_locate 3 .\n.Pp\nThe function\n.Fn zip_fopen_index\nmay also fail with\n.Er ZIP_ER_INVAL\nif\n.Ar index\nis invalid.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fclose 3 ,\n.Xr zip_fread 3 ,\n.Xr zip_fseek 3 ,\n.Xr zip_get_num_entries 3 ,\n.Xr zip_name_locate 3 ,\n.Xr zip_set_default_password 3\n.Sh HISTORY\n.Fn zip_fopen\nand\n.Fn zip_fopen_index\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_fopen_encrypted.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fopen_encrypted.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fopen_encrypted.mdoc -- open encrypted file in zip archive for reading\n.\\\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FOPEN_ENCRYPTED\" \"3\" \"September 15, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fopen_encrypted\\fR,\n\\fBzip_fopen_index_encrypted\\fR\n\\- open encrypted file in zip archive for reading\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_file_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fopen_encrypted\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIconst\\ char\\ *password\\fR);\n.PD\n.PP\n\\fIzip_file_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fopen_index_encrypted\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIconst\\ char\\ *password\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_fopen_encrypted\\fR()\nfunction opens the encrypted file name\n\\fIfname\\fR\nin\n\\fIarchive\\fR\nusing the password given in the\n\\fIpassword\\fR\nargument.\nIf\n\\fIpassword\\fR\nis\n\\fRNULL\\fR\nor the empty string, the default password is used (see\nzip_set_default_password(3)).\nThe\n\\fIflags\\fR\nargument are the same as for\nzip_fopen(3).\n.PP\nThe\n\\fBzip_fopen_index_encrypted\\fR()\nfunction opens the file at position\n\\fIindex\\fR,\nsee\nzip_fopen_index(3).\nThese functions are called automatically by\nzip_fopen(3);\nyou only need to call them if you want to specify a non-default password\n(see\nzip_set_default_password(3)).\n.SH \"RETURN VALUES\"\nUpon successful completion, a\n\\fIstruct zip_file\\fR\npointer is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n.TP 22n\n[\\fRZIP_ER_NOPASSWD\\fR]\nNo password was provided.\n.PP\nThe function\n\\fBzip_fopen_encrypted\\fR()\nmay also fail and set\n\\fIzip_err\\fR\nfor any of the errors specified for the routine\nzip_fopen(3).\n.PP\nThe function\n\\fBzip_fopen_index_encrypted\\fR()\nmay also fail and set\n\\fIzip_err\\fR\nfor any of the errors specified for the routine\nzip_fopen_index(3).\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fclose(3),\nzip_fopen(3),\nzip_fread(3),\nzip_get_num_entries(3),\nzip_name_locate(3)\n.SH \"HISTORY\"\n\\fBzip_fopen_encrypted\\fR()\nand\n\\fBzip_fopen_index_encrypted\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n.SH \"CAVEATS\"\nThe zip file format provides very limited possibility for password\nverification (a short hash of is compared against one byte in the zip\narchive).\nFor this reason, reading a file while using an incorrect password may\nimmediately fail with\n\\fRZIP_ER_WRONGPASSWD\\fR,\nbut if the mismatch is not detected, a zlib error may be returned\nlater instead.\nSince zlib errors can also be caused by broken compressed data, there\nis no way to make sure if the password was incorrect or if it was\ncorrect, but the compressed data was invalid.\n"
  },
  {
    "path": "external/libzip/man/zip_fopen_encrypted.mdoc",
    "content": ".\\\" zip_fopen_encrypted.mdoc -- open encrypted file in zip archive for reading\n.\\\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 15, 2020\n.Dt ZIP_FOPEN_ENCRYPTED 3\n.Os\n.Sh NAME\n.Nm zip_fopen_encrypted ,\n.Nm zip_fopen_index_encrypted\n.Nd open encrypted file in zip archive for reading\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_file_t *\n.Fn zip_fopen_encrypted \"zip_t *archive\" \"const char *fname\" \"zip_flags_t flags\" \"const char *password\"\n.Ft zip_file_t *\n.Fn zip_fopen_index_encrypted \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\" \"const char *password\"\n.Sh DESCRIPTION\nThe\n.Fn zip_fopen_encrypted\nfunction opens the encrypted file name\n.Ar fname\nin\n.Ar archive\nusing the password given in the\n.Ar password\nargument.\nIf\n.Ar password\nis\n.Dv NULL\nor the empty string, the default password is used (see\n.Xr zip_set_default_password 3 ) .\nThe\n.Ar flags\nargument are the same as for\n.Xr zip_fopen 3 .\n.Pp\nThe\n.Fn zip_fopen_index_encrypted\nfunction opens the file at position\n.Ar index ,\nsee\n.Xr zip_fopen_index 3 .\nThese functions are called automatically by\n.Xr zip_fopen 3 ;\nyou only need to call them if you want to specify a non-default password\n(see\n.Xr zip_set_default_password 3 ) .\n.Sh RETURN VALUES\nUpon successful completion, a\n.Ft struct zip_file\npointer is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Bl -tag -width ZIP_ER_ENCRNOTSUPPXX\n.It Bq Er ZIP_ER_NOPASSWD\nNo password was provided.\n.El\n.Pp\nThe function\n.Fn zip_fopen_encrypted\nmay also fail and set\n.Va zip_err\nfor any of the errors specified for the routine\n.Xr zip_fopen 3 .\n.Pp\nThe function\n.Fn zip_fopen_index_encrypted\nmay also fail and set\n.Va zip_err\nfor any of the errors specified for the routine\n.Xr zip_fopen_index 3 .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fclose 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fread 3 ,\n.Xr zip_get_num_entries 3 ,\n.Xr zip_name_locate 3\n.Sh HISTORY\n.Fn zip_fopen_encrypted\nand\n.Fn zip_fopen_index_encrypted\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n.Sh CAVEATS\nThe zip file format provides very limited possibility for password\nverification (a short hash of is compared against one byte in the zip\narchive).\nFor this reason, reading a file while using an incorrect password may\nimmediately fail with\n.Er ZIP_ER_WRONGPASSWD ,\nbut if the mismatch is not detected, a zlib error may be returned\nlater instead.\nSince zlib errors can also be caused by broken compressed data, there\nis no way to make sure if the password was incorrect or if it was\ncorrect, but the compressed data was invalid.\n"
  },
  {
    "path": "external/libzip/man/zip_fread.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fread.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fread.mdoc -- read from file\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FREAD\" \"3\" \"September 11, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fread\\fR\n\\- read from file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fread\\fR(\\fIzip_file_t\\ *file\\fR, \\fIvoid\\ *buf\\fR, \\fIzip_uint64_t\\ nbytes\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_fread\\fR()\nfunction reads up to\n\\fInbytes\\fR\nbytes from\n\\fIfile\\fR\ninto\n\\fIbuf\\fR\nfrom the current position in the file (see\nzip_fseek(3)).\nAfter reading, the current position is updated by the number of bytes read.\n.SH \"RETURN VALUES\"\nIf successful, the number of bytes actually read is returned.\nWhen\n\\fBzip_fread\\fR()\nis called after reaching the end of the file, 0 is returned.\nIn case of error, \\-1 is returned.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fclose(3),\nzip_file_get_error(3),\nzip_fopen(3),\nzip_fseek(3)\n.SH \"HISTORY\"\n\\fBzip_fread\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the return type was changed from\n\\fIssize_t\\fR\nto\n\\fIzip_int64_t\\fR.\nIn libzip 0.10 the type of\n\\fInbytes\\fR\nwas changed from\n\\fIsize_t\\fR\nto\n\\fIzip_uint64_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_fread.mdoc",
    "content": ".\\\" zip_fread.mdoc -- read from file\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 11, 2024\n.Dt ZIP_FREAD 3\n.Os\n.Sh NAME\n.Nm zip_fread\n.Nd read from file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_fread \"zip_file_t *file\" \"void *buf\" \"zip_uint64_t nbytes\"\n.Sh DESCRIPTION\nThe\n.Fn zip_fread\nfunction reads up to\n.Ar nbytes\nbytes from\n.Ar file\ninto\n.Ar buf\nfrom the current position in the file (see\n.Xr zip_fseek 3 ) .\nAfter reading, the current position is updated by the number of bytes read.\n.Sh RETURN VALUES\nIf successful, the number of bytes actually read is returned.\nWhen\n.Fn zip_fread\nis called after reaching the end of the file, 0 is returned.\nIn case of error, \\-1 is returned.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fclose 3 ,\n.Xr zip_file_get_error 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fseek 3\n.Sh HISTORY\n.Fn zip_fread\nwas added in libzip 0.6.\nIn libzip 0.10 the return type was changed from\n.Vt ssize_t\nto\n.Vt zip_int64_t .\nIn libzip 0.10 the type of\n.Ar nbytes\nwas changed from\n.Vt size_t\nto\n.Vt zip_uint64_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_fseek.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_fseek.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_fseek.mdoc -- seek in file\n.\\\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FSEEK\" \"3\" \"September 11, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_fseek\\fR,\n\\fBzip_file_is_seekable\\fR\n\\- seek in file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int8_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_fseek\\fR(\\fIzip_file_t\\ *file\\fR, \\fIzip_int64_t\\ offset\\fR, \\fIint\\ whence\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_file_is_seekable\\fR(\\fIzip_file_t\\ *file\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_fseek\\fR()\nfunction seeks to the specified\n\\fIoffset\\fR\nrelative to\n\\fIwhence\\fR,\njust like\nfseek(3).\n.PP\n\\fBzip_fseek\\fR\nonly works on uncompressed (stored), unencrypted data.\nWhen called on compressed or encrypted data it will return an error.\n.PP\nThe\n\\fBzip_file_is_seekable\\fR()\nfunction returns 1 if a file is seekable.\n.SH \"RETURN VALUES\"\nIf successful,\n\\fBzip_fseek\\fR()\nreturns 0.\nOtherwise, \\-1 is returned.\n.PP\n\\fBzip_file_is_seekable\\fR()\nreturns 1 if a file is seekable and 0 if not.\nOn an invalid argument, it returns \\-1.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fclose(3),\nzip_file_get_error(3),\nzip_fopen(3),\nzip_fread(3),\nzip_ftell(3)\n.SH \"HISTORY\"\n\\fBzip_fseek\\fR()\nwas added in libzip 1.2.0.\n\\fBzip_file_is_seekable\\fR()\nwas added in libzip 1.9.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_fseek.mdoc",
    "content": ".\\\" zip_fseek.mdoc -- seek in file\n.\\\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 11, 2024\n.Dt ZIP_FSEEK 3\n.Os\n.Sh NAME\n.Nm zip_fseek ,\n.Nm zip_file_is_seekable\n.Nd seek in file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int8_t\n.Fn zip_fseek \"zip_file_t *file\" \"zip_int64_t offset\" \"int whence\"\n.Ft int\n.Fn zip_file_is_seekable \"zip_file_t *file\"\n.Sh DESCRIPTION\nThe\n.Fn zip_fseek\nfunction seeks to the specified\n.Ar offset\nrelative to\n.Ar whence ,\njust like\n.Xr fseek 3 .\n.Pp\n.Nm\nonly works on uncompressed (stored), unencrypted data.\nWhen called on compressed or encrypted data it will return an error.\n.Pp\nThe\n.Fn zip_file_is_seekable\nfunction returns 1 if a file is seekable.\n.Sh RETURN VALUES\nIf successful,\n.Fn zip_fseek\nreturns 0.\nOtherwise, \\-1 is returned.\n.Pp\n.Fn zip_file_is_seekable\nreturns 1 if a file is seekable and 0 if not.\nOn an invalid argument, it returns \\-1.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fclose 3 ,\n.Xr zip_file_get_error 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fread 3 ,\n.Xr zip_ftell 3\n.Sh HISTORY\n.Fn zip_fseek\nwas added in libzip 1.2.0.\n.Fn zip_file_is_seekable\nwas added in libzip 1.9.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_ftell.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_ftell.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_ftell.mdoc -- tell position in file\n.\\\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_FTELL\" \"3\" \"September 11, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_ftell\\fR\n\\- tell position in file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_ftell\\fR(\\fIzip_file_t\\ *file\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_ftell\\fR()\nfunction reports the current offset in the file.\n.SH \"RETURN VALUES\"\nIf successful,\n\\fBzip_ftell\\fR\nreturns the current file position.\nOtherwise, \\-1 is returned.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fclose(3),\nzip_file_get_error(3),\nzip_fopen(3),\nzip_fread(3),\nzip_fseek(3)\n.SH \"HISTORY\"\n\\fBzip_ftell\\fR()\nwas added in libzip 1.2.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_ftell.mdoc",
    "content": ".\\\" zip_ftell.mdoc -- tell position in file\n.\\\" Copyright (C) 2016-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 11, 2024\n.Dt ZIP_FTELL 3\n.Os\n.Sh NAME\n.Nm zip_ftell\n.Nd tell position in file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_ftell \"zip_file_t *file\"\n.Sh DESCRIPTION\nThe\n.Fn zip_ftell\nfunction reports the current offset in the file.\n.Sh RETURN VALUES\nIf successful,\n.Nm\nreturns the current file position.\nOtherwise, \\-1 is returned.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fclose 3 ,\n.Xr zip_file_get_error 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fread 3 ,\n.Xr zip_fseek 3\n.Sh HISTORY\n.Fn zip_ftell\nwas added in libzip 1.2.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_archive_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_archive_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_archive_comment.mdoc -- get zip archive comment\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_ARCHIVE_COMMENT\" \"3\" \"September 22, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_archive_comment\\fR\n\\- get zip archive comment\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_archive_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIint\\ *lenp\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_archive_comment\\fR()\nfunction returns the comment for the entire zip archive.\nThe return value is in UTF-8 encoding unless\n\\fRZIP_FL_ENC_RAW\\fR\nwas specified (see below).\nThis pointer should not be modified or\nfree(3)'d,\nand becomes invalid when\n\\fIarchive\\fR\nis closed.\nIf\n\\fIlenp\\fR\nis not\n\\fRNULL\\fR,\nthe integer to which it points will be set to the length of the\ncomment.\nIf\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original unchanged comment is returned.\n.PP\nAdditionally, the following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 21n\n\\fRZIP_FL_ENC_RAW\\fR\nReturn the unmodified archive comment as it is in the ZIP archive.\n.TP 21n\n\\fRZIP_FL_ENC_GUESS\\fR\n(Default.)\nGuess the encoding of the archive comment in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.TP 21n\n\\fRZIP_FL_ENC_STRICT\\fR\nFollow the ZIP specification for file names and extend it to the\narchive comment, thus also expecting it in CP-437 encoding.\nConvert it to UTF-8.\n.RE\n\\fINote\\fR:\nASCII is a subset of both CP-437 and UTF-8.\n.SH \"RETURN VALUES\"\nUpon successful completion, a pointer to the comment is returned,\nor\n\\fRNULL\\fR\nif there is no comment.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_get_comment(3)\n.SH \"HISTORY\"\n\\fBzip_get_archive_comment\\fR()\nwas added in libzip 0.7.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_archive_comment.mdoc",
    "content": ".\\\" zip_get_archive_comment.mdoc -- get zip archive comment\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 22, 2020\n.Dt ZIP_GET_ARCHIVE_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_get_archive_comment\n.Nd get zip archive comment\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_get_archive_comment \"zip_t *archive\" \"int *lenp\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_archive_comment\nfunction returns the comment for the entire zip archive.\nThe return value is in UTF-8 encoding unless\n.Dv ZIP_FL_ENC_RAW\nwas specified (see below).\nThis pointer should not be modified or\n.Xr free 3 Ap d ,\nand becomes invalid when\n.Ar archive\nis closed.\nIf\n.Ar lenp\nis not\n.Dv NULL ,\nthe integer to which it points will be set to the length of the\ncomment.\nIf\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original unchanged comment is returned.\n.Pp\nAdditionally, the following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent\n.It Dv ZIP_FL_ENC_RAW\nReturn the unmodified archive comment as it is in the ZIP archive.\n.It Dv ZIP_FL_ENC_GUESS\n(Default.)\nGuess the encoding of the archive comment in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_STRICT\nFollow the ZIP specification for file names and extend it to the\narchive comment, thus also expecting it in CP-437 encoding.\nConvert it to UTF-8.\n.El\n.Em Note :\nASCII is a subset of both CP-437 and UTF-8.\n.Sh RETURN VALUES\nUpon successful completion, a pointer to the comment is returned,\nor\n.Dv NULL\nif there is no comment.\n.\\\" In case of an error,\n.\\\" .Dv NULL\n.\\\" is returned and the error code in\n.\\\" .Ar archive\n.\\\" is set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_get_comment 3\n.Sh HISTORY\n.Fn zip_get_archive_comment\nwas added in libzip 0.7.\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_archive_flag.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_archive_flag.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_archive_flag.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_ARCHIVE_FLAG\" \"3\" \"January 23, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_archive_flag\\fR\n\\- get status flags for zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_archive_flag\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_flags_t\\ flag\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_archive_flag\\fR()\nfunction returns if the flag\n\\fIflag\\fR\nis set for the archive\n\\fIarchive\\fR.\nThe archive flags might have been changed with\n\\fBzip_set_archive_flag\\fR();\nif\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original unchanged flags are tested.\n.PP\nSupported flags are:\n.TP 20n\n\\fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\\fR\nIf this flag is cleared, the archive file will be removed if the archive is empty.\nIf it is set, an empty archive will be created, which is not recommended by the zip specification.\nThis flag is always cleared unless explicitly set by the user with\nzip_set_archive_flag(3).\n.TP 20n\n\\fRZIP_AFL_IS_TORRENTZIP\\fR\nThe archive is in torrentzip format.\n.TP 20n\n\\fRZIP_AFL_RDONLY\\fR\nThe archive is read-only.\n.TP 20n\n\\fRZIP_AFL_WANT_TORRENTZIP\\fR\nIf the flag is set, the archive will be written in torrentzip format.\nThis flag is always cleared unless explicitly set by the user with\nzip_set_archive_flag(3).\n.SH \"RETURN VALUES\"\n\\fBzip_get_archive_flag\\fR()\nreturns 1 if\n\\fIflag\\fR\nis set for\n\\fIarchive\\fR,\n0 if not,\nand \\-1 if an error occurred.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_set_archive_flag(3)\n.SH \"HISTORY\"\n\\fBzip_get_archive_flag\\fR()\nwas added in libzip 0.9.\nIn libzip 0.11 the type of\n\\fIflag\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t m\\fR\nand the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n\\fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\\fR,\n\\fRZIP_AFL_IS_TORRENTZIP\\fR,\nand\n\\fRZIP_AFL_WANT_TORRENTZIP\\fR\nwere added in libzip 1.10.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_archive_flag.mdoc",
    "content": ".\\\" zip_get_archive_flag.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 23, 2023\n.Dt ZIP_GET_ARCHIVE_FLAG 3\n.Os\n.Sh NAME\n.Nm zip_get_archive_flag\n.Nd get status flags for zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_get_archive_flag \"zip_t *archive\" \"zip_flags_t flag\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_archive_flag\nfunction returns if the flag\n.Ar flag\nis set for the archive\n.Ar archive .\nThe archive flags might have been changed with\n.Fn zip_set_archive_flag ;\nif\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original unchanged flags are tested.\n.Pp\nSupported flags are:\n.Bl -tag -width XZIPXAFLXRDONLYXXX\n.It Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\nIf this flag is cleared, the archive file will be removed if the archive is empty.\nIf it is set, an empty archive will be created, which is not recommended by the zip specification.\nThis flag is always cleared unless explicitly set by the user with\n.Xr zip_set_archive_flag 3 .\n.It Dv ZIP_AFL_IS_TORRENTZIP\nThe archive is in torrentzip format.\n.It Dv ZIP_AFL_RDONLY\nThe archive is read-only.\n.It Dv ZIP_AFL_WANT_TORRENTZIP\nIf the flag is set, the archive will be written in torrentzip format.\nThis flag is always cleared unless explicitly set by the user with\n.Xr zip_set_archive_flag 3 .\n.El\n.Sh RETURN VALUES\n.Fn zip_get_archive_flag\nreturns 1 if\n.Ar flag\nis set for\n.Ar archive ,\n0 if not,\nand \\-1 if an error occurred.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_set_archive_flag 3\n.Sh HISTORY\n.Fn zip_get_archive_flag\nwas added in libzip 0.9.\nIn libzip 0.11 the type of\n.Ar flag\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t m\nand the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE ,\n.Dv ZIP_AFL_IS_TORRENTZIP ,\nand\n.Dv ZIP_AFL_WANT_TORRENTZIP\nwere added in libzip 1.10.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_error.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_error.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_error.mdoc -- get zip_error for archive\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_ERROR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_error\\fR\n\\- get zip error for archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_error_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_error\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_error\\fR()\nfunction returns the zip error for the zip archive\n\\fIarchive\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_system(3),\nzip_error_code_zip(3)\n.SH \"HISTORY\"\n\\fBzip_get_error\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_error.mdoc",
    "content": ".\\\" zip_get_error.mdoc -- get zip_error for archive\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_GET_ERROR 3\n.Os\n.Sh NAME\n.Nm zip_get_error\n.Nd get zip error for archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_error_t *\n.Fn zip_get_error \"zip_t *archive\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_error\nfunction returns the zip error for the zip archive\n.Ar archive .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_system 3 ,\n.Xr zip_error_code_zip 3\n.Sh HISTORY\n.Fn zip_get_error\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_file_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_file_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_file_comment.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_FILE_COMMENT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_file_comment\\fR\n\\- get comment for file in zip (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_file_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIint\\ *lenp\\fR, \\fIint\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_file_comment\\fR()\nfunction is the obsolete version of\nzip_file_get_comment(3).\nThe only differences are the types of the\n\\fIlenp\\fR\nand\n\\fIflags\\fR\narguments.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_get_comment(3)\n.SH \"HISTORY\"\n\\fBzip_get_file_comment\\fR()\nwas added in libzip 0.7.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_file_get_comment\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_file_comment.mdoc",
    "content": ".\\\" zip_get_file_comment.mdoc -- get comment for file in zip\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_GET_FILE_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_get_file_comment\n.Nd get comment for file in zip (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_get_file_comment \"zip_t *archive\" \"zip_uint64_t index\" \"int *lenp\" \"int flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_file_comment\nfunction is the obsolete version of\n.Xr zip_file_get_comment 3 .\nThe only differences are the types of the\n.Ar lenp\nand\n.Ar flags\narguments.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_get_comment 3\n.Sh HISTORY\n.Fn zip_get_file_comment\nwas added in libzip 0.7.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_file_get_comment\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_name.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_name.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_name.mdoc -- get name of file by index\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_NAME\" \"3\" \"September 22, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_name\\fR\n\\- get name of file by index\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_name\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_name\\fR()\nfunction returns the name of the file at position\n\\fIindex\\fR\nin\n\\fIarchive\\fR.\nThe name is in UTF-8 encoding unless\n\\fRZIP_FL_ENC_RAW\\fR\nwas specified (see below).\n.PP\nIf\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original unchanged filename is returned.\nThe returned string must not be modified or freed, and becomes invalid when\n\\fIarchive\\fR\nis closed.\n.PP\nAdditionally, the following\n\\fIflags\\fR\nare supported:\n.RS 6n\n.TP 21n\n\\fRZIP_FL_ENC_RAW\\fR\nReturn the unmodified names as it is in the ZIP archive.\n.TP 21n\n\\fRZIP_FL_ENC_GUESS\\fR\n(Default.)\nGuess the encoding of the name in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.TP 21n\n\\fRZIP_FL_ENC_STRICT\\fR\nFollow the ZIP specification and expect CP-437 encoded names in\nthe ZIP archive (except if they are explicitly marked as UTF-8).\nConvert it to UTF-8.\n.RE\n\\fINote\\fR:\nASCII is a subset of both CP-437 and UTF-8.\n.SH \"RETURN VALUES\"\nUpon successful completion, a pointer to the name is returned.\nOtherwise,\n\\fRNULL\\fR\nand the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_get_name\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_DELETED\\fR]\n\\fIindex\\fR\nrefers to a file that has been deleted\n(see\nzip_delete(3)).\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\nor\n\\fIindex\\fR\npoints to an added file and\n\\fRZIP_FL_UNCHANGED\\fR\nis set.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_name_locate(3)\n.SH \"HISTORY\"\n\\fBzip_get_name\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_name.mdoc",
    "content": ".\\\" zip_get_name.mdoc -- get name of file by index\n.\\\" Copyright (C) 2003-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 22, 2020\n.Dt ZIP_GET_NAME 3\n.Os\n.Sh NAME\n.Nm zip_get_name\n.Nd get name of file by index\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_get_name \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_name\nfunction returns the name of the file at position\n.Ar index\nin\n.Ar archive .\nThe name is in UTF-8 encoding unless\n.Dv ZIP_FL_ENC_RAW\nwas specified (see below).\n.Pp\nIf\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original unchanged filename is returned.\nThe returned string must not be modified or freed, and becomes invalid when\n.Ar archive\nis closed.\n.Pp\nAdditionally, the following\n.Ar flags\nare supported:\n.Bl -tag -width ZIP_FL_ENC_STRICTXX -offset indent\n.It Dv ZIP_FL_ENC_RAW\nReturn the unmodified names as it is in the ZIP archive.\n.It Dv ZIP_FL_ENC_GUESS\n(Default.)\nGuess the encoding of the name in the ZIP archive and convert it\nto UTF-8, if necessary.\n(Only CP-437 and UTF-8 are recognized.)\n.It Dv ZIP_FL_ENC_STRICT\nFollow the ZIP specification and expect CP-437 encoded names in\nthe ZIP archive (except if they are explicitly marked as UTF-8).\nConvert it to UTF-8.\n.El\n.Em Note :\nASCII is a subset of both CP-437 and UTF-8.\n.Sh RETURN VALUES\nUpon successful completion, a pointer to the name is returned.\nOtherwise,\n.Dv NULL\nand the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_get_name\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_DELETED\n.Ar index\nrefers to a file that has been deleted\n(see\n.Xr zip_delete 3 ) .\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive ,\nor\n.Ar index\npoints to an added file and\n.Dv ZIP_FL_UNCHANGED\nis set.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_name_locate 3\n.Sh HISTORY\n.Fn zip_get_name\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_num_entries.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_num_entries.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_num_entries.mdoc -- get number of files in archive\n.\\\" Copyright (C) 2011-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_NUM_ENTRIES\" \"3\" \"August 19, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_num_entries\\fR\n\\- get number of entries in archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_num_entries\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_get_num_entries\\fR()\nfunction returns the number of entries in\n\\fIarchive\\fR.\nEntries are all files that are present in the original archive or that\nwere added while the archive is open.\nThis includes deleted files, since\nindices are not renumbered until the archive is closed.\n(This allows one to refer to deleted files, e. g. to undelete them.)\n.PP\nIf\n\\fIflags\\fR\nis set to\n\\fRZIP_FL_UNCHANGED\\fR,\nthe original number of files is returned.\n.SH \"RETURN VALUES\"\n\\fBzip_get_num_entries\\fR()\nreturns the number of entries in the zip archive,\nor \\-1 if\n\\fIarchive\\fR\nis\n\\fRNULL\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fopen_index(3),\nzip_stat_index(3)\n.SH \"HISTORY\"\n\\fBzip_get_num_entries\\fR()\nwas added in libzip 0.10.\nIn libzip 0.11 the return type was changed from\n\\fIzip_uint64_t\\fR\nto\n\\fIzip_int64_t\\fR.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_num_entries.mdoc",
    "content": ".\\\" zip_get_num_entries.mdoc -- get number of files in archive\n.\\\" Copyright (C) 2011-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd August 19, 2022\n.Dt ZIP_GET_NUM_ENTRIES 3\n.Os\n.Sh NAME\n.Nm zip_get_num_entries\n.Nd get number of entries in archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_get_num_entries \"zip_t *archive\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_get_num_entries\nfunction returns the number of entries in\n.Ar archive .\nEntries are all files that are present in the original archive or that\nwere added while the archive is open.\nThis includes deleted files, since\nindices are not renumbered until the archive is closed.\n(This allows one to refer to deleted files, e. g. to undelete them.)\n.Pp\nIf\n.Ar flags\nis set to\n.Dv ZIP_FL_UNCHANGED ,\nthe original number of files is returned.\n.Sh RETURN VALUES\n.Fn zip_get_num_entries\nreturns the number of entries in the zip archive,\nor \\-1 if\n.Ar archive\nis\n.Dv NULL .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fopen_index 3 ,\n.Xr zip_stat_index 3\n.Sh HISTORY\n.Fn zip_get_num_entries\nwas added in libzip 0.10.\nIn libzip 0.11 the return type was changed from\n.Vt zip_uint64_t\nto\n.Vt zip_int64_t .\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_get_num_files.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_get_num_files.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_get_num_files.mdoc -- get number of files in archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_GET_NUM_FILES\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_get_num_files\\fR\n\\- get number of files in archive (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_get_num_files\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\n\\fIThis function is deprecated\\fR.\n\\fIUse\\fR\nzip_get_num_entries(3)\n\\fIinstead\\fR.\n.PP\nThe\n\\fBzip_get_num_files\\fR()\nfunction returns the number of files in\n\\fIarchive\\fR.\n.SH \"RETURN VALUES\"\n\\fBzip_get_num_files\\fR()\nreturns the number of files in the zip archive,\nor \\-1 if\n\\fIarchive\\fR\nis\n\\fRNULL\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fopen_index(3),\nzip_stat_index(3)\n.SH \"HISTORY\"\n\\fBzip_get_num_files\\fR()\nwas added in libzip 0.6.\nIt was deprecated in libzip 0.11, use\n\\fBzip_get_num_entries\\fR(\\fIinstead\\fR)\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_get_num_files.mdoc",
    "content": ".\\\" zip_get_num_files.mdoc -- get number of files in archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_GET_NUM_FILES 3\n.Os\n.Sh NAME\n.Nm zip_get_num_files\n.Nd get number of files in archive (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_get_num_files \"zip_t *archive\"\n.Sh DESCRIPTION\n.Em This function is deprecated .\n.Em Use\n.Xr zip_get_num_entries 3\n.Em instead .\n.Pp\nThe\n.Fn zip_get_num_files\nfunction returns the number of files in\n.Ar archive .\n.Sh RETURN VALUES\n.Fn zip_get_num_files\nreturns the number of files in the zip archive,\nor \\-1 if\n.Ar archive\nis\n.Dv NULL .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fopen_index 3 ,\n.Xr zip_stat_index 3\n.Sh HISTORY\n.Fn zip_get_num_files\nwas added in libzip 0.6.\nIt was deprecated in libzip 0.11, use\n.Fn zip_get_num_entries instead\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_libzip_version.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_libzip_version.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_libzip_version.mdoc -- return run-time version of library\n.\\\" Copyright (C) 2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_LIBZIP_VERSION\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_libzip_version\\fR\n\\- return run-time version of library\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIconst char *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_libzip_version\\fR(\\fIvoid\\fR);\n.PD\n.SH \"DESCRIPTION\"\n\\fBzip_libzip_version\\fR\nreturns the version number of the library as string in the format\n\\(lq$MAJOR.$MINOR.$MICRO$SUFFIX\\(rq\nwhere\n\\fI$MAJOR\\fR\nis the major version,\n\\fI$MINOR\\fR\nthe minor,\n\\fI$MICRO\\fR\nthe micro, and\n\\fI$SUFFIX\\fR\na suffix that's only set for development versions.\n.SH \"SEE ALSO\"\nlibzip(3)\n.SH \"HISTORY\"\n\\fBzip_libzip_version\\fR()\nwas added in libzip 1.3.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_libzip_version.mdoc",
    "content": ".\\\" zip_libzip_version.mdoc -- return run-time version of library\n.\\\" Copyright (C) 2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_LIBZIP_VERSION 3\n.Os\n.Sh NAME\n.Nm zip_libzip_version\n.Nd return run-time version of library\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft const char *\n.Fn zip_libzip_version void\n.Sh DESCRIPTION\n.Nm\nreturns the version number of the library as string in the format\n.Dq $MAJOR.$MINOR.$MICRO$SUFFIX\nwhere\n.Ar $MAJOR\nis the major version,\n.Ar $MINOR\nthe minor,\n.Ar $MICRO\nthe micro, and\n.Ar $SUFFIX\na suffix that's only set for development versions.\n.Sh SEE ALSO\n.Xr libzip 3\n.Sh HISTORY\n.Fn zip_libzip_version\nwas added in libzip 1.3.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_name_locate.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_name_locate.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_name_locate.mdoc -- get index of file by name\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_NAME_LOCATE\" \"3\" \"March 15, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_name_locate\\fR\n\\- get index of file by name\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_name_locate\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_flags_t\\ flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_name_locate\\fR()\nfunction returns the index of the file named\n\\fIfname\\fR\nin\n\\fIarchive\\fR.\nIf\n\\fIarchive\\fR\ndoes not contain a file with that name, \\-1 is returned.\n.PP\nIf neither\n\\fRZIP_FL_ENC_RAW\\fR\nnor\n\\fRZIP_FL_ENC_STRICT\\fR\nare specified, guess the encoding of the name in the ZIP archive and convert it\nto UTF-8, if necessary, before comparing.\n.PP\nIf neither\n\\fRZIP_FL_ENC_CP437\\fR\nnor\n\\fRZIP_FL_ENC_UTF_8\\fR\nare specified, guess the encoding of\n\\fIfname\\fR.\n.PP\nOnly CP-437 and UTF-8 are recognized.\n.PP\nThe\n\\fIflags\\fR\nare specified by\n\\fIor\\fR'ing\nthe following values, or 0 for none of them.\n.RS 6n\n.TP 19n\n\\fRZIP_FL_NOCASE\\fR\nIgnore case distinctions.\n(Will only work well if the file names are ASCII.)\nWith this flag,\n\\fBzip_name_locate\\fR()\nwill be slow for archives with many files.\n.TP 19n\n\\fRZIP_FL_NODIR\\fR\nIgnore directory part of file name in archive.\nWith this flag,\n\\fBzip_name_locate\\fR()\nwill be slow for archives with many files.\n.TP 19n\n\\fRZIP_FL_ENC_GUESS\\fR\nThis flag has no effect (its value is 0); it can be used to explicitly denote the absence of encoding flags.\n.TP 19n\n\\fRZIP_FL_ENC_RAW\\fR\nCompare\n\\fIfname\\fR\nagainst the unmodified names as they are in the ZIP archive, without converting them to UTF-8.\n.TP 19n\n\\fRZIP_FL_ENC_STRICT\\fR\nFollow the ZIP specification and expect CP-437 encoded names in\nthe ZIP archive (except if they are explicitly marked as UTF-8).\nConvert them to UTF-8 before comparing.\n.TP 19n\n\\fRZIP_FL_ENC_CP437\\fR\n\\fIfname\\fR\nis encoded as CP-437.\n.TP 19n\n\\fRZIP_FL_ENC_UTF_8\\fR\n\\fIfname\\fR\nis encoded as UTF-8.\n.RE\n.PP\n\\fINote\\fR:\nASCII is a subset of both CP-437 and UTF-8.\n.SH \"RETURN VALUES\"\n\\fBzip_name_locate\\fR()\nreturns the index of the file named\n\\fIfname\\fR\nor \\-1, if\n\\fIarchive\\fR\ndoes not contain an entry of that name.\n.SH \"ERRORS\"\n\\fBzip_name_locate\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nOne of the arguments is invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\nNo entry of the name\n\\fIfname\\fR\nis found in the archive.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_get_name(3)\n.SH \"HISTORY\"\n\\fBzip_name_locate\\fR()\nwas added in libzip 0.6.\nIn libzip 0.11 the return type was changed from\n\\fIint\\fR\nto\n\\fIzip_int64_t\\fR.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_name_locate.mdoc",
    "content": ".\\\" zip_name_locate.mdoc -- get index of file by name\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 15, 2022\n.Dt ZIP_NAME_LOCATE 3\n.Os\n.Sh NAME\n.Nm zip_name_locate\n.Nd get index of file by name\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_name_locate \"zip_t *archive\" \"const char *fname\" \"zip_flags_t flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_name_locate\nfunction returns the index of the file named\n.Ar fname\nin\n.Ar archive .\nIf\n.Ar archive\ndoes not contain a file with that name, \\-1 is returned.\n.Pp\nIf neither\n.Dv ZIP_FL_ENC_RAW\nnor\n.Dv ZIP_FL_ENC_STRICT\nare specified, guess the encoding of the name in the ZIP archive and convert it\nto UTF-8, if necessary, before comparing.\n.Pp\nIf neither\n.Dv ZIP_FL_ENC_CP437\nnor\n.Dv ZIP_FL_ENC_UTF_8\nare specified, guess the encoding of\n.Ar fname .\n.Pp\nOnly CP-437 and UTF-8 are recognized.\n.Pp\nThe\n.Fa flags\nare specified by\n.Em or Ns No 'ing\nthe following values, or 0 for none of them.\n.Bl -tag -offset indent -width ZIP_FL_ENC_STRICT\n.It Dv ZIP_FL_NOCASE\nIgnore case distinctions.\n(Will only work well if the file names are ASCII.)\nWith this flag,\n.Fn zip_name_locate\nwill be slow for archives with many files.\n.It Dv ZIP_FL_NODIR\nIgnore directory part of file name in archive.\nWith this flag,\n.Fn zip_name_locate\nwill be slow for archives with many files.\n.It Dv ZIP_FL_ENC_GUESS\nThis flag has no effect (its value is 0); it can be used to explicitly denote the absence of encoding flags.\n.It Dv ZIP_FL_ENC_RAW\nCompare\n.Ar fname\nagainst the unmodified names as they are in the ZIP archive, without converting them to UTF-8.\n.It Dv ZIP_FL_ENC_STRICT\nFollow the ZIP specification and expect CP-437 encoded names in\nthe ZIP archive (except if they are explicitly marked as UTF-8).\nConvert them to UTF-8 before comparing.\n.It Dv ZIP_FL_ENC_CP437\n.Ar fname\nis encoded as CP-437.\n.It Dv ZIP_FL_ENC_UTF_8\n.Ar fname\nis encoded as UTF-8.\n.El\n.Pp\n.Em Note :\nASCII is a subset of both CP-437 and UTF-8.\n.Sh RETURN VALUES\n.Fn zip_name_locate\nreturns the index of the file named\n.Ar fname\nor \\-1, if\n.Ar archive\ndoes not contain an entry of that name.\n.Sh ERRORS\n.Fn zip_name_locate\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\nOne of the arguments is invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOENT\nNo entry of the name\n.Ar fname\nis found in the archive.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_get_name 3\n.Sh HISTORY\n.Fn zip_name_locate\nwas added in libzip 0.6.\nIn libzip 0.11 the return type was changed from\n.Vt int\nto\n.Vt zip_int64_t .\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_open.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_open.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_open.mdoc -- open zip archive\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_OPEN\" \"3\" \"May 5, 2025\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_open\\fR,\n\\fBzip_open_from_source\\fR\n\\- open zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_open\\fR(\\fIconst\\ char\\ *path\\fR, \\fIint\\ flags\\fR, \\fIint\\ *errorp\\fR);\n.PD\n.PP\n\\fIzip_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_open_from_source\\fR(\\fIzip_source_t\\ *zs\\fR, \\fIint\\ flags\\fR, \\fIzip_error_t\\ *ze\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_open\\fR()\nfunction opens the zip archive specified by\n\\fIpath\\fR\nand returns a pointer to a\n\\fIstruct zip\\fR,\nused to manipulate the archive.\nThe\n\\fIflags\\fR\nare specified by\n\\fIor\\fR'ing\nthe following values, or 0 for none of them.\n.RS 6n\n.TP 15n\n\\fRZIP_CHECKCONS\\fR\nPerform additional stricter consistency checks on the archive, and\nerror if they fail.\n.TP 15n\n\\fRZIP_CREATE\\fR\nCreate the archive if it does not exist.\n.TP 15n\n\\fRZIP_EXCL\\fR\nError if archive already exists.\n.TP 15n\n\\fRZIP_TRUNCATE\\fR\nIf archive exists, ignore its current contents.\nIn other words, handle it the same way as an empty archive.\n.TP 15n\n\\fRZIP_RDONLY\\fR\nOpen archive in read-only mode.\n.RE\n.PP\nIf an error occurs and\n\\fIerrorp\\fR\nis\nnon-\\fRNULL\\fR,\nit will be set to the corresponding error code.\n.PP\nThe\n\\fBzip_open_from_source\\fR()\nfunction opens a zip archive encapsulated by the zip_source\n\\fIzs\\fR\nusing the provided\n\\fIflags\\fR.\nIn case of error, the zip_error\n\\fIze\\fR\nis filled in.\n.SH \"RETURN VALUES\"\nUpon successful completion\n\\fBzip_open\\fR()\nand\n\\fBzip_open_from_source\\fR()\nreturn a\n\\fIstruct zip\\fR\npointer.\nOtherwise,\n\\fRNULL\\fR\nis returned and\n\\fBzip_open\\fR()\nsets\n\\fI*errorp\\fR\nto indicate the error, while\n\\fBzip_open_from\\fR(\\fIsource\\fR)\nsets\n\\fIze\\fR\nto indicate the error.\n.SH \"EXAMPLES\"\nHere's an example of how you could report errors during\n\\fBzip_open\\fR:\n.nf\n.sp\n.RS 0n\n    zip_t *za;\n    int err;\n\n    if ((za = zip_open(name, 0, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\en\",\n\t        progname, name, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return -1;\n    }\n.RE\n.fi\n.SH \"ERRORS\"\nThe archive specified by\n\\fIpath\\fR\nis opened unless:\n.TP 19n\n[\\fRZIP_ER_EXISTS\\fR]\nThe file specified by\n\\fIpath\\fR\nexists and\n\\fRZIP_EXCL\\fR\nis set.\n.TP 19n\n[\\fRZIP_ER_INCONS\\fR]\nInconsistencies were found in the file specified by\n\\fIpath\\fR.\nThis error is often caused by specifying\n\\fRZIP_CHECKCONS\\fR\nbut can also happen without it.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nThe\n\\fIpath\\fR\nargument is\n\\fRNULL\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_NOENT\\fR]\nThe file specified by\n\\fIpath\\fR\ndoes not exist and\n\\fRZIP_CREATE\\fR\nis not set.\n.TP 19n\n[\\fRZIP_ER_NOZIP\\fR]\nThe file specified by\n\\fIpath\\fR\nis not a zip archive.\n.TP 19n\n[\\fRZIP_ER_OPEN\\fR]\nThe file specified by\n\\fIpath\\fR\ncould not be opened.\n.TP 19n\n[\\fRZIP_ER_READ\\fR]\nA read error occurred; see\n\\fIerrno\\fR\nfor details.\n.TP 19n\n[\\fRZIP_ER_SEEK\\fR]\nThe file specified by\n\\fIpath\\fR\ndoes not allow seeks.\n.PD 0\n.PP\nFor newly created archives,\n\\fBzip_open\\fR()\ndoes not try to create the file; this is done when calling\nzip_close(3)\nand any errors, like missing write permissions, will\nbe reported then.\n.PD\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3),\nzip_error_strerror(3),\nzip_fdopen(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_open\\fR()\nand\n\\fBzip_open_from_source\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_open.mdoc",
    "content": ".\\\" zip_open.mdoc -- open zip archive\n.\\\" Copyright (C) 2003-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt ZIP_OPEN 3\n.Os\n.Sh NAME\n.Nm zip_open ,\n.Nm zip_open_from_source\n.Nd open zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_t *\n.Fn zip_open \"const char *path\" \"int flags\" \"int *errorp\"\n.Ft zip_t *\n.Fn zip_open_from_source \"zip_source_t *zs\" \"int flags\" \"zip_error_t *ze\"\n.Sh DESCRIPTION\nThe\n.Fn zip_open\nfunction opens the zip archive specified by\n.Ar path\nand returns a pointer to a\n.Ft struct zip ,\nused to manipulate the archive.\nThe\n.Fa flags\nare specified by\n.Em or Ns No 'ing\nthe following values, or 0 for none of them.\n.Bl -tag -offset indent -width ZIP_CHECKCONS\n.It Dv ZIP_CHECKCONS\nPerform additional stricter consistency checks on the archive, and\nerror if they fail.\n.It Dv ZIP_CREATE\nCreate the archive if it does not exist.\n.It Dv ZIP_EXCL\nError if archive already exists.\n.It Dv ZIP_TRUNCATE\nIf archive exists, ignore its current contents.\nIn other words, handle it the same way as an empty archive.\n.It Dv ZIP_RDONLY\nOpen archive in read-only mode.\n.El\n.Pp\nIf an error occurs and\n.Ar errorp\nis\n.Pf non- Dv NULL ,\nit will be set to the corresponding error code.\n.Pp\nThe\n.Fn zip_open_from_source\nfunction opens a zip archive encapsulated by the zip_source\n.Fa zs\nusing the provided\n.Fa flags .\nIn case of error, the zip_error\n.Fa ze\nis filled in.\n.Sh RETURN VALUES\nUpon successful completion\n.Fn zip_open\nand\n.Fn zip_open_from_source\nreturn a\n.Ft struct zip\npointer.\nOtherwise,\n.Dv NULL\nis returned and\n.Fn zip_open\nsets\n.Ar *errorp\nto indicate the error, while\n.Fn zip_open_from source\nsets\n.Ar ze\nto indicate the error.\n.Sh EXAMPLES\nHere's an example of how you could report errors during\n.Nm :\n.Bd -literal\n    zip_t *za;\n    int err;\n\n    if ((za = zip_open(name, 0, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\en\",\n\t        progname, name, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return -1;\n    }\n.Ed\n.Sh ERRORS\nThe archive specified by\n.Ar path\nis opened unless:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_EXISTS\nThe file specified by\n.Ar path\nexists and\n.Dv ZIP_EXCL\nis set.\n.It Bq Er ZIP_ER_INCONS\nInconsistencies were found in the file specified by\n.Ar path .\nThis error is often caused by specifying\n.Dv ZIP_CHECKCONS\nbut can also happen without it.\n.It Bq Er ZIP_ER_INVAL\nThe\n.Ar path\nargument is\n.Dv NULL .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_NOENT\nThe file specified by\n.Ar path\ndoes not exist and\n.Dv ZIP_CREATE\nis not set.\n.It Bq Er ZIP_ER_NOZIP\nThe file specified by\n.Ar path\nis not a zip archive.\n.It Bq Er ZIP_ER_OPEN\nThe file specified by\n.Ar path\ncould not be opened.\n.It Bq Er ZIP_ER_READ\nA read error occurred; see\n.Va errno\nfor details.\n.It Bq Er ZIP_ER_SEEK\nThe file specified by\n.Ar path\ndoes not allow seeks.\n.El\nFor newly created archives,\n.Fn zip_open\ndoes not try to create the file; this is done when calling\n.Xr zip_close 3\nand any errors, like missing write permissions, will\nbe reported then.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3 ,\n.Xr zip_error_strerror 3 ,\n.Xr zip_fdopen 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_open\nand\n.Fn zip_open_from_source\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_register_cancel_callback_with_state.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_register_cancel_callback_with_state.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_register_cancel_callback_with_state.mdoc -- allow cancelling during zip_close\n.\\\" Copyright (C) 2021-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_REGISTER_CANCEL_CALLBACK_WITH_STATE\" \"3\" \"June 18, 2022\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_register_cancel_callback_with_state\\fR\n\\- allow cancelling during zip_close\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fItypedef int (*zip_cancel_callback)(zip_t *, void *);\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_register_cancel_callback_with_state\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_cancel_callback\\ callback\\fR, \\fIvoid\\ (*ud_free)(void\\ *)\\fR, \\fIvoid\\ *ud\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThis function can be used to cancel writing of a zip archive during\nzip_close(3).\n.PP\nThe\n\\fBzip_register_cancel_callback_with_state\\fR()\nfunction registers a callback function\n\\fIcallback\\fR\nfor the zip archive\n\\fIarchive\\fR.\nThe\n\\fIud_free\\fR\nfunction is called during cleanup for deleting the userdata supplied in\n\\fIud\\fR.\n.PP\nThe callback function is called during\nzip_close(3)\nin regular intervals (after every zip archive entry that's completely\nwritten to disk, and while writing data for entries) with zip archive\n\\fIarchive\\fR\nand the user-provided user-data\n\\fIud\\fR\nas arguments.\nWhen the callback function returns a non-zero value, writing is cancelled and\nzip_close(3)\nreturns an error.\n.PP\nThe callback function should be fast, since it will be called often.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3),\nzip_register_progress_callback_with_state(3)\n.SH \"HISTORY\"\n\\fBzip_register_cancel_callback_with_state\\fR()\nwas added in libzip 1.6.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_register_cancel_callback_with_state.mdoc",
    "content": ".\\\" zip_register_cancel_callback_with_state.mdoc -- allow cancelling during zip_close\n.\\\" Copyright (C) 2021-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 18, 2022\n.Dt ZIP_REGISTER_CANCEL_CALLBACK_WITH_STATE 3\n.Os\n.Sh NAME\n.Nm zip_register_cancel_callback_with_state\n.Nd allow cancelling during zip_close\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt typedef int (*zip_cancel_callback)(zip_t *, void *);\n.Ft void\n.Fn zip_register_cancel_callback_with_state \"zip_t *archive\" \"zip_cancel_callback callback\" \"void (*ud_free)(void *)\" \"void *ud\"\n.Sh DESCRIPTION\nThis function can be used to cancel writing of a zip archive during\n.Xr zip_close 3 .\n.Pp\nThe\n.Fn zip_register_cancel_callback_with_state\nfunction registers a callback function\n.Ar callback\nfor the zip archive\n.Ar archive .\nThe\n.Ar ud_free\nfunction is called during cleanup for deleting the userdata supplied in\n.Ar ud .\n.Pp\nThe callback function is called during\n.Xr zip_close 3\nin regular intervals (after every zip archive entry that's completely\nwritten to disk, and while writing data for entries) with zip archive\n.Ar archive\nand the user-provided user-data\n.Ar ud\nas arguments.\nWhen the callback function returns a non-zero value, writing is cancelled and\n.Xr zip_close 3\nreturns an error.\n.Pp\nThe callback function should be fast, since it will be called often.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3 ,\n.Xr zip_register_progress_callback_with_state 3\n.Sh HISTORY\n.Fn zip_register_cancel_callback_with_state\nwas added in libzip 1.6.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_register_progress_callback.mdoc -- provide updates during zip_close\n.\\\" Copyright (C) 2016-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_REGISTER_PROGRESS_CALLBACK\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_register_progress_callback\\fR\n\\- provide updates during zip_close (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fItypedef void (*zip_progress_callback_t)(double);\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_register_progress_callback\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_progress_callback_t\\ progress_callback\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_register_progress_callback\\fR()\nis the obsolete version of\nzip_register_progress_callback_with_state(3).\n.PP\nThe\n\\fBzip_register_progress_callback\\fR()\nfunction registers a callback function\n\\fIprogress_callback\\fR\nfor the zip archive\n\\fIarchive\\fR.\nThis function is called during\nzip_close(3)\nafter every zip archive entry that's completely written to disk.\nThe value is a\n\\fIdouble\\fR\nin the range from 0.0 to 1.0.\nThis can be used to provide progress indicators for user interfaces.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3)\n.SH \"HISTORY\"\n\\fBzip_register_progress_callback\\fR()\nwas added in libzip 1.2.0.\nIt was deprecated in libzip 1.3.0, use\n\\fBzip_register_progress_callback_with_state\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback.mdoc",
    "content": ".\\\" zip_register_progress_callback.mdoc -- provide updates during zip_close\n.\\\" Copyright (C) 2016-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_REGISTER_PROGRESS_CALLBACK 3\n.Os\n.Sh NAME\n.Nm zip_register_progress_callback\n.Nd provide updates during zip_close (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt typedef void (*zip_progress_callback_t)(double);\n.Ft void\n.Fn zip_register_progress_callback \"zip_t *archive\" \"zip_progress_callback_t progress_callback\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_register_progress_callback\nis the obsolete version of\n.Xr zip_register_progress_callback_with_state 3 .\n.Pp\nThe\n.Fn zip_register_progress_callback\nfunction registers a callback function\n.Ar progress_callback\nfor the zip archive\n.Ar archive .\nThis function is called during\n.Xr zip_close 3\nafter every zip archive entry that's completely written to disk.\nThe value is a\n.Vt double\nin the range from 0.0 to 1.0.\nThis can be used to provide progress indicators for user interfaces.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3\n.Sh HISTORY\n.Fn zip_register_progress_callback\nwas added in libzip 1.2.0.\nIt was deprecated in libzip 1.3.0, use\n.Fn zip_register_progress_callback_with_state\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback_with_state.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback_with_state.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_register_progress_callback_with_state.mdoc -- provide updates during zip_close\n.\\\" Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_REGISTER_PROGRESS_CALLBACK_WITH_STATE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_register_progress_callback_with_state\\fR\n\\- provide updates during zip_close\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fItypedef void (*zip_progress_callback)(zip_t *, double, void *);\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_register_progress_callback_with_state\\fR(\\fIzip_t\\ *archive\\fR, \\fIdouble\\ precision\\fR, \\fIzip_progress_callback\\ callback\\fR, \\fIvoid\\ (*ud_free)(void\\ *)\\fR, \\fIvoid\\ *ud\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_register_progress_callback_with_state\\fR()\nfunction registers a callback function\n\\fIcallback\\fR\nfor the zip archive\n\\fIarchive\\fR.\nThe\n\\fIprecision\\fR\nargument is a double in the range from 0.00 to 1.0 that defines the\nsmallest change for which the callback should be called (to avoid too\nfrequent calls).\nThe\n\\fIud_free\\fR\nfunction is called during cleanup for deleting the userdata supplied in\n\\fIud\\fR.\n.PP\nThe callback function is called during\nzip_close(3)\nin regular intervals (after every zip archive entry that's completely\nwritten to disk, and while writing data for entries) with zip archive\n\\fIarchive\\fR,\nthe current progression state as a\n\\fIdouble\\fR,\nand the user-provided user-data\n\\fIud\\fR\nas arguments.\nThe progression state is a\n\\fIdouble\\fR\nin the range from 0.0 to 1.0.\nThis can be used to provide progress indicators for user interfaces.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_close(3),\nzip_register_cancel_callback_with_state(3)\n.SH \"HISTORY\"\n\\fBzip_register_progress_callback_with_state\\fR()\nwas added in libzip 1.3.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_register_progress_callback_with_state.mdoc",
    "content": ".\\\" zip_register_progress_callback_with_state.mdoc -- provide updates during zip_close\n.\\\" Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_REGISTER_PROGRESS_CALLBACK_WITH_STATE 3\n.Os\n.Sh NAME\n.Nm zip_register_progress_callback_with_state\n.Nd provide updates during zip_close\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt typedef void (*zip_progress_callback)(zip_t *, double, void *);\n.Ft void\n.Fn zip_register_progress_callback_with_state \"zip_t *archive\" \"double precision\" \"zip_progress_callback callback\" \"void (*ud_free)(void *)\" \"void *ud\"\n.Sh DESCRIPTION\nThe\n.Fn zip_register_progress_callback_with_state\nfunction registers a callback function\n.Ar callback\nfor the zip archive\n.Ar archive .\nThe\n.Ar precision\nargument is a double in the range from 0.00 to 1.0 that defines the\nsmallest change for which the callback should be called (to avoid too\nfrequent calls).\nThe\n.Ar ud_free\nfunction is called during cleanup for deleting the userdata supplied in\n.Ar ud .\n.Pp\nThe callback function is called during\n.Xr zip_close 3\nin regular intervals (after every zip archive entry that's completely\nwritten to disk, and while writing data for entries) with zip archive\n.Ar archive ,\nthe current progression state as a\n.Vt double ,\nand the user-provided user-data\n.Ar ud\nas arguments.\nThe progression state is a\n.Vt double\nin the range from 0.0 to 1.0.\nThis can be used to provide progress indicators for user interfaces.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_close 3 ,\n.Xr zip_register_cancel_callback_with_state 3\n.Sh HISTORY\n.Fn zip_register_progress_callback_with_state\nwas added in libzip 1.3.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_rename.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_rename.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_rename.mdoc -- rename file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_RENAME\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_rename\\fR\n\\- rename file in zip archive (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_rename\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIconst\\ char\\ *name\\fR);\n.PD\n.SH \"DESCRIPTION\"\n\\fBzip_rename\\fR()\nis the obsolete version of\nzip_file_rename(3).\nIt is the same as calling\nzip_file_rename(3)\nwith an empty flags argument.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_rename(3)\n.SH \"HISTORY\"\n\\fBzip_rename\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_file_rename\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_rename.mdoc",
    "content": ".\\\" zip_rename.mdoc -- rename file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_RENAME 3\n.Os\n.Sh NAME\n.Nm zip_rename\n.Nd rename file in zip archive (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_rename \"zip_t *archive\" \"zip_uint64_t index\" \"const char *name\"\n.Sh DESCRIPTION\n.Fn zip_rename\nis the obsolete version of\n.Xr zip_file_rename 3 .\nIt is the same as calling\n.Xr zip_file_rename 3\nwith an empty flags argument.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_rename 3\n.Sh HISTORY\n.Fn zip_rename\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_file_rename\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_set_archive_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_set_archive_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_set_archive_comment.mdoc -- set zip archive comment\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SET_ARCHIVE_COMMENT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_set_archive_comment\\fR\n\\- set zip archive comment\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_set_archive_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *comment\\fR, \\fIzip_uint16_t\\ len\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_set_archive_comment\\fR()\nfunction sets the comment for the entire zip archive.\nIf\n\\fIcomment\\fR\nis\n\\fRNULL\\fR\nand\n\\fIlen\\fR\nis 0, the archive comment will be removed.\n\\fIcomment\\fR\nmust be encoded in ASCII or UTF-8.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_set_archive_comment\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIlen\\fR\nis less than 0 or longer than the maximum comment length in a zip file\n(65535), or\n\\fIcomment\\fR\nis not a valid UTF-8 encoded string.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_get_comment(3),\nzip_file_set_comment(3),\nzip_get_archive_comment(3)\n.SH \"HISTORY\"\n\\fBzip_set_archive_comment\\fR()\nwas added in libzip 0.7.\nIn libzip 0.11 the type of\n\\fIlen\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint16_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_set_archive_comment.mdoc",
    "content": ".\\\" zip_set_archive_comment.mdoc -- set zip archive comment\n.\\\" Copyright (C) 2006-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SET_ARCHIVE_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_set_archive_comment\n.Nd set zip archive comment\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_set_archive_comment \"zip_t *archive\" \"const char *comment\" \"zip_uint16_t len\"\n.Sh DESCRIPTION\nThe\n.Fn zip_set_archive_comment\nfunction sets the comment for the entire zip archive.\nIf\n.Ar comment\nis\n.Dv NULL\nand\n.Ar len\nis 0, the archive comment will be removed.\n.Ar comment\nmust be encoded in ASCII or UTF-8.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_set_archive_comment\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar len\nis less than 0 or longer than the maximum comment length in a zip file\n(65535), or\n.Ar comment\nis not a valid UTF-8 encoded string.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_get_comment 3 ,\n.Xr zip_file_set_comment 3 ,\n.Xr zip_get_archive_comment 3\n.Sh HISTORY\n.Fn zip_set_archive_comment\nwas added in libzip 0.7.\nIn libzip 0.11 the type of\n.Ar len\nwas changed from\n.Vt int\nto\n.Vt zip_uint16_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_set_archive_flag.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_set_archive_flag.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_set_archive_flag.mdoc -- set zip archive flag\n.\\\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SET_ARCHIVE_FLAG\" \"3\" \"July 19, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_set_archive_flag\\fR\n\\- set zip archive flag\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_set_archive_flag\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_flags_t\\ flag\\fR, \\fIint\\ value\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_set_archive_flag\\fR()\nfunction sets the flag\n\\fIflag\\fR\nfor the archive\n\\fIarchive\\fR\nto the value\n\\fIvalue\\fR.\n.PP\nSupported flags are:\n.TP 20n\n\\fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\\fR\nIf this flag is cleared, the archive file will be removed if the archive is empty.\nIf it is set, an empty archive will be created, which is not recommended by the zip specification.\n.TP 20n\n\\fRZIP_AFL_RDONLY\\fR\nIf this flag is set, no modification to the archive are allowed.\nThis flag can only be cleared if it was manually set with\n\\fBzip_set_archive_flag\\fR,\nnot if the archive was opened read-only.\n.TP 20n\n\\fRZIP_AFL_WANT_TORRENTZIP\\fR\nIf this flag is set, the archive will be written in torrentzip format.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned, and \\-1 if an error\noccurred.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_get_archive_flag(3)\n.SH \"HISTORY\"\n\\fBzip_set_archive_flag\\fR()\nwas added in libzip 0.9.\nIn libzip 0.11 the type of\n\\fIflag\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n\\fRZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\\fR\nand\n\\fRZIP_AFL_WANT_TORRENTZIP\\fR\nwere added in libzip 1.10.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_set_archive_flag.mdoc",
    "content": ".\\\" zip_set_archive_flag.mdoc -- set zip archive flag\n.\\\" Copyright (C) 2008-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd July 19, 2023\n.Dt ZIP_SET_ARCHIVE_FLAG 3\n.Os\n.Sh NAME\n.Nm zip_set_archive_flag\n.Nd set zip archive flag\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_set_archive_flag \"zip_t *archive\" \"zip_flags_t flag\" \"int value\"\n.Sh DESCRIPTION\nThe\n.Fn zip_set_archive_flag\nfunction sets the flag\n.Ar flag\nfor the archive\n.Ar archive\nto the value\n.Ar value .\n.Pp\nSupported flags are:\n.Bl -tag -width XZIPXAFLXRDONLYXXX\n.It Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\nIf this flag is cleared, the archive file will be removed if the archive is empty.\nIf it is set, an empty archive will be created, which is not recommended by the zip specification.\n.It Dv ZIP_AFL_RDONLY\nIf this flag is set, no modification to the archive are allowed.\nThis flag can only be cleared if it was manually set with\n.Nm ,\nnot if the archive was opened read-only.\n.It Dv ZIP_AFL_WANT_TORRENTZIP\nIf this flag is set, the archive will be written in torrentzip format.\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned, and \\-1 if an error\noccurred.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_get_archive_flag 3\n.Sh HISTORY\n.Fn zip_set_archive_flag\nwas added in libzip 0.9.\nIn libzip 0.11 the type of\n.Ar flag\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Dv ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE\nand\n.Dv ZIP_AFL_WANT_TORRENTZIP\nwere added in libzip 1.10.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_set_default_password.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_set_default_password.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_set_default_password.mdoc -- set default password for zip\n.\\\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SET_DEFAULT_PASSWORD\" \"3\" \"September 15, 2020\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_set_default_password\\fR\n\\- set default password for encrypted files in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_set_default_password\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *password\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_set_default_password\\fR()\nfunction sets the default password used when accessing encrypted files.\nIf\n\\fIpassword\\fR\nis\n\\fRNULL\\fR\nor the empty string, the default password is unset.\n.PP\nIf you prefer a different password for single files, use\nzip_fopen_encrypted(3)\ninstead of\nzip_fopen(3).\nUsually, however, the same password is used for every file in an\nzip archive.\n.PP\nThe password is not verified when calling this function.\nSee the\n\\fICAVEATS\\fR\nsection in\nzip_fopen_encrypted(3)\nfor more details about password handling.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_set_default_password\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_fopen(3),\nzip_fopen_encrypted(3)\n.SH \"HISTORY\"\n\\fBzip_set_default_password\\fR()\nwas added in libzip 0.10.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_set_default_password.mdoc",
    "content": ".\\\" zip_set_default_password.mdoc -- set default password for zip\n.\\\" Copyright (C) 2011-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 15, 2020\n.Dt ZIP_SET_DEFAULT_PASSWORD 3\n.Os\n.Sh NAME\n.Nm zip_set_default_password\n.Nd set default password for encrypted files in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_set_default_password \"zip_t *archive\" \"const char *password\"\n.Sh DESCRIPTION\nThe\n.Fn zip_set_default_password\nfunction sets the default password used when accessing encrypted files.\nIf\n.Ar password\nis\n.Dv NULL\nor the empty string, the default password is unset.\n.Pp\nIf you prefer a different password for single files, use\n.Xr zip_fopen_encrypted 3\ninstead of\n.Xr zip_fopen 3 .\nUsually, however, the same password is used for every file in an\nzip archive.\n.Pp\nThe password is not verified when calling this function.\nSee the\n.Sx CAVEATS\nsection in\n.Xr zip_fopen_encrypted 3\nfor more details about password handling.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_set_default_password\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_fopen 3 ,\n.Xr zip_fopen_encrypted 3\n.Sh HISTORY\n.Fn zip_set_default_password\nwas added in libzip 0.10.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_set_file_comment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_set_file_comment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_set_file_comment.mdoc -- set comment for file in zip\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SET_FILE_COMMENT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_set_file_comment\\fR\n\\- set comment for file in zip (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_set_file_comment\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIconst\\ char\\ *comment\\fR, \\fIint\\ len\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_set_file_comment\\fR()\nfunction is the obsolete version of\nzip_file_set_comment(3).\nThe only differences are the type of the\n\\fIlen\\fR\nargument and the additional\n\\fIflags\\fR\nargument.\n\\fBzip_set_file_comment\\fR()\nis the same as calling\nzip_file_set_comment(3)\nwith an empty\n\\fIflags\\fR\nargument.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_set_comment(3)\n.SH \"HISTORY\"\n\\fBzip_set_file_comment\\fR()\nwas added in libzip 0.7.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIt was deprecated in libzip 0.11, use\n\\fBzip_file_set_comment\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_set_file_comment.mdoc",
    "content": ".\\\" zip_set_file_comment.mdoc -- set comment for file in zip\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SET_FILE_COMMENT 3\n.Os\n.Sh NAME\n.Nm zip_set_file_comment\n.Nd set comment for file in zip (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_set_file_comment \"zip_t *archive\" \"zip_uint64_t index\" \"const char *comment\" \"int len\"\n.Sh DESCRIPTION\nThe\n.Fn zip_set_file_comment\nfunction is the obsolete version of\n.Xr zip_file_set_comment 3 .\nThe only differences are the type of the\n.Ar len\nargument and the additional\n.Ar flags\nargument.\n.Fn zip_set_file_comment\nis the same as calling\n.Xr zip_file_set_comment 3\nwith an empty\n.Ar flags\nargument.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_set_comment 3\n.Sh HISTORY\n.Fn zip_set_file_comment\nwas added in libzip 0.7.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIt was deprecated in libzip 0.11, use\n.Fn zip_file_set_comment\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_set_file_compression.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_set_file_compression.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_set_file_compression.mdoc -- set compression method and its flags\n.\\\" Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SET_FILE_COMPRESSION\" \"3\" \"February 2, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_set_file_compression\\fR\n\\- set compression method for file in zip\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_set_file_compression\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_int32_t\\ comp\\fR, \\fIzip_uint32_t\\ comp_flags\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_set_file_compression\\fR()\nfunction sets the compression method for the file at position\n\\fIindex\\fR\nin the zip archive to\n\\fIcomp\\fR\nwith the compression method specific\n\\fIcomp_flags\\fR.\nThe\n\\fIcomp\\fR\nis the same as returned by\nzip_stat(3).\nFor the\n\\fIcomp\\fR\nargument, currently only the following values are supported:\n.TP 19n\n\\fRZIP_CM_DEFAULT\\fR\ndefault compression; currently the same as\n\\fRZIP_CM_DEFLATE\\fR,\nbut\n\\fIflags\\fR\nare ignored.\n.TP 19n\n\\fRZIP_CM_STORE\\fR\nStore the file uncompressed.\n.TP 19n\n\\fRZIP_CM_BZIP2\\fR\nCompress the file using the\nbzip2(1)\nalgorithm.\n.TP 19n\n\\fRZIP_CM_DEFLATE\\fR\nDeflate the file with the\nzlib(3)\nalgorithm and default options.\n.TP 19n\n\\fRZIP_CM_XZ\\fR\nUse the\nxz(1)\nalgorithm for compression\n.TP 19n\n\\fRZIP_CM_ZSTD\\fR\nUse the\nzstd(1)\nalgorithm for compression\n.PP\n\\fINOTE\\fR:\nOnly the deflate and store methods can be assumed to be universally\nsupported.\n.PP\nThe\n\\fIcomp_flags\\fR\nargument defines the compression level.\nThis value is dependent on the compression algorithm.\nIn general, lower numbers mean faster de/compression and higher\nnumbers mean slower de/compression.\nFor\n\\fRZIP_CM_BZIP\\fR,\n\\fRZIP_CM_DEFLATE\\fR,\nand\n\\fRZIP_CM_XZ\\fR\n1 is the fastest compression and 9 the best, 0 chooses the default.\nFor\n\\fRZIP_CM_ZSTD\\fR\npossible values are\nZSTD_minCLevel(3)\nto\nZSTD_maxCLevel(3); negative values must be cast to\n\\fIzip_uint32_t\\fR.\n.PP\nFurther compression method specific flags might be added over time.\n.PP\nThe current compression method for a file in a zip archive can be\ndetermined using\nzip_stat(3).\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_set_file_compression\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_COMPNOTSUPP\\fR]\nUnsupported compression method requested.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIarchive\\fR,\nor the argument combination is invalid.\n.TP 19n\n[\\fRZIP_ER_RDONLY\\fR]\nRead-only zip file, no changes allowed.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_compression_method_supported(3),\nzip_stat(3)\n.SH \"HISTORY\"\n\\fBzip_set_file_compression\\fR()\nwas added in libzip 0.11.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_set_file_compression.mdoc",
    "content": ".\\\" zip_set_file_compression.mdoc -- set compression method and its flags\n.\\\" Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP files.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd February 2, 2023\n.Dt ZIP_SET_FILE_COMPRESSION 3\n.Os\n.Sh NAME\n.Nm zip_set_file_compression\n.Nd set compression method for file in zip\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_set_file_compression \"zip_t *archive\" \"zip_uint64_t index\" \"zip_int32_t comp\" \"zip_uint32_t comp_flags\"\n.Sh DESCRIPTION\nThe\n.Fn zip_set_file_compression\nfunction sets the compression method for the file at position\n.Ar index\nin the zip archive to\n.Ar comp\nwith the compression method specific\n.Ar comp_flags .\nThe\n.Ar comp\nis the same as returned by\n.Xr zip_stat 3 .\nFor the\n.Ar comp\nargument, currently only the following values are supported:\n.Bl -tag -width ZIP_CM_DEFLATE_XX\n.It Dv ZIP_CM_DEFAULT\ndefault compression; currently the same as\n.Dv ZIP_CM_DEFLATE ,\nbut\n.Ar flags\nare ignored.\n.It Dv ZIP_CM_STORE\nStore the file uncompressed.\n.It Dv ZIP_CM_BZIP2\nCompress the file using the\n.Xr bzip2 1\nalgorithm.\n.It Dv ZIP_CM_DEFLATE\nDeflate the file with the\n.Xr zlib 3\nalgorithm and default options.\n.It Dv ZIP_CM_XZ\nUse the\n.Xr xz 1\nalgorithm for compression\n.It Dv ZIP_CM_ZSTD\nUse the\n.Xr zstd 1\nalgorithm for compression\n.El\n.Pp\n.Em NOTE :\nOnly the deflate and store methods can be assumed to be universally\nsupported.\n.Pp\nThe\n.Ar comp_flags\nargument defines the compression level.\nThis value is dependent on the compression algorithm.\nIn general, lower numbers mean faster de/compression and higher\nnumbers mean slower de/compression.\nFor\n.Dv ZIP_CM_BZIP ,\n.Dv ZIP_CM_DEFLATE ,\nand\n.Dv ZIP_CM_XZ\n1 is the fastest compression and 9 the best, 0 chooses the default.\nFor\n.Dv ZIP_CM_ZSTD\npossible values are\n.Xr ZSTD_minCLevel 3\nto\n.Xr ZSTD_maxCLevel 3 ; negative values must be cast to\n.Ft zip_uint32_t .\n.Pp\nFurther compression method specific flags might be added over time.\n.Pp\nThe current compression method for a file in a zip archive can be\ndetermined using\n.Xr zip_stat 3 .\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_set_file_compression\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_COMPNOTSUPP\nUnsupported compression method requested.\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar archive ,\nor the argument combination is invalid.\n.It Bq Er ZIP_ER_RDONLY\nRead-only zip file, no changes allowed.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_compression_method_supported 3 ,\n.Xr zip_stat 3\n.Sh HISTORY\n.Fn zip_set_file_compression\nwas added in libzip 0.11.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source.mdoc -- description of zip data source\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE\" \"5\" \"May 5, 2025\" \"NiH\" \"File Formats Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source\\fR\n\\- zip data source structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *source\\fR;\n.SH \"DESCRIPTION\"\nA\n\\fIzip_source_t\\fR\nrepresents a data source (or destination when used for writing).\nlibzip(3)\nuses it for adding or replacing file contents for a file in a zip archive.\nIf the source supports seeking, it can also be used to open zip archives from.\n.PP\nData can come from a file on disk\n(zip_source_file(3),\nzip_source_file_create(3),\nzip_source_filep(3),\nor\nzip_source_filep_create(3)),\nmemory\n(zip_source_buffer(3),\nzip_source_buffer_create(3),\nzip_source_buffer_fragment(3),\nor\nzip_source_buffer_fragment_create(3)),\na file inside an archive\n(zip_source_zip(3)),\nor provided via a callback function\n(zip_source_function(3)\nor\nzip_source_function_create(3)).\nzip_source_window(3)\nor\nzip_source_window_create(3)\ncan be used restrict access to a part of the contained data.\n.PP\nIt can also be used as a filter to process the data provided by an underlying\n\\fIzip_source_t\\fR\n(e.g., to compress it or compute a checksum), created with\nzip_source_layered(3)\nor\nzip_source_layered_create(3)).\n.PP\nSources are freed with\nzip_source_free(3).\n.PP\nSources must support reading, and can optionally support seeking and\nwriting.\n.PP\n\\fIzip_source_t\\fR\nis reference counted, and created with a reference count of 1.\nzip_open_from_source(3),\nzip_file_add(3),\nand\nzip_file_replace(3)\nwill take ownership of the passed source (decrement the reference count when they are done using it), so\nzip_source_free(3)\nonly needs to be called when these functions return an error.\nThe underlying data (file or buffer) must remain valid until the archive is closed.\nUse\nzip_source_keep(3)\nto increase the reference count, for example if you need the source after\nzip_close(3).\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source_buffer(3),\nzip_source_file(3),\nzip_source_filep(3),\nzip_source_free(3),\nzip_source_function(3),\nzip_source_keep(3),\nzip_source_window(3),\nzip_source_zip(3)\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source.mdoc",
    "content": ".\\\" zip_source.mdoc -- description of zip data source\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 5, 2025\n.Dt ZIP_SOURCE 5\n.Os\n.Sh NAME\n.Nm zip_source\n.Nd zip data source structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Vt zip_source_t *source ;\n.Sh DESCRIPTION\nA\n.Vt zip_source_t\nrepresents a data source (or destination when used for writing).\n.Xr libzip 3\nuses it for adding or replacing file contents for a file in a zip archive.\nIf the source supports seeking, it can also be used to open zip archives from.\n.Pp\nData can come from a file on disk\n.Xr ( zip_source_file 3 ,\n.Xr zip_source_file_create 3 ,\n.Xr zip_source_filep 3 ,\nor\n.Xr zip_source_filep_create 3 ) ,\nmemory\n.Xr ( zip_source_buffer 3 ,\n.Xr zip_source_buffer_create 3 ,\n.Xr zip_source_buffer_fragment 3 ,\nor\n.Xr zip_source_buffer_fragment_create 3 ) ,\na file inside an archive\n.Xr ( zip_source_zip 3 ) ,\nor provided via a callback function\n.Xr ( zip_source_function 3\nor\n.Xr zip_source_function_create 3 ) .\n.Xr zip_source_window 3\nor\n.Xr zip_source_window_create 3\ncan be used restrict access to a part of the contained data.\n.Pp\nIt can also be used as a filter to process the data provided by an underlying\n.Vt zip_source_t\n(e.g., to compress it or compute a checksum), created with\n.Xr zip_source_layered 3\nor\n.Xr zip_source_layered_create 3 ) .\n.Pp\nSources are freed with\n.Xr zip_source_free 3 .\n.Pp\nSources must support reading, and can optionally support seeking and\nwriting.\n.Pp\n.Vt zip_source_t\nis reference counted, and created with a reference count of 1.\n.Xr zip_open_from_source 3 ,\n.Xr zip_file_add 3 ,\nand\n.Xr zip_file_replace 3\nwill take ownership of the passed source (decrement the reference count when they are done using it), so\n.Xr zip_source_free 3\nonly needs to be called when these functions return an error.\nThe underlying data (file or buffer) must remain valid until the archive is closed.\nUse\n.Xr zip_source_keep 3\nto increase the reference count, for example if you need the source after\n.Xr zip_close 3 .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source_buffer 3 ,\n.Xr zip_source_file 3 ,\n.Xr zip_source_filep 3 ,\n.Xr zip_source_free 3 ,\n.Xr zip_source_function 3 ,\n.Xr zip_source_keep 3 ,\n.Xr zip_source_window 3 ,\n.Xr zip_source_zip 3\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_begin_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_begin_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_begin_write.mdoc -- prepare zip source for writing\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_BEGIN_WRITE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_begin_write\\fR,\n\\fBzip_source_begin_write_cloning\\fR\n\\- prepare zip source for writing\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_begin_write\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_begin_write_cloning\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_uint64_t\\ offset\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_begin_write\\fR()\nand\n\\fBzip_source_begin_write_cloning\\fR()\nprepare\n\\fIsource\\fR\nfor writing.\nUsually this involves creating temporary files or allocating buffers.\n.PP\n\\fBzip_source_begin_write_cloning\\fR()\npreserves the first\n\\fIoffset\\fR\nbytes of the original file.\nThis is done efficiently, and writes to\n\\fIsource\\fR\nwon't overwrite the original data until\n\\fBzip_commit_write\\fR()\nis called.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_commit_write(3),\nzip_source_rollback_write(3),\nzip_source_seek_write(3),\nzip_source_tell_write(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_begin_write\\fR()\nwas added in libzip 1.0.\n.PP\n\\fBzip_source_begin_write_cloning\\fR()\nwas added in libzip 1.4.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_begin_write.mdoc",
    "content": ".\\\" zip_source_begin_write.mdoc -- prepare zip source for writing\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_BEGIN_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_begin_write ,\n.Nm zip_source_begin_write_cloning\n.Nd prepare zip source for writing\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_begin_write \"zip_source_t *source\"\n.Ft int\n.Fn zip_source_begin_write_cloning \"zip_source_t *source\" \"zip_uint64_t offset\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_begin_write\nand\n.Fn zip_source_begin_write_cloning\nprepare\n.Fa source\nfor writing.\nUsually this involves creating temporary files or allocating buffers.\n.Pp\n.Fn zip_source_begin_write_cloning\npreserves the first\n.Ar offset\nbytes of the original file.\nThis is done efficiently, and writes to\n.Ar source\nwon't overwrite the original data until\n.Fn zip_commit_write\nis called.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_commit_write 3 ,\n.Xr zip_source_rollback_write 3 ,\n.Xr zip_source_seek_write 3 ,\n.Xr zip_source_tell_write 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_begin_write\nwas added in libzip 1.0.\n.Pp\n.Fn zip_source_begin_write_cloning\nwas added in libzip 1.4.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_buffer.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_buffer.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_buffer.mdoc -- create zip data source from buffer\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_BUFFER\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_buffer\\fR,\n\\fBzip_source_buffer_create\\fR\n\\- create zip data source from buffer\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_buffer\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ void\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR, \\fIint\\ freep\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_buffer_create\\fR(\\fIconst\\ void\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR, \\fIint\\ freep\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_buffer\\fR()\nand\n\\fBzip_source_buffer_create\\fR()\ncreate a zip source from the buffer\n\\fIdata\\fR\nof size\n\\fIlen\\fR.\nIf\n\\fIfreep\\fR\nis non-zero, the buffer will be freed when it is no longer needed.\n\\fIdata\\fR\nmust remain valid for the lifetime of the created source.\n.PP\nThe source can be used to open a zip archive from.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_buffer\\fR()\nand\n\\fBzip_source_buffer_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIlen\\fR\nis greater than zero and\n\\fIdata\\fR\nis\n\\fRNULL\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_open_from_source(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_buffer\\fR()\nand\n\\fBzip_source_buffer_create\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_buffer.mdoc",
    "content": ".\\\" zip_source_buffer.mdoc -- create zip data source from buffer\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_BUFFER 3\n.Os\n.Sh NAME\n.Nm zip_source_buffer ,\n.Nm zip_source_buffer_create\n.Nd create zip data source from buffer\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_buffer \"zip_t *archive\" \"const void *data\" \"zip_uint64_t len\" \"int freep\"\n.Ft zip_source_t *\n.Fn zip_source_buffer_create \"const void *data\" \"zip_uint64_t len\" \"int freep\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_buffer\nand\n.Fn zip_source_buffer_create\ncreate a zip source from the buffer\n.Ar data\nof size\n.Ar len .\nIf\n.Ar freep\nis non-zero, the buffer will be freed when it is no longer needed.\n.Ar data\nmust remain valid for the lifetime of the created source.\n.Pp\nThe source can be used to open a zip archive from.\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_buffer\nand\n.Fn zip_source_buffer_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar len\nis greater than zero and\n.Ar data\nis\n.Dv NULL .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_open_from_source 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_buffer\nand\n.Fn zip_source_buffer_create\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_buffer_fragment.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_buffer_fragment.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_buffer_fragment.mdoc -- create zip data source from multiple buffers\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_BUFFER_FRAGMENT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_buffer_fragment\\fR,\n\\fBzip_source_buffer_fragment_create\\fR\n\\- create zip data source from multiple buffer\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_buffer_fragment\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_buffer_fragment_t\\ *fragments\\fR, \\fIzip_uint64_t\\ nfragments\\fR, \\fIint\\ freep\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_buffer_fragment_create\\fR(\\fIzip_buffer_fragment_t\\ *fragments\\fR, \\fIzip_uint64_t\\ nfragments\\fR, \\fIint\\ freep\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_buffer_fragment\\fR()\nand\n\\fBzip_source_buffer_fragment_create\\fR()\ncreate a zip source from the data in\n\\fIfragments\\fR.\n\\fInfragments\\fR\nspecifies the number of fragments.\nIf\n\\fIfreep\\fR\nis non-zero, the data will be freed when it is no longer needed.\n.nf\n.sp\n.RS 0n\nstruct zip_stat {\n    zip_uint8_t *data;    /* pointer to the actual data */\n    zip_uint64_t length;  /* length of this fragment */\n};\n.RE\n.fi\n.PP\nThe data\n\\fIfragments\\fR\npoint to must remain valid for the lifetime of the created source.\n\\fIfragments\\fR\nitself can be discarded once the source is created.\n.PP\nThe source can be used to open a zip archive from.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_buffer\\fR()\nand\n\\fBzip_source_buffer_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fInfragments\\fR\nis greater than zero and\n\\fIfragments\\fR\nis\n\\fRNULL\\fR.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_open_from_source(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_buffer_fragment\\fR()\nand\n\\fBzip_source_buffer_fragment_create\\fR()\nwere added in libzip 1.4.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_buffer_fragment.mdoc",
    "content": ".\\\" zip_source_buffer_fragment.mdoc -- create zip data source from multiple buffers\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_BUFFER_FRAGMENT 3\n.Os\n.Sh NAME\n.Nm zip_source_buffer_fragment ,\n.Nm zip_source_buffer_fragment_create\n.Nd create zip data source from multiple buffer\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_buffer_fragment \"zip_t *archive\" \"zip_buffer_fragment_t *fragments\" \"zip_uint64_t nfragments\" \"int freep\"\n.Ft zip_source_t *\n.Fn zip_source_buffer_fragment_create \"zip_buffer_fragment_t *fragments\" \"zip_uint64_t nfragments\" \"int freep\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_buffer_fragment\nand\n.Fn zip_source_buffer_fragment_create\ncreate a zip source from the data in\n.Ar fragments .\n.Ar nfragments\nspecifies the number of fragments.\nIf\n.Ar freep\nis non-zero, the data will be freed when it is no longer needed.\n.Bd -literal\nstruct zip_stat {\n    zip_uint8_t *data;    /* pointer to the actual data */\n    zip_uint64_t length;  /* length of this fragment */\n};\n.Ed\n.Pp\nThe data\n.Ar fragments\npoint to must remain valid for the lifetime of the created source.\n.Ar fragments\nitself can be discarded once the source is created.\n.Pp\nThe source can be used to open a zip archive from.\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_buffer\nand\n.Fn zip_source_buffer_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar nfragments\nis greater than zero and\n.Ar fragments\nis\n.Dv NULL .\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_open_from_source 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_buffer_fragment\nand\n.Fn zip_source_buffer_fragment_create\nwere added in libzip 1.4.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_close.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_close.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_close.mdoc -- close zip source (open for reading)\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_CLOSE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_close\\fR\n\\- close zip_source (which was open for reading)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_close\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_close\\fR()\ncloses\n\\fIsource\\fR,\nindicating that no more data will be read.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_free(3),\nzip_source_open(3)\n.SH \"HISTORY\"\n\\fBzip_source_close\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_close.mdoc",
    "content": ".\\\" zip_source_close.mdoc -- close zip source (open for reading)\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_CLOSE 3\n.Os\n.Sh NAME\n.Nm zip_source_close\n.Nd close zip_source (which was open for reading)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_close \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_close\ncloses\n.Fa source ,\nindicating that no more data will be read.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_free 3 ,\n.Xr zip_source_open 3\n.Sh HISTORY\n.Fn zip_source_close\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_commit_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_commit_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_commit_write.mdoc -- finalize changes to zip source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_COMMIT_WRITE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_commit_write\\fR\n\\- finalize changes to zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_commit_write\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_commit_write\\fR()\nfinishes writing data to\n\\fIsource\\fR\nand replaces the original with the newly written data.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_rollback_write(3),\nzip_source_seek_write(3),\nzip_source_tell_write(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_commit_write\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_commit_write.mdoc",
    "content": ".\\\" zip_source_commit_write.mdoc -- finalize changes to zip source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_COMMIT_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_commit_write\n.Nd finalize changes to zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_commit_write \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_commit_write\nfinishes writing data to\n.Fa source\nand replaces the original with the newly written data.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_rollback_write 3 ,\n.Xr zip_source_seek_write 3 ,\n.Xr zip_source_tell_write 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_commit_write\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_error.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_error.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_error.mdoc -- get zip_error for data source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_ERROR\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_error\\fR\n\\- get zip error for data source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_error_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_error\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_source_error\\fR()\nfunction returns the zip error for the data source\n\\fIsource\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_error_code_system(3),\nzip_error_code_zip(3)\n.SH \"HISTORY\"\n\\fBzip_source_error\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_error.mdoc",
    "content": ".\\\" zip_source_error.mdoc -- get zip_error for data source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_ERROR 3\n.Os\n.Sh NAME\n.Nm zip_source_error\n.Nd get zip error for data source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_error_t *\n.Fn zip_source_error \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe\n.Fn zip_source_error\nfunction returns the zip error for the data source\n.Ar source .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_error_code_system 3 ,\n.Xr zip_error_code_zip 3\n.Sh HISTORY\n.Fn zip_source_error\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_file.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_file.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_file.mdoc -- create data source from a file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_FILE\" \"3\" \"June 30, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_file\\fR,\n\\fBzip_source_file_create\\fR\n\\- create data source from a file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_file\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_file_create\\fR(\\fIconst\\ char\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_file\\fR()\nand\n\\fBzip_source_file_create\\fR()\ncreate a zip source from a file.\nThey open\n\\fIfname\\fR\nand read\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nfrom it.\n.PP\nWhen passing\n\\fRZIP_LENGTH_TO_END\\fR\n(or \\-1, which is deprecated) as\n\\fIlen\\fR,\n\\fBzip_source_file\\fR\ndetermines the file size when it is called and uses that as the\nexpected file size.\nIf the file size grows between creating and reading from the source,\nthe additional data is ignored.\nIf the file shrinks,\n\\fBlibzip\\fR\ntreats it as an error\n(\\fRZIP_ER_DATA_LENGTH\\fR).\n.PP\nWhen passing\n\\fRZIP_LENGTH_UNCHECKED\\fR\nas\n\\fIlen\\fR,\n\\fBzip_source_file\\fR\nassumes the file's size is unknown.\nReading from the source returns as much data as is there at that time\n(usually when calling\nzip_close(3)).\n.PP\n\\fBlibzip\\fR\ncan do various optimizations if the size of a source is known when\nit's created, so\n\\fRZIP_LENGTH_TO_END\\fR\nis preferable.\nIf you deal with files that are likely to change while you are\nprocessing them, you can use the less efficient\n\\fRZIP_LENGTH_UNCHECKED\\fR.\n.PP\nIf the file supports seek, the source can be used to open a zip archive from.\n.PP\nThe file is opened and read when the data from the source is used, usually by\n\\fBzip_close\\fR()\nor\n\\fBzip_open_from_source\\fR().\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_file\\fR()\nand\n\\fBzip_source_file_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIfname\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_OPEN\\fR]\nOpening\n\\fIfname\\fR\nfailed.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_file\\fR()\nand\n\\fBzip_source_file_create\\fR()\nwere added in libzip 1.0.\n.PP\n\\fRZIP_LENGTH_TO_END\\fR\nand\n\\fRZIP_LENGTH_UNCHECKED\\fR\nwere added in libzip 1.10.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_file.mdoc",
    "content": ".\\\" zip_source_file.mdoc -- create data source from a file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 30, 2023\n.Dt ZIP_SOURCE_FILE 3\n.Os\n.Sh NAME\n.Nm zip_source_file ,\n.Nm zip_source_file_create\n.Nd create data source from a file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_file \"zip_t *archive\" \"const char *fname\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_file_create \"const char *fname\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_file\nand\n.Fn zip_source_file_create\ncreate a zip source from a file.\nThey open\n.Ar fname\nand read\n.Ar len\nbytes from offset\n.Ar start\nfrom it.\n.Pp\nWhen passing\n.Dv ZIP_LENGTH_TO_END\n(or \\-1, which is deprecated) as\n.Ar len ,\n.Nm\ndetermines the file size when it is called and uses that as the\nexpected file size.\nIf the file size grows between creating and reading from the source,\nthe additional data is ignored.\nIf the file shrinks,\n.Nm libzip\ntreats it as an error\n.Dv ( ZIP_ER_DATA_LENGTH ) .\n.Pp\nWhen passing\n.Dv ZIP_LENGTH_UNCHECKED\nas\n.Ar len ,\n.Nm\nassumes the file's size is unknown.\nReading from the source returns as much data as is there at that time\n(usually when calling\n.Xr zip_close 3 ) .\n.Pp\n.Nm libzip\ncan do various optimizations if the size of a source is known when\nit's created, so\n.Dv ZIP_LENGTH_TO_END\nis preferable.\nIf you deal with files that are likely to change while you are\nprocessing them, you can use the less efficient\n.Dv ZIP_LENGTH_UNCHECKED .\n.Pp\nIf the file supports seek, the source can be used to open a zip archive from.\n.Pp\nThe file is opened and read when the data from the source is used, usually by\n.Fn zip_close\nor\n.Fn zip_open_from_source .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_file\nand\n.Fn zip_source_file_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar fname ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_OPEN\nOpening\n.Ar fname\nfailed.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_file\nand\n.Fn zip_source_file_create\nwere added in libzip 1.0.\n.Pp\n.Dv ZIP_LENGTH_TO_END\nand\n.Dv ZIP_LENGTH_UNCHECKED\nwere added in libzip 1.10.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_filep.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_filep.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_filep.mdoc -- create data source from a file stream\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_FILEP\" \"3\" \"June 30, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_filep\\fR,\n\\fBzip_source_filep_create\\fR\n\\- create data source from FILE *\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_filep\\fR(\\fIzip_t\\ *archive\\fR, \\fIFILE\\ *file\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_filep_create\\fR(\\fIFILE\\ *file\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_filep\\fR()\nand\n\\fBzip_source_filep_create\\fR()\ncreate a zip source from a file stream.\nThey read\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nfrom the open file stream\n\\fIfile\\fR.\nFor a description of the\n\\fIlen\\fR\nargument, see\nzip_source_file(3).\n.PP\nIf the file stream supports seeking, the source can be used to open\na read-only zip archive from.\n.PP\nThe file stream is closed when the source is being freed, usually\nby\nzip_close(3).\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_filep\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIfile\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5),\nzip_source_file(3)\n.SH \"HISTORY\"\n\\fBzip_source_filep\\fR()\nand\n\\fBzip_source_filep_create\\fR()\nwere added in libzip 1.0.\n.PP\n\\fRZIP_LENGTH_TO_END\\fR\nand\n\\fRZIP_LENGTH_UNCHECKED\\fR\nwere added in libzip 1.10.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_filep.mdoc",
    "content": ".\\\" zip_source_filep.mdoc -- create data source from a file stream\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 30, 2023\n.Dt ZIP_SOURCE_FILEP 3\n.Os\n.Sh NAME\n.Nm zip_source_filep ,\n.Nm zip_source_filep_create\n.Nd create data source from FILE *\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_filep \"zip_t *archive\" \"FILE *file\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_filep_create \"FILE *file\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_filep\nand\n.Fn zip_source_filep_create\ncreate a zip source from a file stream.\nThey read\n.Ar len\nbytes from offset\n.Ar start\nfrom the open file stream\n.Ar file .\nFor a description of the\n.Ar len\nargument, see\n.Xr zip_source_file 3 .\n.Pp\nIf the file stream supports seeking, the source can be used to open\na read-only zip archive from.\n.Pp\nThe file stream is closed when the source is being freed, usually\nby\n.Xr zip_close 3 .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_filep\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar file ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_file 3\n.Sh HISTORY\n.Fn zip_source_filep\nand\n.Fn zip_source_filep_create\nwere added in libzip 1.0.\n.Pp\n.Dv ZIP_LENGTH_TO_END\nand\n.Dv ZIP_LENGTH_UNCHECKED\nwere added in libzip 1.10.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_free.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_free.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_free.mdoc -- free zip data source\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_FREE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_free\\fR\n\\- free zip data source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_free\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_free\\fR()\ndecrements the reference count of\n\\fIsource\\fR\nand frees it if the reference count drops to 0.\nIf\n\\fIsource\\fR\nis\n\\fRNULL\\fR,\nit does nothing.\n.PP\n\\fINOTE\\fR:\nThis function should not be called on a\n\\fIsource\\fR\nafter it was used successfully in a\nzip_open_from_source(3),\nzip_file_add(3),\nor\nzip_file_replace(3)\ncall.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_keep(3)\n.SH \"HISTORY\"\n\\fBzip_source_free\\fR()\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_free.mdoc",
    "content": ".\\\" zip_source_free.mdoc -- free zip data source\n.\\\" Copyright (C) 2004-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_FREE 3\n.Os\n.Sh NAME\n.Nm zip_source_free\n.Nd free zip data source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_source_free \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_free\ndecrements the reference count of\n.Ar source\nand frees it if the reference count drops to 0.\nIf\n.Ar source\nis\n.Dv NULL ,\nit does nothing.\n.Pp\n.Em NOTE :\nThis function should not be called on a\n.Ar source\nafter it was used successfully in a\n.Xr zip_open_from_source 3 ,\n.Xr zip_file_add 3 ,\nor\n.Xr zip_file_replace 3\ncall.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_keep 3\n.Sh HISTORY\n.Fn zip_source_free\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_function.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_function.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_function.mdoc -- create data source from function\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_FUNCTION\" \"3\" \"January 5, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_function\\fR,\n\\fBzip_source_function_create\\fR\n\\- create data source from function\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_function\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_source_callback\\ fn\\fR, \\fIvoid\\ *userdata\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_function_create\\fR(\\fIzip_source_callback\\ fn\\fR, \\fIvoid\\ *userdata\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_function\\fR()\nand\n\\fBzip_source_function_create\\fR()\ncreate a zip source from the user-provided function\n\\fIfn\\fR,\nwhich must be of the following type:\n.PP\n\\fItypedef zip_int64_t\\fR\n\\fB\\fR(*\\fPzip_source_callback\\fR)\\fP\\fR(\\fIvoid\\ *userdata\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR, \\fIzip_source_cmd_t\\ cmd\\fR)\n.PP\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nare used for reporting errors and can be\n\\fRNULL\\fR.\n.PP\nWhen called by the library, the first argument is the\n\\fIuserdata\\fR\nargument supplied to the function.\nThe next two arguments are a buffer\n\\fIdata\\fR\nof size\n\\fIlen\\fR\nwhen data is passed in or expected to be returned, or else\n\\fRNULL\\fR\nand 0.\nThe last argument,\n\\fIcmd\\fR,\nspecifies which action the function should perform.\n.PP\nDepending on the uses, there are three useful sets of commands to be supported by a\n\\fBzip_source_callback\\fR():\n.TP 24n\nread source\nProviding streamed data (for file data added to archives).\nMust support\n\\fRZIP_SOURCE_OPEN\\fR,\n\\fRZIP_SOURCE_READ\\fR,\n\\fRZIP_SOURCE_CLOSE\\fR,\n\\fRZIP_SOURCE_STAT\\fR,\nand\n\\fRZIP_SOURCE_ERROR\\fR.\n.sp\nIf your source uses any allocated memory (including\n\\fIuserdata\\fR)\nit should also implement\n\\fRZIP_SOURCE_FREE\\fR\nto avoid memory leaks.\n.TP 24n\nseekable read source\nSame as previous, but from a source allowing reading from arbitrary\noffsets (also for read-only zip archive).\nMust additionally support\n\\fRZIP_SOURCE_SEEK\\fR,\n\\fRZIP_SOURCE_TELL\\fR,\nand\n\\fRZIP_SOURCE_SUPPORTS\\fR.\n.TP 24n\nread/write source\nSame as previous, but additionally allowing writing (also for writable\nzip archives).\nMust additionally support\n\\fRZIP_SOURCE_BEGIN_WRITE\\fR,\n\\fRZIP_SOURCE_COMMIT_WRITE\\fR,\n\\fRZIP_SOURCE_ROLLBACK_WRITE\\fR,\n\\fRZIP_SOURCE_SEEK_WRITE\\fR,\n\\fRZIP_SOURCE_TELL_WRITE\\fR,\nand\n\\fRZIP_SOURCE_REMOVE\\fR.\n.sp\nOn top of the above, supporting the pseudo-command\n\\fRZIP_SOURCE_SUPPORTS_REOPEN\\fR\nallows calling\n\\fBzip_source_open\\fR()\nagain after calling\n\\fBzip_source_close\\fR().\n.SS \"\\fRZIP_SOURCE_ACCEPT_EMPTY\\fR\"\nReturn 1 if an empty source should be accepted as a valid zip archive.\nThis is the default if this command is not supported by a source.\nFile system backed sources should return 0.\n.SS \"\\fRZIP_SOURCE_BEGIN_WRITE\\fR\"\nPrepare the source for writing.\nUse this to create any temporary file(s).\n.SS \"\\fRZIP_SOURCE_BEGIN_WRITE_CLONING\\fR\"\nPrepare the source for writing, keeping the first\n\\fIlen\\fR\nbytes of the original file.\nOnly implement this command if it is more efficient than copying the\ndata, and if it does not destructively overwrite the original file\n(you still have to be able to execute\n\\fRZIP_SOURCE_ROLLBACK_WRITE\\fR).\n.PP\nThe next write should happen at byte\n\\fIoffset\\fR.\n.SS \"\\fRZIP_SOURCE_CLOSE\\fR\"\nReading is done.\n.SS \"\\fRZIP_SOURCE_COMMIT_WRITE\\fR\"\nFinish writing to the source.\nReplace the original data with the newly written data.\nClean up temporary files or internal buffers.\nSubsequently opening and reading from the source should return the\nnewly written data.\n.SS \"\\fRZIP_SOURCE_ERROR\\fR\"\nGet error information.\n\\fIdata\\fR\npoints to an array of two ints, which should be filled with the libzip\nerror code and the corresponding system error code for the error that\noccurred.\nSee\nzip_errors(3)\nfor details on the error codes.\nIf the source stores error information in a zip_error_t, use\nzip_error_to_data(3)\nand return its return value.\nOtherwise, return 2 * sizeof(int).\n.SS \"\\fRZIP_SOURCE_FREE\\fR\"\nClean up and free all resources, including\n\\fIuserdata\\fR.\nThe callback function will not be called again.\n.SS \"\\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\\fR\"\nProvide information about various data.\nThen the data should be put in the appropriate entry in the passed\n\\fIzip_file_attributes_t\\fR\nargument, and the appropriate\n\\fRZIP_FILE_ATTRIBUTES_*\\fR\nvalue must be or'ed into the\n\\fIvalid\\fR\nmember to denote that the corresponding data has been provided.\nA\n\\fIzip_file_attributes_t\\fR\nstructure can be initialized using\nzip_file_attributes_init(3).\n.TP 12n\nASCII mode\nIf a file is a plaintext file in ASCII.\nCan be used by extraction tools to automatically convert line endings\n(part of the internal file attributes).\nMember\n\\fIascii\\fR,\nflag\n\\fRZIP_FILE_ATTRIBUTES_ASCII\\fR.\n.TP 12n\nGeneral Purpose Bit Flags (limited to Compression Flags)\nThe general purpose bit flag in the zip in the local and central\ndirectory headers contain information about the compression method.\nMember\n\\fIgeneral_purpose_bit_flags\\fR\nand\n\\fIgeneral_purpose_bit_mask\\fR\nto denote which members have been set;\nflag\n\\fRZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS\\fR.\n.TP 12n\nExternal File Attributes\nThe external file attributes (usually operating system-specific).\nMember\n\\fIexternal_file_attributes\\fR,\nflag\n\\fRZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES\\fR.\n.TP 12n\nVersion Needed\nA minimum version needed required to unpack this entry (in the usual\n\"major * 10 + minor\" format).\nMember\n\\fIversion_needed\\fR,\nflag\n\\fRZIP_FILE_ATTRIBUTES_VERSION_NEEDED\\fR.\n.TP 12n\nOperating System\nOne of the operating systems as defined by the\n\\fRZIP_OPSYS_*\\fR\nvariables (see\n\\fIzip.h\\fR).\nThis value affects the interpretation of the external file attributes.\nMember\n\\fIhost_system\\fR,\nflag\n\\fRZIP_FILE_ATTRIBUTES_HOST_SYSTEM\\fR.\n.SS \"\\fRZIP_SOURCE_OPEN\\fR\"\nPrepare for reading.\n.SS \"\\fRZIP_SOURCE_READ\\fR\"\nRead data into the buffer\n\\fIdata\\fR\nof size\n\\fIlen\\fR.\nReturn the number of bytes placed into\n\\fIdata\\fR\non success, and zero for end-of-file.\n.SS \"\\fRZIP_SOURCE_REMOVE\\fR\"\nRemove the underlying file.\nThis is called if a zip archive is empty when closed.\n.SS \"\\fRZIP_SOURCE_ROLLBACK_WRITE\\fR\"\nAbort writing to the source.\nDiscard written data.\nClean up temporary files or internal buffers.\nSubsequently opening and reading from the source should return the\noriginal data.\n.SS \"\\fRZIP_SOURCE_SEEK\\fR\"\nSpecify position to read next byte from, like\nfseek(3).\nUse\nZIP_SOURCE_GET_ARGS(3)\nto decode the arguments into the following struct:\n.nf\n.sp\n.RS 0n\nstruct zip_source_args_seek {\n    zip_int64_t offset;\n    int whence;\n};\n.RE\n.fi\n.PP\nIf the size of the source's data is known, use\nzip_source_seek_compute_offset(3)\nto validate the arguments and compute the new offset.\n.SS \"\\fRZIP_SOURCE_SEEK_WRITE\\fR\"\nSpecify position to write next byte to, like\nfseek(3).\nSee\n\\fRZIP_SOURCE_SEEK\\fR\nfor details.\n.SS \"\\fRZIP_SOURCE_STAT\\fR\"\nGet meta information for the input data.\n\\fIdata\\fR\npoints to an allocated\n\\fIstruct zip_stat\\fR,\nwhich should be initialized using\nzip_stat_init(3)\nand then filled in.\n.PP\nFor uncompressed, unencrypted data, all information is optional.\nHowever, fill in as much information as is readily available.\n.PP\nIf the data is compressed,\n\\fRZIP_STAT_COMP_METHOD\\fR,\n\\fRZIP_STAT_SIZE\\fR,\nand\n\\fRZIP_STAT_CRC\\fR\nmust be filled in.\n.PP\nIf the data is encrypted,\n\\fRZIP_STAT_ENCRYPTION_METHOD\\fR,\n\\fRZIP_STAT_COMP_METHOD\\fR,\n\\fRZIP_STAT_SIZE\\fR,\nand\n\\fRZIP_STAT_CRC\\fR\nmust be filled in.\n.PP\nInformation only available after the source has been read (e.g., size)\ncan be omitted in an earlier call.\n\\fINOTE\\fR:\n\\fBzip_source_function\\fR()\nmay be called with this argument even after being called with\n\\fRZIP_SOURCE_CLOSE\\fR.\n.PP\nReturn sizeof(struct zip_stat) on success.\n.SS \"\\fRZIP_SOURCE_SUPPORTS\\fR\"\nReturn bitmap specifying which commands are supported.\nUse\nzip_source_make_command_bitmap(3).\nIf this command is not implemented, the source is assumed to be a\nread source without seek support.\n.SS \"\\fRZIP_SOURCE_TELL\\fR\"\nReturn the current read offset in the source, like\nftell(3).\n.SS \"\\fRZIP_SOURCE_TELL_WRITE\\fR\"\nReturn the current write offset in the source, like\nftell(3).\n.SS \"\\fRZIP_SOURCE_WRITE\\fR\"\nWrite data to the source.\nReturn number of bytes written.\n.SS \"\\fRZIP_SOURCE_SUPPORTS_REOPEN\\fR\"\nThis command is never actually invoked, support for it signals the\nability to handle multiple open/read/close cycles.\n.SS \"Return Values\"\nCommands should return \\-1 on error.\n\\fRZIP_SOURCE_ERROR\\fR\nwill be called to retrieve the error code.\nOn success, commands return 0, unless specified otherwise in the\ndescription above.\n.SS \"Calling Conventions\"\nThe library will always issue\n\\fRZIP_SOURCE_OPEN\\fR\nbefore issuing\n\\fRZIP_SOURCE_READ\\fR,\n\\fRZIP_SOURCE_SEEK\\fR,\nor\n\\fRZIP_SOURCE_TELL\\fR.\nWhen it no longer wishes to read from this source, it will issue\n\\fRZIP_SOURCE_CLOSE\\fR.\nIf the library wishes to read the data again, it will issue\n\\fRZIP_SOURCE_OPEN\\fR\na second time.\nIf the function is unable to provide the data again, it should\nreturn \\-1.\n.PP\n\\fRZIP_SOURCE_BEGIN_WRITE\\fR\nor\n\\fRZIP_SOURCE_BEGIN_WRITE_CLONING\\fR\nwill be called before\n\\fRZIP_SOURCE_WRITE\\fR,\n\\fRZIP_SOURCE_SEEK_WRITE\\fR,\nor\n\\fRZIP_SOURCE_TELL_WRITE\\fR.\nWhen writing is complete, either\n\\fRZIP_SOURCE_COMMIT_WRITE\\fR\nor\n\\fRZIP_SOURCE_ROLLBACK_WRITE\\fR\nwill be called.\n.PP\n\\fRZIP_SOURCE_ACCEPT_EMPTY\\fR,\n\\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\\fR,\nand\n\\fRZIP_SOURCE_STAT\\fR\ncan be issued at any time.\n.PP\n\\fRZIP_SOURCE_ERROR\\fR\nwill only be issued in response to the function\nreturning \\-1.\n.PP\n\\fRZIP_SOURCE_FREE\\fR\nwill be the last command issued;\nif\n\\fRZIP_SOURCE_OPEN\\fR\nwas called and succeeded,\n\\fRZIP_SOURCE_CLOSE\\fR\nwill be called before\n\\fRZIP_SOURCE_FREE\\fR,\nand similarly for\n\\fRZIP_SOURCE_BEGIN_WRITE\\fR\nor\n\\fRZIP_SOURCE_BEGIN_WRITE_CLONING\\fR\nand\n\\fRZIP_SOURCE_COMMIT_WRITE\\fR\nor\n\\fRZIP_SOURCE_ROLLBACK_WRITE\\fR.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error (unless\nit is\n\\fRNULL\\fR).\n.SH \"ERRORS\"\n\\fBzip_source_function\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_attributes_init(3),\nzip_file_replace(3),\nzip_source(5),\nzip_stat_init(3)\n.SH \"HISTORY\"\n\\fBzip_source_function\\fR()\nand\n\\fBzip_source_function_create\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_function.mdoc",
    "content": ".\\\" zip_source_function.mdoc -- create data source from function\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 5, 2023\n.Dt ZIP_SOURCE_FUNCTION 3\n.Os\n.Sh NAME\n.Nm zip_source_function ,\n.Nm zip_source_function_create\n.Nd create data source from function\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_function \"zip_t *archive\" \"zip_source_callback fn\" \"void *userdata\"\n.Ft zip_source_t *\n.Fn zip_source_function_create \"zip_source_callback fn\" \"void *userdata\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_function\nand\n.Fn zip_source_function_create\ncreate a zip source from the user-provided function\n.Ar fn ,\nwhich must be of the following type:\n.Pp\n.Ft typedef zip_int64_t\n.Fo \\fR(*\\fPzip_source_callback\\fR)\\fP\n.Fa \"void *userdata\" \"void *data\" \"zip_uint64_t len\" \"zip_source_cmd_t cmd\"\n.Fc\n.Pp\n.Ar archive\nor\n.Ar error\nare used for reporting errors and can be\n.Dv NULL .\n.Pp\nWhen called by the library, the first argument is the\n.Ar userdata\nargument supplied to the function.\nThe next two arguments are a buffer\n.Ar data\nof size\n.Ar len\nwhen data is passed in or expected to be returned, or else\n.Dv NULL\nand 0.\nThe last argument,\n.Ar cmd ,\nspecifies which action the function should perform.\n.Pp\nDepending on the uses, there are three useful sets of commands to be supported by a\n.Fn zip_source_callback :\n.Bl -tag -width seekable-read-sourceXX\n.It read source\nProviding streamed data (for file data added to archives).\nMust support\n.Dv ZIP_SOURCE_OPEN ,\n.Dv ZIP_SOURCE_READ ,\n.Dv ZIP_SOURCE_CLOSE ,\n.Dv ZIP_SOURCE_STAT ,\nand\n.Dv ZIP_SOURCE_ERROR .\n.Pp\nIf your source uses any allocated memory (including\n.Ar userdata )\nit should also implement\n.Dv ZIP_SOURCE_FREE\nto avoid memory leaks.\n.It seekable read source\nSame as previous, but from a source allowing reading from arbitrary\noffsets (also for read-only zip archive).\nMust additionally support\n.Dv ZIP_SOURCE_SEEK ,\n.Dv ZIP_SOURCE_TELL ,\nand\n.Dv ZIP_SOURCE_SUPPORTS .\n.It read/write source\nSame as previous, but additionally allowing writing (also for writable\nzip archives).\nMust additionally support\n.Dv ZIP_SOURCE_BEGIN_WRITE ,\n.Dv ZIP_SOURCE_COMMIT_WRITE ,\n.Dv ZIP_SOURCE_ROLLBACK_WRITE ,\n.Dv ZIP_SOURCE_SEEK_WRITE ,\n.Dv ZIP_SOURCE_TELL_WRITE ,\nand\n.Dv ZIP_SOURCE_REMOVE .\n.Pp\nOn top of the above, supporting the pseudo-command\n.Dv ZIP_SOURCE_SUPPORTS_REOPEN\nallows calling\n.Fn zip_source_open\nagain after calling\n.Fn zip_source_close .\n.El\n.Ss Dv ZIP_SOURCE_ACCEPT_EMPTY\nReturn 1 if an empty source should be accepted as a valid zip archive.\nThis is the default if this command is not supported by a source.\nFile system backed sources should return 0.\n.Ss Dv ZIP_SOURCE_BEGIN_WRITE\nPrepare the source for writing.\nUse this to create any temporary file(s).\n.Ss Dv ZIP_SOURCE_BEGIN_WRITE_CLONING\nPrepare the source for writing, keeping the first\n.Ar len\nbytes of the original file.\nOnly implement this command if it is more efficient than copying the\ndata, and if it does not destructively overwrite the original file\n(you still have to be able to execute\n.Dv ZIP_SOURCE_ROLLBACK_WRITE ) .\n.Pp\nThe next write should happen at byte\n.Ar offset .\n.Ss Dv ZIP_SOURCE_CLOSE\nReading is done.\n.Ss Dv ZIP_SOURCE_COMMIT_WRITE\nFinish writing to the source.\nReplace the original data with the newly written data.\nClean up temporary files or internal buffers.\nSubsequently opening and reading from the source should return the\nnewly written data.\n.Ss Dv ZIP_SOURCE_ERROR\nGet error information.\n.Ar data\npoints to an array of two ints, which should be filled with the libzip\nerror code and the corresponding system error code for the error that\noccurred.\nSee\n.Xr zip_errors 3\nfor details on the error codes.\nIf the source stores error information in a zip_error_t, use\n.Xr zip_error_to_data 3\nand return its return value.\nOtherwise, return 2 * sizeof(int).\n.Ss Dv ZIP_SOURCE_FREE\nClean up and free all resources, including\n.Ar userdata .\nThe callback function will not be called again.\n.Ss Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES\nProvide information about various data.\nThen the data should be put in the appropriate entry in the passed\n.Vt zip_file_attributes_t\nargument, and the appropriate\n.Dv ZIP_FILE_ATTRIBUTES_*\nvalue must be or'ed into the\n.Ar valid\nmember to denote that the corresponding data has been provided.\nA\n.Vt zip_file_attributes_t\nstructure can be initialized using\n.Xr zip_file_attributes_init 3 .\n.Bl -tag -width 10n\n.It ASCII mode\nIf a file is a plaintext file in ASCII.\nCan be used by extraction tools to automatically convert line endings\n(part of the internal file attributes).\nMember\n.Ar ascii ,\nflag\n.Dv ZIP_FILE_ATTRIBUTES_ASCII .\n.It General Purpose Bit Flags (limited to Compression Flags)\nThe general purpose bit flag in the zip in the local and central\ndirectory headers contain information about the compression method.\nMember\n.Ar general_purpose_bit_flags\nand\n.Ar general_purpose_bit_mask\nto denote which members have been set;\nflag\n.Dv ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS .\n.It External File Attributes\nThe external file attributes (usually operating system-specific).\nMember\n.Ar external_file_attributes ,\nflag\n.Dv ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES .\n.It Version Needed\nA minimum version needed required to unpack this entry (in the usual\n\"major * 10 + minor\" format).\nMember\n.Ar version_needed ,\nflag\n.Dv ZIP_FILE_ATTRIBUTES_VERSION_NEEDED .\n.It Operating System\nOne of the operating systems as defined by the\n.Dv ZIP_OPSYS_*\nvariables (see\n.Pa zip.h ) .\nThis value affects the interpretation of the external file attributes.\nMember\n.Ar host_system ,\nflag\n.Dv ZIP_FILE_ATTRIBUTES_HOST_SYSTEM .\n.El\n.Ss Dv ZIP_SOURCE_OPEN\nPrepare for reading.\n.Ss Dv ZIP_SOURCE_READ\nRead data into the buffer\n.Ar data\nof size\n.Ar len .\nReturn the number of bytes placed into\n.Ar data\non success, and zero for end-of-file.\n.Ss Dv ZIP_SOURCE_REMOVE\nRemove the underlying file.\nThis is called if a zip archive is empty when closed.\n.Ss Dv ZIP_SOURCE_ROLLBACK_WRITE\nAbort writing to the source.\nDiscard written data.\nClean up temporary files or internal buffers.\nSubsequently opening and reading from the source should return the\noriginal data.\n.Ss Dv ZIP_SOURCE_SEEK\nSpecify position to read next byte from, like\n.Xr fseek 3 .\nUse\n.Xr ZIP_SOURCE_GET_ARGS 3\nto decode the arguments into the following struct:\n.Bd -literal\nstruct zip_source_args_seek {\n    zip_int64_t offset;\n    int whence;\n};\n.Ed\n.Pp\nIf the size of the source's data is known, use\n.Xr zip_source_seek_compute_offset 3\nto validate the arguments and compute the new offset.\n.Ss Dv ZIP_SOURCE_SEEK_WRITE\nSpecify position to write next byte to, like\n.Xr fseek 3 .\nSee\n.Dv ZIP_SOURCE_SEEK\nfor details.\n.Ss Dv ZIP_SOURCE_STAT\nGet meta information for the input data.\n.Ar data\npoints to an allocated\n.Vt struct zip_stat ,\nwhich should be initialized using\n.Xr zip_stat_init 3\nand then filled in.\n.Pp\nFor uncompressed, unencrypted data, all information is optional.\nHowever, fill in as much information as is readily available.\n.Pp\nIf the data is compressed,\n.Dv ZIP_STAT_COMP_METHOD ,\n.Dv ZIP_STAT_SIZE ,\nand\n.Dv ZIP_STAT_CRC\nmust be filled in.\n.Pp\nIf the data is encrypted,\n.Dv ZIP_STAT_ENCRYPTION_METHOD ,\n.Dv ZIP_STAT_COMP_METHOD ,\n.Dv ZIP_STAT_SIZE ,\nand\n.Dv ZIP_STAT_CRC\nmust be filled in.\n.Pp\nInformation only available after the source has been read (e.g., size)\ncan be omitted in an earlier call.\n.Em NOTE :\n.Fn zip_source_function\nmay be called with this argument even after being called with\n.Dv ZIP_SOURCE_CLOSE .\n.Pp\nReturn sizeof(struct zip_stat) on success.\n.Ss Dv ZIP_SOURCE_SUPPORTS\nReturn bitmap specifying which commands are supported.\nUse\n.Xr zip_source_make_command_bitmap 3 .\nIf this command is not implemented, the source is assumed to be a\nread source without seek support.\n.Ss Dv ZIP_SOURCE_TELL\nReturn the current read offset in the source, like\n.Xr ftell 3 .\n.Ss Dv ZIP_SOURCE_TELL_WRITE\nReturn the current write offset in the source, like\n.Xr ftell 3 .\n.Ss Dv ZIP_SOURCE_WRITE\nWrite data to the source.\nReturn number of bytes written.\n.Ss Dv ZIP_SOURCE_SUPPORTS_REOPEN\nThis command is never actually invoked, support for it signals the\nability to handle multiple open/read/close cycles.\n.Ss Return Values\nCommands should return \\-1 on error.\n.Dv ZIP_SOURCE_ERROR\nwill be called to retrieve the error code.\nOn success, commands return 0, unless specified otherwise in the\ndescription above.\n.Ss Calling Conventions\nThe library will always issue\n.Dv ZIP_SOURCE_OPEN\nbefore issuing\n.Dv ZIP_SOURCE_READ ,\n.Dv ZIP_SOURCE_SEEK ,\nor\n.Dv ZIP_SOURCE_TELL .\nWhen it no longer wishes to read from this source, it will issue\n.Dv ZIP_SOURCE_CLOSE .\nIf the library wishes to read the data again, it will issue\n.Dv ZIP_SOURCE_OPEN\na second time.\nIf the function is unable to provide the data again, it should\nreturn \\-1.\n.Pp\n.Dv ZIP_SOURCE_BEGIN_WRITE\nor\n.Dv ZIP_SOURCE_BEGIN_WRITE_CLONING\nwill be called before\n.Dv ZIP_SOURCE_WRITE ,\n.Dv ZIP_SOURCE_SEEK_WRITE ,\nor\n.Dv ZIP_SOURCE_TELL_WRITE .\nWhen writing is complete, either\n.Dv ZIP_SOURCE_COMMIT_WRITE\nor\n.Dv ZIP_SOURCE_ROLLBACK_WRITE\nwill be called.\n.Pp\n.Dv ZIP_SOURCE_ACCEPT_EMPTY ,\n.Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES ,\nand\n.Dv ZIP_SOURCE_STAT\ncan be issued at any time.\n.Pp\n.Dv ZIP_SOURCE_ERROR\nwill only be issued in response to the function\nreturning \\-1.\n.Pp\n.Dv ZIP_SOURCE_FREE\nwill be the last command issued;\nif\n.Dv ZIP_SOURCE_OPEN\nwas called and succeeded,\n.Dv ZIP_SOURCE_CLOSE\nwill be called before\n.Dv ZIP_SOURCE_FREE ,\nand similarly for\n.Dv ZIP_SOURCE_BEGIN_WRITE\nor\n.Dv ZIP_SOURCE_BEGIN_WRITE_CLONING\nand\n.Dv ZIP_SOURCE_COMMIT_WRITE\nor\n.Dv ZIP_SOURCE_ROLLBACK_WRITE .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error (unless\nit is\n.Dv NULL ) .\n.Sh ERRORS\n.Fn zip_source_function\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_attributes_init 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_stat_init 3\n.Sh HISTORY\n.Fn zip_source_function\nand\n.Fn zip_source_function_create\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_is_deleted.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_is_deleted.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_is_deleted.mdoc -- check if zip source is deleted\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_IS_DELETED\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_is_deleted\\fR\n\\- check if zip_source is deleted\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_is_deleted\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_is_deleted\\fR()\nreturns whether the zip_source was deleted.\nThis can for example happen when all entries are removed from a zip archive.\n.SH \"RETURN VALUES\"\n\\fBzip_source_is_deleted\\fR()\nreturns 1 if the zip_source is deleted and 0 otherwise.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_is_deleted\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_is_deleted.mdoc",
    "content": ".\\\" zip_source_is_deleted.mdoc -- check if zip source is deleted\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_IS_DELETED 3\n.Os\n.Sh NAME\n.Nm zip_source_is_deleted\n.Nd check if zip_source is deleted\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_is_deleted \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_is_deleted\nreturns whether the zip_source was deleted.\nThis can for example happen when all entries are removed from a zip archive.\n.Sh RETURN VALUES\n.Fn zip_source_is_deleted\nreturns 1 if the zip_source is deleted and 0 otherwise.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_is_deleted\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_is_seekable.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_is_seekable.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_seek.mdoc -- set read offset in source\n.\\\" Copyright (C) 2023 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_IS_SEEKABLE\" \"3\" \"March 10, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_is_seekable\\fR\n\\- check if a source supports seeking\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_is_seekable\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_is_seekable\\fR()\nchecks if\n\\fIsource\\fR\nsupports seeking via\nzip_source_seek(3).\n.SH \"RETURN VALUES\"\nIf the source supports seeking, 1 is returned.\nOtherwise, 0 is returned.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_seek(3)\n.SH \"HISTORY\"\n\\fBzip_source_is_seekable\\fR()\nwas added in libzip 1.10.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_is_seekable.mdoc",
    "content": ".\\\" zip_source_seek.mdoc -- set read offset in source\n.\\\" Copyright (C) 2023 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 10, 2023\n.Dt ZIP_SOURCE_IS_SEEKABLE 3\n.Os\n.Sh NAME\n.Nm zip_source_is_seekable\n.Nd check if a source supports seeking\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_is_seekable \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_is_seekable\nchecks if\n.Fa source\nsupports seeking via\n.Xr zip_source_seek 3 .\n.Sh RETURN VALUES\nIf the source supports seeking, 1 is returned.\nOtherwise, 0 is returned.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_seek 3\n.Sh HISTORY\n.Fn zip_source_is_seekable\nwas added in libzip 1.10.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_keep.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_keep.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_keep.mdoc -- increment reference count of zip data source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_KEEP\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_keep\\fR\n\\- increment reference count of zip data source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_keep\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_keep\\fR()\nincrements the reference count of\n\\fIsource\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_free(3)\n.SH \"HISTORY\"\n\\fBzip_source_keep\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_keep.mdoc",
    "content": ".\\\" zip_source_keep.mdoc -- increment reference count of zip data source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_KEEP 3\n.Os\n.Sh NAME\n.Nm zip_source_keep\n.Nd increment reference count of zip data source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_source_keep \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_keep\nincrements the reference count of\n.Ar source .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_free 3\n.Sh HISTORY\n.Fn zip_source_keep\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_layered.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_layered.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_layered.mdoc -- create layered source from function\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_LAYERED\" \"3\" \"January 20, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_layered\\fR,\n\\fBzip_source_layered_create\\fR\n\\- create layered data source from function\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_layered\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_source_t\\ *source\\fR, \\fIzip_source_layered_callback\\ fn\\fR, \\fIvoid\\ *userdata\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_layered_create\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_source_layered_callback\\ fn\\fR, \\fIvoid\\ *userdata\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_layered\\fR()\nand\n\\fBzip_source_layered_create\\fR()\ncreate a layered zip source from the user-provided function\n\\fIfn\\fR,\nwhich must be of the following type:\n.PP\n\\fItypedef zip_int64_t\\fR\n\\fB\\fR(*\\zip_source_layered_callback\\fR)\\fP\\fR(\\fIzip_source_t\\ *source\\fR, \\fIvoid\\ *userdata\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ length\\fR, \\fIzip_source_cmd_t\\ cmd\\fR)\n.PP\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nare used for reporting errors and can be\n\\fRNULL\\fR.\n.PP\nWhen called by the library, the first argument is the\n\\fIsource\\fR\nof the lower layer, the second argument is the\n\\fIuserdata\\fR\nargument supplied to the function.\nThe next two arguments are a buffer\n\\fIdata\\fR\nof size\n\\fIlength\\fR\nwhen data is passed in or expected to be returned, or else\n\\fRNULL\\fR\nand 0.\nThe last argument,\n\\fIcmd\\fR,\nspecifies which action the function should perform.\n.PP\nSee\nzip_source_function(3)\nfor a description of the commands.\n.PP\nA layered source transforms the data or metadata of the source below in some way.\nLayered sources can't support writing and are not sufficient to cleanly add support for additional compression or encryption methods.\nThis may be revised in a later release of libzip.\n.PP\nOn success, the layered source takes ownership of\n\\fIsource\\fR.\nThe caller should not free it.\n.PP\nThe interaction with the lower layer depends on the command:\n.SS \"\\fRZIP_SOURCE_ACCEPT_EMPTY\\fR\"\nIf the layered source supports this command, the lower layer is not called automatically.\nOtherwise, the return value of the lower source is used.\n.SS \"\\fRZIP_SOURCE_CLOSE\\fR\"\nThe lower layer is closed after the callback returns.\n.SS \"\\fRZIP_SOURCE_ERROR\\fR\"\nThe lower layer is not called automatically.\nIf you need to retrieve error information from the lower layer, use\nzip_error_set_from_source(3)\nor\nzip_source_pass_to_lower_layer(3).\n.SS \"\\fRZIP_SOURCE_FREE\\fR\"\nThe lower layer is freed after the callback returns.\n.SS \"\\fRZIP_SOURCE_GET_FILE_ATTRIBUTES\\fR\"\nThe attributes of the lower layer are merged with the attributes returned by the callback: information set by the callback wins over the lower layer, with the following exceptions: the higher\n\\fIversion_needed\\fR\nis used, and\n\\fIgeneral_purpose_bit_flags\\fR\nare only overwritten if the corresponding bit is set in\n\\fIgeneral_purpose_bit_mask\\fR.\n.SS \"\\fRZIP_SOURCE_OPEN\\fR\"\nThe lower layer is opened before the callback is called.\n.SS \"\\fRZIP_SOURCE_READ\\fR\"\nThe lower layer is not called automatically.\n.SS \"\\fRZIP_SOURCE_SEEK\\fR\"\nThe lower layer is not called automatically.\n.SS \"\\fRZIP_SOURCE_STAT\\fR\"\n\\fIdata\\fR\ncontains the stat information from the lower layer when the callback is called.\n.SS \"\\fRZIP_SOURCE_SUPPORTS\\fR\"\n\\fIdata\\fR\ncontains the bitmap of commands supported by the lower layer when the callback is called.\nSince layered sources can't support writing, all commands related to writing are stripped from the returned support bitmap.\n.SS \"\\fRZIP_SOURCE_TELL\\fR\"\nThe lower layer is not called automatically.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error (unless\nit is\n\\fRNULL\\fR).\n.SH \"ERRORS\"\n\\fBzip_source_layered\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_attributes_init(3),\nzip_file_replace(3),\nzip_source(5),\nzip_source_function(3),\nzip_source_pass_to_lower_layer(3)\n.SH \"HISTORY\"\n\\fBzip_source_layered\\fR()\nand\n\\fBzip_source_layered_create\\fR()\nwere added in libzip 1.10.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_layered.mdoc",
    "content": ".\\\" zip_source_layered.mdoc -- create layered source from function\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 20, 2023\n.Dt ZIP_SOURCE_LAYERED 3\n.Os\n.Sh NAME\n.Nm zip_source_layered ,\n.Nm zip_source_layered_create\n.Nd create layered data source from function\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_layered \"zip_t *archive\" \"zip_source_t *source\" \"zip_source_layered_callback fn\" \"void *userdata\"\n.Ft zip_source_t *\n.Fn zip_source_layered_create \"zip_source_t *source\" \"zip_source_layered_callback fn\" \"void *userdata\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_layered\nand\n.Fn zip_source_layered_create\ncreate a layered zip source from the user-provided function\n.Ar fn ,\nwhich must be of the following type:\n.Pp\n.Ft typedef zip_int64_t\n.Fo \\fR(*\\zip_source_layered_callback\\fR)\\fP\n.Fa \"zip_source_t *source\" \"void *userdata\" \"void *data\" \"zip_uint64_t length\" \"zip_source_cmd_t cmd\"\n.Fc\n.Pp\n.Ar archive\nor\n.Ar error\nare used for reporting errors and can be\n.Dv NULL .\n.Pp\nWhen called by the library, the first argument is the\n.Ar source\nof the lower layer, the second argument is the\n.Ar userdata\nargument supplied to the function.\nThe next two arguments are a buffer\n.Ar data\nof size\n.Ar length\nwhen data is passed in or expected to be returned, or else\n.Dv NULL\nand 0.\nThe last argument,\n.Ar cmd ,\nspecifies which action the function should perform.\n.Pp\nSee\n.Xr zip_source_function 3\nfor a description of the commands.\n.Pp\nA layered source transforms the data or metadata of the source below in some way.\nLayered sources can't support writing and are not sufficient to cleanly add support for additional compression or encryption methods.\nThis may be revised in a later release of libzip.\n.Pp\nOn success, the layered source takes ownership of\n.Ar source .\nThe caller should not free it.\n.Pp\nThe interaction with the lower layer depends on the command:\n.Ss Dv ZIP_SOURCE_ACCEPT_EMPTY\nIf the layered source supports this command, the lower layer is not called automatically.\nOtherwise, the return value of the lower source is used.\n.Ss Dv ZIP_SOURCE_CLOSE\nThe lower layer is closed after the callback returns.\n.Ss Dv ZIP_SOURCE_ERROR\nThe lower layer is not called automatically.\nIf you need to retrieve error information from the lower layer, use\n.Xr zip_error_set_from_source 3\nor\n.Xr zip_source_pass_to_lower_layer 3 .\n.Ss Dv ZIP_SOURCE_FREE\nThe lower layer is freed after the callback returns.\n.Ss Dv ZIP_SOURCE_GET_FILE_ATTRIBUTES\nThe attributes of the lower layer are merged with the attributes returned by the callback: information set by the callback wins over the lower layer, with the following exceptions: the higher\n.Ar version_needed\nis used, and\n.Ar general_purpose_bit_flags\nare only overwritten if the corresponding bit is set in\n.Ar general_purpose_bit_mask .\n.Ss Dv ZIP_SOURCE_OPEN\nThe lower layer is opened before the callback is called.\n.Ss Dv ZIP_SOURCE_READ\nThe lower layer is not called automatically.\n.Ss Dv ZIP_SOURCE_SEEK\nThe lower layer is not called automatically.\n.Ss Dv ZIP_SOURCE_STAT\n.Ar data\ncontains the stat information from the lower layer when the callback is called.\n.Ss Dv ZIP_SOURCE_SUPPORTS\n.Ar data\ncontains the bitmap of commands supported by the lower layer when the callback is called.\nSince layered sources can't support writing, all commands related to writing are stripped from the returned support bitmap.\n.Ss Dv ZIP_SOURCE_TELL\nThe lower layer is not called automatically.\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error (unless\nit is\n.Dv NULL ) .\n.Sh ERRORS\n.Fn zip_source_layered\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_attributes_init 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_function 3 ,\n.Xr zip_source_pass_to_lower_layer 3\n.Sh HISTORY\n.Fn zip_source_layered\nand\n.Fn zip_source_layered_create\nwere added in libzip 1.10.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_make_command_bitmap.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_make_command_bitmap.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_make_command_bitmap -- create bitmap of supported source operations\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_MAKE_COMMAND_BITMAP\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_make_command_bitmap\\fR\n\\- create bitmap of supported source operations\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_make_command_bitmap\\fR(\\fIzip_source_cmd_t\\ command\\fR, \\fI...\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_source_make_command_bitmap\\fR()\nfunction returns a bitmap of source commands suitable as return value\nfor\n\\fRZIP_SOURCE_SUPPORTS\\fR.\nIt includes all the commands from the argument list, which must be\nterminated by \\-1.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source_function(3)\n.SH \"HISTORY\"\n\\fBzip_source_make_command_bitmap\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_make_command_bitmap.mdoc",
    "content": ".\\\" zip_source_make_command_bitmap -- create bitmap of supported source operations\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_MAKE_COMMAND_BITMAP 3\n.Os\n.Sh NAME\n.Nm zip_source_make_command_bitmap\n.Nd create bitmap of supported source operations\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_make_command_bitmap \"zip_source_cmd_t command\" \"...\"\n.Sh DESCRIPTION\nThe\n.Fn zip_source_make_command_bitmap\nfunction returns a bitmap of source commands suitable as return value\nfor\n.Dv ZIP_SOURCE_SUPPORTS .\nIt includes all the commands from the argument list, which must be\nterminated by \\-1.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source_function 3\n.Sh HISTORY\n.Fn zip_source_make_command_bitmap\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_open.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_open.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_open.mdoc -- open zip source for reading\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_OPEN\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_open\\fR\n\\- open zip_source for reading\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_open\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_open\\fR()\nopens\n\\fIsource\\fR\nfor reading.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_close(3),\nzip_source_read(3),\nzip_source_seek(3),\nzip_source_tell(3)\n.SH \"HISTORY\"\n\\fBzip_source_open\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_open.mdoc",
    "content": ".\\\" zip_source_open.mdoc -- open zip source for reading\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_OPEN 3\n.Os\n.Sh NAME\n.Nm zip_source_open\n.Nd open zip_source for reading\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_open \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_open\nopens\n.Fa source\nfor reading.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_close 3 ,\n.Xr zip_source_read 3 ,\n.Xr zip_source_seek 3 ,\n.Xr zip_source_tell 3\n.Sh HISTORY\n.Fn zip_source_open\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_pass_to_lower_layer.mdoc",
    "content": ".\\\" zip_source_pass_to_lower_layer.mdoc -- pass command to lower layer\n.\\\" Copyright (C) 2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 5, 2022\n.Dt ZIP_SOURCE_PASS_TO_LOWER_LAYER 3\n.Os\n.Sh NAME\n.Nm zip_source_pass_to_lower_layer\n.Nd pass command to lower layer\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_pass_to_lower_layer \"zip_source_t *source\" \"void *data\" \"zip_uint64_t length\" \"zip_source_cmd_t command\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_pass_to_lower_layer\nis used in a layered source callback to pass commands for which you don't want to change the result to the lower layer.\nYou can use it in the\n.Dv default\ncase of the callback.\n.Sh RETURN VALUES\nThe return value is meant to be returned by the callback.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_layered 3\n.Sh HISTORY\n.Fn zip_source_pass_to_lower_layer\nwas added in libzip 1.10.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_read.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_read.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_read.mdoc -- read data from zip source\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_READ\" \"3\" \"September 28, 2021\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_read\\fR\n\\- read data from zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_read\\fR(\\fIzip_source_t\\ *source\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_read\\fR()\nreads up to\n\\fIlen\\fR\nbytes of data from\n\\fIsource\\fR\nat the current read offset into the buffer\n\\fIdata\\fR.\n.PP\nThe zip source\n\\fIsource\\fR\nhas to be opened for reading by calling\nzip_source_open(3)\nfirst.\n.SH \"RETURN VALUES\"\nUpon successful completion the number of bytes read is returned.\nWhen\n\\fBzip_source_read\\fR()\nis called after reaching the end of the file, 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_seek(3),\nzip_source_tell(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_read\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_read.mdoc",
    "content": ".\\\" zip_source_read.mdoc -- read data from zip source\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd September 28, 2021\n.Dt ZIP_SOURCE_READ 3\n.Os\n.Sh NAME\n.Nm zip_source_read\n.Nd read data from zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_read \"zip_source_t *source\" \"void *data\" \"zip_uint64_t len\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_read\nreads up to\n.Ar len\nbytes of data from\n.Ar source\nat the current read offset into the buffer\n.Ar data .\n.Pp\nThe zip source\n.Ar source\nhas to be opened for reading by calling\n.Xr zip_source_open 3\nfirst.\n.Sh RETURN VALUES\nUpon successful completion the number of bytes read is returned.\nWhen\n.Fn zip_source_read\nis called after reaching the end of the file, 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_seek 3 ,\n.Xr zip_source_tell 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_read\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_rollback_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_rollback_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_rollback_write.mdoc -- undo changes to zip source\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_ROLLBACK_WRITE\" \"3\" \"November 3, 2021\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_rollback_write\\fR\n\\- undo changes to zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_rollback_write\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_rollback_write\\fR()\nreverts changes written to\n\\fIsource\\fR,\nrestoring the data before\nzip_source_begin_write(3)\nwas called.\nUsually this removes temporary files or frees buffers.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_commit_write(3),\nzip_source_seek_write(3),\nzip_source_tell_write(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_rollback_write\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_rollback_write.mdoc",
    "content": ".\\\" zip_source_rollback_write.mdoc -- undo changes to zip source\n.\\\" Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd November 3, 2021\n.Dt ZIP_SOURCE_ROLLBACK_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_rollback_write\n.Nd undo changes to zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_source_rollback_write \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_rollback_write\nreverts changes written to\n.Fa source ,\nrestoring the data before\n.Xr zip_source_begin_write 3\nwas called.\nUsually this removes temporary files or frees buffers.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_commit_write 3 ,\n.Xr zip_source_seek_write 3 ,\n.Xr zip_source_tell_write 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_rollback_write\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_seek.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_seek.mdoc -- set read offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_SEEK\" \"3\" \"March 10, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_seek\\fR\n\\- set read offset in zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_seek\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_int64_t\\ offset\\fR, \\fIint\\ whence\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_seek\\fR()\nsets the current read offset for\n\\fIsource\\fR.\nJust like in\nfseek(3),\ndepending on the\n\\fIwhence\\fR\nargument, the\n\\fIoffset\\fR\nis counted relative from:\n.RS 6n\n.TP 12n\n\\fRSEEK_SET\\fR\nstart of file\n.TP 12n\n\\fRSEEK_CUR\\fR\ncurrent read offset in file\n.TP 12n\n\\fRSEEK_END\\fR\nend of file\n.RE\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_is_seekable(3),\nzip_source_read(3),\nzip_source_tell(3)\n.SH \"HISTORY\"\n\\fBzip_source_seek\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek.mdoc",
    "content": ".\\\" zip_source_seek.mdoc -- set read offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 10, 2023\n.Dt ZIP_SOURCE_SEEK 3\n.Os\n.Sh NAME\n.Nm zip_source_seek\n.Nd set read offset in zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_seek \"zip_source_t *source\" \"zip_int64_t offset\" \"int whence\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_seek\nsets the current read offset for\n.Fa source .\nJust like in\n.Xr fseek 3 ,\ndepending on the\n.Ar whence\nargument, the\n.Ar offset\nis counted relative from:\n.Bl -tag -width SEEK_CURXX -offset indent\n.It Dv SEEK_SET\nstart of file\n.It Dv SEEK_CUR\ncurrent read offset in file\n.It Dv SEEK_END\nend of file\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_is_seekable 3 ,\n.Xr zip_source_read 3 ,\n.Xr zip_source_tell 3\n.Sh HISTORY\n.Fn zip_source_seek\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek_compute_offset.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_seek_compute_offset.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_seek_compute_offset.mdoc - validate arguments and compute offset\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_SEEK_COMPUTE_OFFSET\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_seek_compute_offset\\fR\n\\- validate arguments and compute offset\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_seek_compute_offset\\fR(\\fIzip_uint64_t\\ offset\\fR, \\fIzip_uint64_t\\ length\\fR, \\fIvoid\\ *data\\fR, \\fIzip_uint64_t\\ data_length\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nUse this function to compute the offset for a\n\\fRZIP_SOURCE_SEEK\\fR\nor\n\\fRZIP_SOURCE_SEEK_WRITE\\fR\ncommand.\n\\fIdata\\fR\nand\n\\fIdata_length\\fR\nare the arguments to the source callback,\n\\fIoffset\\fR\nis the current offset and\n\\fIlength\\fR\nis the length of the source data or, for\n\\fRZIP_SOURCE_SEEK_WRITE\\fR,\nthe amount of data written.\n.SH \"RETURN VALUES\"\nOn success, it returns the new offset, on error it returns \\-1 and\nsets\n\\fIerror\\fR.\n.SH \"ERRORS\"\n\\fBzip_source_seek_compute_offset\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\nOne of the arguments is invalid or the seek would place the offset\noutside the data.\n.SH \"SEE ALSO\"\nzip_source_function(3)\n.SH \"HISTORY\"\n\\fBzip_source_seek_compute_offset\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek_compute_offset.mdoc",
    "content": ".\\\" zip_source_seek_compute_offset.mdoc - validate arguments and compute offset\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_SEEK_COMPUTE_OFFSET 3\n.Os\n.Sh NAME\n.Nm zip_source_seek_compute_offset\n.Nd validate arguments and compute offset\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_seek_compute_offset \"zip_uint64_t offset\" \"zip_uint64_t length\" \"void *data\" \"zip_uint64_t data_length\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nUse this function to compute the offset for a\n.Dv ZIP_SOURCE_SEEK\nor\n.Dv ZIP_SOURCE_SEEK_WRITE\ncommand.\n.Ar data\nand\n.Ar data_length\nare the arguments to the source callback,\n.Ar offset\nis the current offset and\n.Ar length\nis the length of the source data or, for\n.Dv ZIP_SOURCE_SEEK_WRITE ,\nthe amount of data written.\n.Sh RETURN VALUES\nOn success, it returns the new offset, on error it returns \\-1 and\nsets\n.Ar error .\n.Sh ERRORS\n.Fn zip_source_seek_compute_offset\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\nOne of the arguments is invalid or the seek would place the offset\noutside the data.\n.El\n.Sh SEE ALSO\n.Xr zip_source_function 3\n.Sh HISTORY\n.Fn zip_source_seek_compute_offset\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_seek_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_seek_write.mdoc -- set write offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_SEEK_WRITE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_seek_write\\fR\n\\- set write offset in zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_seek_write\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_int64_t\\ offset\\fR, \\fIint\\ whence\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_seek_write\\fR()\nsets the current write offset for\n\\fIsource\\fR.\nJust like in\nfseek(3),\ndepending on the\n\\fIwhence\\fR\nargument, the\n\\fIoffset\\fR\nis counted relative from:\n.RS 6n\n.TP 12n\n\\fRSEEK_SET\\fR\nstart of file\n.TP 12n\n\\fRSEEK_CUR\\fR\ncurrent write offset in file\n.TP 12n\n\\fRSEEK_END\\fR\nend of file\n.RE\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_commit_write(3),\nzip_source_rollback_write(3),\nzip_source_tell_write(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_seek_write\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_seek_write.mdoc",
    "content": ".\\\" zip_source_seek_write.mdoc -- set write offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_SEEK_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_seek_write\n.Nd set write offset in zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_seek_write \"zip_source_t *source\" \"zip_int64_t offset\" \"int whence\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_seek_write\nsets the current write offset for\n.Fa source .\nJust like in\n.Xr fseek 3 ,\ndepending on the\n.Ar whence\nargument, the\n.Ar offset\nis counted relative from:\n.Bl -tag -width SEEK_CURXX -offset indent\n.It Dv SEEK_SET\nstart of file\n.It Dv SEEK_CUR\ncurrent write offset in file\n.It Dv SEEK_END\nend of file\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_commit_write 3 ,\n.Xr zip_source_rollback_write 3 ,\n.Xr zip_source_tell_write 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_seek_write\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_stat.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_stat.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_stat.mdoc -- get information about zip source\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_STAT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_stat\\fR\n\\- get information about zip_source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_stat\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_stat_t\\ *sb\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_source_stat\\fR()\nfunction obtains information about the zip source\n\\fIsource\\fR\n.PP\nThe\n\\fIsb\\fR\nargument is a pointer to a\n\\fIstruct zip_source_stat\\fR\n(shown below), into which information about the zip source is placed.\n.nf\n.sp\n.RS 0n\nstruct zip_source_stat {\n    zip_uint64_t valid;                 /* which fields have valid values */\n    const char *name;                   /* name of the file */\n    zip_uint64_t index;                 /* index within archive */\n    zip_uint64_t size;                  /* size of file (uncompressed) */\n    zip_uint64_t comp_size;             /* size of file (compressed) */\n    time_t mtime;                       /* modification time */\n    zip_uint32_t crc;                   /* crc of file data */\n    zip_uint16_t comp_method;           /* compression method used */\n    zip_uint16_t encryption_method;     /* encryption method used */\n    zip_uint32_t flags;                 /* reserved for future use */\n};\n.RE\n.fi\nThe structure pointed to by\n\\fIsb\\fR\nmust be initialized with\n\\fBzip_stat_init\\fR(\\fI3\\fR)\nbefore calling\n\\fBzip_source_stat\\fR().\n.PP\nThe\n\\fIvalid\\fR\nfield of the structure specifies which other fields are valid.\nCheck if the flag defined by the following defines are in\n\\fIvalid\\fR\nbefore accessing the fields:\n.RS 6n\n.PD 0\n.TP 30n\n\\fRZIP_STAT_NAME\\fR\n\\fIname\\fR\n.TP 30n\n\\fRZIP_STAT_INDEX\\fR\n\\fIindex\\fR\n.TP 30n\n\\fRZIP_STAT_SIZE\\fR\n\\fIsize\\fR\n.TP 30n\n\\fRZIP_STAT_COMP_SIZE\\fR\n\\fIcomp_size\\fR\n.TP 30n\n\\fRZIP_STAT_MTIME\\fR\n\\fImtime\\fR\n.TP 30n\n\\fRZIP_STAT_CRC\\fR\n\\fIcrc\\fR\n.TP 30n\n\\fRZIP_STAT_COMP_METHOD\\fR\n\\fIcomp_method\\fR\n.TP 30n\n\\fRZIP_STAT_ENCRYPTION_METHOD\\fR\n\\fIencryption_method\\fR\n.TP 30n\n\\fRZIP_STAT_FLAGS\\fR\n\\fIflags\\fR\n.RE\n.PD\n.PP\n\\fINOTE\\fR:\nSome fields may only be filled out after all data has been read from\nthe source, for example the\n\\fIcrc\\fR\nor\n\\fIsize\\fR\nfields.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_stat\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_stat.mdoc",
    "content": ".\\\" zip_source_stat.mdoc -- get information about zip source\n.\\\" Copyright (C) 2014-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_STAT 3\n.Os\n.Sh NAME\n.Nm zip_source_stat\n.Nd get information about zip_source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_source_stat \"zip_source_t *source\" \"zip_stat_t *sb\"\n.Sh DESCRIPTION\nThe\n.Fn zip_source_stat\nfunction obtains information about the zip source\n.Ar source\n.Pp\nThe\n.Ar sb\nargument is a pointer to a\n.Ft struct zip_source_stat\n(shown below), into which information about the zip source is placed.\n.Bd -literal\nstruct zip_source_stat {\n    zip_uint64_t valid;                 /* which fields have valid values */\n    const char *name;                   /* name of the file */\n    zip_uint64_t index;                 /* index within archive */\n    zip_uint64_t size;                  /* size of file (uncompressed) */\n    zip_uint64_t comp_size;             /* size of file (compressed) */\n    time_t mtime;                       /* modification time */\n    zip_uint32_t crc;                   /* crc of file data */\n    zip_uint16_t comp_method;           /* compression method used */\n    zip_uint16_t encryption_method;     /* encryption method used */\n    zip_uint32_t flags;                 /* reserved for future use */\n};\n.Ed\nThe structure pointed to by\n.Ar sb\nmust be initialized with\n.Fn zip_stat_init 3\nbefore calling\n.Fn zip_source_stat .\n.Pp\nThe\n.Ar valid\nfield of the structure specifies which other fields are valid.\nCheck if the flag defined by the following defines are in\n.Ar valid\nbefore accessing the fields:\n.Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent\n.It Dv ZIP_STAT_NAME\n.Ar name\n.It Dv ZIP_STAT_INDEX\n.Ar index\n.It Dv ZIP_STAT_SIZE\n.Ar size\n.It Dv ZIP_STAT_COMP_SIZE\n.Ar comp_size\n.It Dv ZIP_STAT_MTIME\n.Ar mtime\n.It Dv ZIP_STAT_CRC\n.Ar crc\n.It Dv ZIP_STAT_COMP_METHOD\n.Ar comp_method\n.It Dv ZIP_STAT_ENCRYPTION_METHOD\n.Ar encryption_method\n.It Dv ZIP_STAT_FLAGS\n.Ar flags\n.El\n.Pp\n.Em NOTE :\nSome fields may only be filled out after all data has been read from\nthe source, for example the\n.Ar crc\nor\n.Ar size\nfields.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_stat\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_tell.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_tell.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_tell.mdoc -- report current read offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_TELL\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_tell\\fR\n\\- report current read offset in zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_tell\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_tell\\fR()\nreturns the current read offset\nfor\n\\fIsource\\fR.\nThe return value can be passed to\nzip_source_seek(3)\nwith\n\\fIwhence\\fR\nset to\n\\fRSEEK_SET\\fR\nto return to the same location in the source.\n.SH \"RETURN VALUES\"\nUpon successful completion the current read offset is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_read(3),\nzip_source_tell_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_tell\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_tell.mdoc",
    "content": ".\\\" zip_source_tell.mdoc -- report current read offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_TELL 3\n.Os\n.Sh NAME\n.Nm zip_source_tell\n.Nd report current read offset in zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_tell \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_tell\nreturns the current read offset\nfor\n.Fa source .\nThe return value can be passed to\n.Xr zip_source_seek 3\nwith\n.Ar whence\nset to\n.Dv SEEK_SET\nto return to the same location in the source.\n.Sh RETURN VALUES\nUpon successful completion the current read offset is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_read 3 ,\n.Xr zip_source_tell_write 3\n.Sh HISTORY\n.Fn zip_source_tell\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_tell_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_tell_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_tell_write.mdoc -- report current write offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_TELL_WRITE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_tell_write\\fR\n\\- report current write offset in zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_tell_write\\fR(\\fIzip_source_t\\ *source\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_tell_write\\fR()\nreturns the current write offset\nfor\n\\fIsource\\fR.\nThe return value can be passed to\nzip_source_seek_write(3)\nwith\n\\fIwhence\\fR\nset to\n\\fRSEEK_SET\\fR\nto return to the same location in the source.\n.SH \"RETURN VALUES\"\nUpon successful completion the current write offset is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_commit_write(3),\nzip_source_rollback_write(3),\nzip_source_tell(3),\nzip_source_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_tell_write\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_tell_write.mdoc",
    "content": ".\\\" zip_source_tell_write.mdoc -- report current write offset in source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_TELL_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_tell_write\n.Nd report current write offset in zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_tell_write \"zip_source_t *source\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_tell_write\nreturns the current write offset\nfor\n.Fa source .\nThe return value can be passed to\n.Xr zip_source_seek_write 3\nwith\n.Ar whence\nset to\n.Dv SEEK_SET\nto return to the same location in the source.\n.Sh RETURN VALUES\nUpon successful completion the current write offset is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_commit_write 3 ,\n.Xr zip_source_rollback_write 3 ,\n.Xr zip_source_tell 3 ,\n.Xr zip_source_write 3\n.Sh HISTORY\n.Fn zip_source_tell_write\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32a.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_win32a.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_win32a.mdoc -- create data source using a win32 ANSI name\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_WIN32A\" \"3\" \"June 30, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_win32a\\fR,\n\\fBzip_source_win32a_create\\fR\n\\- create data source from a Windows ANSI file name\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32a\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32a_create\\fR(\\fIconst\\ char\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_win32a\\fR()\nand\n\\fBzip_source_win32a_create\\fR()\ncreate a zip source on Windows using a Windows ANSI name.\nThey open\n\\fIfname\\fR\nand read\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nfrom it.\nFor a description of the\n\\fIlen\\fR\nargument, see\nzip_source_file(3).\n.PP\nIf the file supports seek, the source can be used to open a zip archive from.\n.PP\nThe file is opened and read when the data from the source is used, usually by\n\\fBzip_close\\fR()\nor\n\\fBzip_open_from_source\\fR().\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_win32a\\fR()\nand\n\\fBzip_source_win32a_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIfname\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_OPEN\\fR]\nOpening\n\\fIfname\\fR\nfailed.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5),\nzip_source_file(3),\nzip_source_win32handle(3),\nzip_source_win32w(3)\n.SH \"HISTORY\"\n\\fBzip_source_win32a\\fR()\nand\n\\fBzip_source_win32a_create\\fR()\nwere added in libzip 1.0.\n.PP\n\\fRZIP_LENGTH_TO_END\\fR\nand\n\\fRZIP_LENGTH_UNCHECKED\\fR\nwere added in libzip 1.10.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32a.mdoc",
    "content": ".\\\" zip_source_win32a.mdoc -- create data source using a win32 ANSI name\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 30, 2023\n.Dt ZIP_SOURCE_WIN32A 3\n.Os\n.Sh NAME\n.Nm zip_source_win32a ,\n.Nm zip_source_win32a_create\n.Nd create data source from a Windows ANSI file name\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_win32a \"zip_t *archive\" \"const char *fname\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_win32a_create \"const char *fname\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_win32a\nand\n.Fn zip_source_win32a_create\ncreate a zip source on Windows using a Windows ANSI name.\nThey open\n.Ar fname\nand read\n.Ar len\nbytes from offset\n.Ar start\nfrom it.\nFor a description of the\n.Ar len\nargument, see\n.Xr zip_source_file 3 .\n.Pp\nIf the file supports seek, the source can be used to open a zip archive from.\n.Pp\nThe file is opened and read when the data from the source is used, usually by\n.Fn zip_close\nor\n.Fn zip_open_from_source .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_win32a\nand\n.Fn zip_source_win32a_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar fname ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_OPEN\nOpening\n.Ar fname\nfailed.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_file 3 ,\n.Xr zip_source_win32handle 3 ,\n.Xr zip_source_win32w 3\n.Sh HISTORY\n.Fn zip_source_win32a\nand\n.Fn zip_source_win32a_create\nwere added in libzip 1.0.\n.Pp\n.Dv ZIP_LENGTH_TO_END\nand\n.Dv ZIP_LENGTH_UNCHECKED\nwere added in libzip 1.10.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32handle.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_win32handle.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_handle.mdoc -- create data source from a Windows file handle\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_WIN32HANDLE\" \"3\" \"May 14, 2024\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_win32handle\\fR,\n\\fBzip_source_win32handle_create\\fR\n\\- create data source from a Windows file handle\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32handle\\fR(\\fIzip_t\\ *archive\\fR, \\fIHANDLE\\ h\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32handle_create\\fR(\\fIHANDLE\\ h\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_win32handle\\fR()\nand\n\\fBzip_source_win32handle_create\\fR()\ncreate a zip source from a Windows file handle.\nThey read\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nfrom it.\nIf\n\\fIlen\\fR\nis 0 or \\-1, the whole file (starting from\n\\fIstart\\fR)\nis used.\n.PP\nIf the file supports seek, the source can be used to open a zip archive from.\n.PP\nThe file is opened and read when the data from the source is used, usually by\n\\fBzip_close\\fR()\nor\n\\fBzip_open_from_source\\fR().\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_w32handle\\fR()\nand\n\\fBzip_source_w32handle_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIh\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5),\nzip_source_win32a(3),\nzip_source_win32w(3)\n.SH \"HISTORY\"\n\\fBzip_source_win32handle\\fR()\nand\n\\fBzip_source_win32handle_create\\fR()\nwere added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32handle.mdoc",
    "content": ".\\\" zip_source_handle.mdoc -- create data source from a Windows file handle\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd May 14, 2024\n.Dt ZIP_SOURCE_WIN32HANDLE 3\n.Os\n.Sh NAME\n.Nm zip_source_win32handle ,\n.Nm zip_source_win32handle_create\n.Nd create data source from a Windows file handle\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_win32handle \"zip_t *archive\" \"HANDLE h\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_win32handle_create \"HANDLE h\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_win32handle\nand\n.Fn zip_source_win32handle_create\ncreate a zip source from a Windows file handle.\nThey read\n.Ar len\nbytes from offset\n.Ar start\nfrom it.\nIf\n.Ar len\nis 0 or \\-1, the whole file (starting from\n.Ar start )\nis used.\n.Pp\nIf the file supports seek, the source can be used to open a zip archive from.\n.Pp\nThe file is opened and read when the data from the source is used, usually by\n.Fn zip_close\nor\n.Fn zip_open_from_source .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_w32handle\nand\n.Fn zip_source_w32handle_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar h ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_win32a 3 ,\n.Xr zip_source_win32w 3\n.Sh HISTORY\n.Fn zip_source_win32handle\nand\n.Fn zip_source_win32handle_create\nwere added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32w.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_win32w.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_win32w.mdoc -- create data source using a win32 Unicode name\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_WIN32W\" \"3\" \"June 30, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_win32w\\fR,\n\\fBzip_source_win32w_create\\fR\n\\- create data source from a Windows Unicode file name\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32w\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ wchar_t\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_win32w_create\\fR(\\fIconst\\ wchar_t\\ *fname\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_win32w\\fR()\nand\n\\fBzip_source_win32w_create\\fR()\ncreate a zip source on Windows using a Windows Unicode name.\nThey open\n\\fIfname\\fR\nand read\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nfrom it.\nFor a description of the\n\\fIlen\\fR\nargument, see\nzip_source_file(3).\n.PP\nIf the file supports seek, the source can be used to open a zip archive from.\n.PP\nThe file is opened and read when the data from the source is used, usually by\n\\fBzip_close\\fR()\nor\n\\fBzip_open_from_source\\fR().\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_win32w\\fR()\nand\n\\fBzip_source_win32w_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIfname\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.TP 19n\n[\\fRZIP_ER_OPEN\\fR]\nOpening\n\\fIfname\\fR\nfailed.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5),\nzip_source_file(3),\nzip_source_win32a(3),\nzip_source_win32handle(3)\n.SH \"HISTORY\"\n\\fBzip_source_win32w\\fR()\nwas added in libzip 1.0.\n.PP\n\\fRZIP_LENGTH_TO_END\\fR\nand\n\\fRZIP_LENGTH_UNCHECKED\\fR\nwere added in libzip 1.10.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_win32w.mdoc",
    "content": ".\\\" zip_source_win32w.mdoc -- create data source using a win32 Unicode name\n.\\\" Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd June 30, 2023\n.Dt ZIP_SOURCE_WIN32W 3\n.Os\n.Sh NAME\n.Nm zip_source_win32w ,\n.Nm zip_source_win32w_create\n.Nd create data source from a Windows Unicode file name\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_win32w \"zip_t *archive\" \"const wchar_t *fname\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_win32w_create \"const wchar_t *fname\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_win32w\nand\n.Fn zip_source_win32w_create\ncreate a zip source on Windows using a Windows Unicode name.\nThey open\n.Ar fname\nand read\n.Ar len\nbytes from offset\n.Ar start\nfrom it.\nFor a description of the\n.Ar len\nargument, see\n.Xr zip_source_file 3 .\n.Pp\nIf the file supports seek, the source can be used to open a zip archive from.\n.Pp\nThe file is opened and read when the data from the source is used, usually by\n.Fn zip_close\nor\n.Fn zip_open_from_source .\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_win32w\nand\n.Fn zip_source_win32w_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar fname ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.It Bq Er ZIP_ER_OPEN\nOpening\n.Ar fname\nfailed.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_file 3 ,\n.Xr zip_source_win32a 3 ,\n.Xr zip_source_win32handle 3\n.Sh HISTORY\n.Fn zip_source_win32w\nwas added in libzip 1.0.\n.Pp\n.Dv ZIP_LENGTH_TO_END\nand\n.Dv ZIP_LENGTH_UNCHECKED\nwere added in libzip 1.10.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_window_create.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_window_create.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_window_create.mdoc -- create zip data source overlay\n.\\\" Copyright (C) 2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_WINDOW_CREATE\" \"3\" \"April 29, 2021\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_window_create\\fR\n\\- create zip data source overlay\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_window_create\\fR(\\fIzip_source_t\\ *source\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_source_window_create\\fR()\nfunction create a zip source from an underlying zip source,\nrestricting access to a particular window starting at byte\n\\fIstart\\fR\nand having size\n\\fIlen\\fR.\nIf\n\\fIlen\\fR\nis \\-1, the window spans to the end of the underlying source.\n.PP\n\\fBzip_source_window\\fR()\nand\n\\fBzip_source_window_create\\fR()\ndon't take ownership of\n\\fIsource\\fR.\nThe caller is responsible for freeing it.\n(This is different to other layered sources.)\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_window_create\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIsrc\\fR\nis\n\\fRNULL\\fR;\nthere is an integer overflow adding\n\\fIstart\\fR\nand\n\\fIlen\\fR;\nor\n\\fIlen\\fR\nis less than \\-1.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_window_create\\fR()\nwas added in libzip 1.8.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_window_create.mdoc",
    "content": ".\\\" zip_source_window_create.mdoc -- create zip data source overlay\n.\\\" Copyright (C) 2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd April 29, 2021\n.Dt ZIP_SOURCE_WINDOW_CREATE 3\n.Os\n.Sh NAME\n.Nm zip_source_window_create\n.Nd create zip data source overlay\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_window_create \"zip_source_t *source\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe\n.Fn zip_source_window_create\nfunction create a zip source from an underlying zip source,\nrestricting access to a particular window starting at byte\n.Ar start\nand having size\n.Ar len .\nIf\n.Ar len\nis \\-1, the window spans to the end of the underlying source.\n.Pp\n.Fn zip_source_window\nand\n.Fn zip_source_window_create\ndon't take ownership of\n.Ar source .\nThe caller is responsible for freeing it.\n(This is different to other layered sources.)\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_window_create\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_INVAL\n.Ar src\nis\n.Dv NULL ;\nthere is an integer overflow adding\n.Ar start\nand\n.Ar len ;\nor\n.Ar len\nis less than \\-1.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_window_create\nwas added in libzip 1.8.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_write.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_write.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_write.mdoc -- write data to zip source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_WRITE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_write\\fR\n\\- write data to zip source\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_int64_t\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_write\\fR(\\fIzip_source_t\\ *source\\fR, \\fIconst\\ void\\ *data\\fR, \\fIzip_uint64_t\\ len\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe function\n\\fBzip_source_write\\fR()\nwrites\n\\fIlen\\fR\nbytes from the buffer\n\\fIdata\\fR\nto the zip source\n\\fIsource\\fR\nat the current write offset.\n.PP\nThe zip source\n\\fIsource\\fR\nhas to be prepared for writing by calling\nzip_source_begin_write(3)\nfirst.\n.SH \"RETURN VALUES\"\nUpon successful completion the number of bytes written is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIsource\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_source(5),\nzip_source_begin_write(3),\nzip_source_commit_write(3),\nzip_source_rollback_write(3),\nzip_source_seek_write(3),\nzip_source_tell_write(3)\n.SH \"HISTORY\"\n\\fBzip_source_write\\fR()\nwas added in libzip 1.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_write.mdoc",
    "content": ".\\\" zip_source_write.mdoc -- write data to zip source\n.\\\" Copyright (C) 2014-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_SOURCE_WRITE 3\n.Os\n.Sh NAME\n.Nm zip_source_write\n.Nd write data to zip source\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_int64_t\n.Fn zip_source_write \"zip_source_t *source\" \"const void *data\" \"zip_uint64_t len\"\n.Sh DESCRIPTION\nThe function\n.Fn zip_source_write\nwrites\n.Ar len\nbytes from the buffer\n.Ar data\nto the zip source\n.Ar source\nat the current write offset.\n.Pp\nThe zip source\n.Ar source\nhas to be prepared for writing by calling\n.Xr zip_source_begin_write 3\nfirst.\n.Sh RETURN VALUES\nUpon successful completion the number of bytes written is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar source\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_source 5 ,\n.Xr zip_source_begin_write 3 ,\n.Xr zip_source_commit_write 3 ,\n.Xr zip_source_rollback_write 3 ,\n.Xr zip_source_seek_write 3 ,\n.Xr zip_source_tell_write 3\n.Sh HISTORY\n.Fn zip_source_write\nwas added in libzip 1.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_zip.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_zip.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_zip.mdoc -- create data source from zip file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_ZIP\" \"3\" \"January 23, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_zip\\fR,\n\\fBzip_source_zip_create\\fR\n\\- create data source from zip file (obsolete interface)\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_zip\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_t\\ *srcarchive\\fR, \\fIzip_uint64_t\\ srcidx\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_zip_create\\fR(\\fIzip_t\\ *srcarchive\\fR, \\fIzip_uint64_t\\ srcidx\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ len\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_zip\\fR()\nand\n\\fBzip_source_zip_create\\fR()\nare the obsolete versions of\nzip_source_zip_file(3)\nor\nzip_source_zip_file_create(3)\nrespectively.\nIf you want to get the compressed data of the complete file, use\n.RS 6n\nzip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL)\n.RE\n.PP\nThe functions\n\\fBzip_source_zip\\fR()\nand\n\\fBzip_source_zip_create\\fR()\ncreate a zip source from a file in a zip archive.\nThe\n\\fIsrcarchive\\fR\nargument is the (open) zip archive containing the source zip file\nat index\n\\fIsrcidx\\fR.\n\\fIlen\\fR\nbytes from offset\n\\fIstart\\fR\nwill be used in the zip_source.\nIf\n\\fIlen\\fR\nis 0 or \\-1, the rest of the file, starting from\n\\fIstart\\fR,\nis used.\nIf\n\\fIstart\\fR\nis zero and\n\\fIlen\\fR\nis \\-1, the whole file will be copied without decompressing it.\n.PP\nSupported flags are:\n.TP 14n\n\\fRZIP_FL_UNCHANGED\\fR\nTry to get the original data without any changes that may have been\nmade to\n\\fIsrcarchive\\fR\nafter opening it.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_zip\\fR()\nand\n\\fBzip_source_zip_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_CHANGED\\fR]\nUnchanged data was requested, but it is not available.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIsrcarchive\\fR,\n\\fIsrcidx\\fR,\n\\fIstart\\fR,\nor\n\\fIlen\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.PD 0\n.PP\nAdditionally, it can return all error codes from\n\\fBzip_stat_index\\fR()\nand\n\\fBzip_fopen_index\\fR().\n.PD\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_zip\\fR()\nwas added in libzip 1.0.\n\\fBzip_source_zip_create\\fR()\nwas added in libzip 1.8.0.\nBoth were deprecated in libzip 1.10.0.\nUse\n\\fBzip_source_zip_file\\fR()\nor\n\\fBzip_source_zip_file_create\\fR()\ninstead.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_zip.mdoc",
    "content": ".\\\" zip_source_zip.mdoc -- create data source from zip file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 23, 2023\n.Dt ZIP_SOURCE_ZIP 3\n.Os\n.Sh NAME\n.Nm zip_source_zip ,\n.Nm zip_source_zip_create\n.Nd create data source from zip file (obsolete interface)\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_zip \"zip_t *archive\" \"zip_t *srcarchive\" \"zip_uint64_t srcidx\" \"zip_flags_t flags\" \"zip_uint64_t start\" \"zip_int64_t len\"\n.Ft zip_source_t *\n.Fn zip_source_zip_create \"zip_t *srcarchive\" \"zip_uint64_t srcidx\" \"zip_flags_t flags\" \"zip_uint64_t start\" \"zip_int64_t len\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_zip\nand\n.Fn zip_source_zip_create\nare the obsolete versions of\n.Xr zip_source_zip_file 3\nor\n.Xr zip_source_zip_file_create 3\nrespectively.\nIf you want to get the compressed data of the complete file, use\n.Dl zip_source_zip_file(za, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL)\n.Pp\nThe functions\n.Fn zip_source_zip\nand\n.Fn zip_source_zip_create\ncreate a zip source from a file in a zip archive.\nThe\n.Ar srcarchive\nargument is the (open) zip archive containing the source zip file\nat index\n.Ar srcidx .\n.Ar len\nbytes from offset\n.Ar start\nwill be used in the zip_source.\nIf\n.Ar len\nis 0 or \\-1, the rest of the file, starting from\n.Ar start ,\nis used.\nIf\n.Ar start\nis zero and\n.Ar len\nis \\-1, the whole file will be copied without decompressing it.\n.Pp\nSupported flags are:\n.Bl -tag -width Dv\n.It Dv ZIP_FL_UNCHANGED\nTry to get the original data without any changes that may have been\nmade to\n.Ar srcarchive\nafter opening it.\n.El\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_zip\nand\n.Fn zip_source_zip_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_CHANGED\nUnchanged data was requested, but it is not available.\n.It Bq Er ZIP_ER_INVAL\n.Ar srcarchive ,\n.Ar srcidx ,\n.Ar start ,\nor\n.Ar len\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\nAdditionally, it can return all error codes from\n.Fn zip_stat_index\nand\n.Fn zip_fopen_index .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_zip\nwas added in libzip 1.0.\n.Fn zip_source_zip_create\nwas added in libzip 1.8.0.\nBoth were deprecated in libzip 1.10.0.\nUse\n.Fn zip_source_zip_file\nor\n.Fn zip_source_zip_file_create\ninstead.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_source_zip_file.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_source_zip_file.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_source_zip_file.mdoc -- create data source from zip file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_SOURCE_ZIP_FILE\" \"3\" \"March 10, 2023\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_source_zip_file\\fR,\n\\fBzip_source_zip_file_create\\fR\n\\- create data source from zip file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_zip_file\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_t\\ *srcarchive\\fR, \\fIzip_uint64_t\\ srcidx\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ length\\fR, \\fIconst\\ char\\ *password\\fR);\n.PD\n.PP\n\\fIzip_source_t *\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_source_zip_file_create\\fR(\\fIzip_t\\ *srcarchive\\fR, \\fIzip_uint64_t\\ srcidx\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_uint64_t\\ start\\fR, \\fIzip_int64_t\\ length\\fR, \\fIconst\\ char\\ *password\\fR, \\fIzip_error_t\\ *error\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe functions\n\\fBzip_source_zip_file\\fR()\nand\n\\fBzip_source_zip_file_create\\fR()\ncreate a zip source from a file in a zip archive.\nThe\n\\fIsrcarchive\\fR\nargument is the (open) zip archive containing the source zip file\nat index\n\\fIsrcidx\\fR.\n\\fIlength\\fR\nbytes from offset\n\\fIstart\\fR\nwill be used in the zip_source.\nIf\n\\fIlength\\fR\nis \\-1, the rest of the file, starting from\n\\fIstart\\fR,\nis used.\n.PP\nIf you intend to copy a file from one archive to another, using the flag\n\\fRZIP_FL_COMPRESSED\\fR\nis more efficient, as it avoids recompressing the file data.\n.PP\nSupported flags are:\n.TP 22n\n\\fRZIP_FL_COMPRESSED\\fR\nGet the compressed data.\nThis is only supported if the complete file data is requested\n(\\fIstart\\fR\n== 0 and\n\\fIlength\\fR\n== \\-1).\nThis is not supported for changed data.\nDefault is uncompressed.\n.TP 22n\n\\fRZIP_FL_ENCRYPTED\\fR\nGet the encrypted data.\n(This flag implies\n\\fRZIP_FL_COMPRESSED\\fR.)\nThis is only supported if the complete file data is requested\n(\\fIstart\\fR\n== 0 and\n\\fIlength\\fR\n== \\-1).\nDefault is decrypted.\n.TP 22n\n\\fRZIP_FL_UNCHANGED\\fR\nTry to get the original data without any changes that may have been\nmade to\n\\fIsrcarchive\\fR\nafter opening it.\n.SH \"RETURN VALUES\"\nUpon successful completion, the created source is returned.\nOtherwise,\n\\fRNULL\\fR\nis returned and the error code in\n\\fIarchive\\fR\nor\n\\fIerror\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_source_zip_file\\fR()\nand\n\\fBzip_source_zip_file_create\\fR()\nfail if:\n.TP 19n\n[\\fRZIP_ER_CHANGED\\fR]\nUnchanged data was requested, but it is not available.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIsrcarchive\\fR,\n\\fIsrcidx\\fR,\n\\fIstart\\fR,\nor\n\\fIlength\\fR\nare invalid.\n.TP 19n\n[\\fRZIP_ER_MEMORY\\fR]\nRequired memory could not be allocated.\n.PD 0\n.PP\nAdditionally, it can return all error codes from\n\\fBzip_stat_index\\fR()\nand\n\\fBzip_fopen_index\\fR().\n.PD\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_file_add(3),\nzip_file_replace(3),\nzip_source(5)\n.SH \"HISTORY\"\n\\fBzip_source_zip_file\\fR()\nand\n\\fBzip_source_zip_file_create\\fR()\nwere added in libzip 1.10.0.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_source_zip_file.mdoc",
    "content": ".\\\" zip_source_zip_file.mdoc -- create data source from zip file\n.\\\" Copyright (C) 2004-2021 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 10, 2023\n.Dt ZIP_SOURCE_ZIP_FILE 3\n.Os\n.Sh NAME\n.Nm zip_source_zip_file ,\n.Nm zip_source_zip_file_create\n.Nd create data source from zip file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft zip_source_t *\n.Fn zip_source_zip_file \"zip_t *archive\" \"zip_t *srcarchive\" \"zip_uint64_t srcidx\" \"zip_flags_t flags\" \"zip_uint64_t start\" \"zip_int64_t length\" \"const char *password\"\n.Ft zip_source_t *\n.Fn zip_source_zip_file_create \"zip_t *srcarchive\" \"zip_uint64_t srcidx\" \"zip_flags_t flags\" \"zip_uint64_t start\" \"zip_int64_t length\" \"const char *password\" \"zip_error_t *error\"\n.Sh DESCRIPTION\nThe functions\n.Fn zip_source_zip_file\nand\n.Fn zip_source_zip_file_create\ncreate a zip source from a file in a zip archive.\nThe\n.Ar srcarchive\nargument is the (open) zip archive containing the source zip file\nat index\n.Ar srcidx .\n.Ar length\nbytes from offset\n.Ar start\nwill be used in the zip_source.\nIf\n.Ar length\nis \\-1, the rest of the file, starting from\n.Ar start ,\nis used.\n.Pp\nIf you intend to copy a file from one archive to another, using the flag\n.Dv ZIP_FL_COMPRESSED\nis more efficient, as it avoids recompressing the file data.\n.Pp\nSupported flags are:\n.Bl -tag -width 20n\n.It Dv ZIP_FL_COMPRESSED\nGet the compressed data.\nThis is only supported if the complete file data is requested\n.Ar ( start\n== 0 and\n.Ar length\n== \\-1).\nThis is not supported for changed data.\nDefault is uncompressed.\n.It Dv ZIP_FL_ENCRYPTED\nGet the encrypted data.\n(This flag implies\n.Dv ZIP_FL_COMPRESSED . )\nThis is only supported if the complete file data is requested\n.Ar ( start\n== 0 and\n.Ar length\n== \\-1).\nDefault is decrypted.\n.It Dv ZIP_FL_UNCHANGED\nTry to get the original data without any changes that may have been\nmade to\n.Ar srcarchive\nafter opening it.\n.El\n.Sh RETURN VALUES\nUpon successful completion, the created source is returned.\nOtherwise,\n.Dv NULL\nis returned and the error code in\n.Ar archive\nor\n.Ar error\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_source_zip_file\nand\n.Fn zip_source_zip_file_create\nfail if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_CHANGED\nUnchanged data was requested, but it is not available.\n.It Bq Er ZIP_ER_INVAL\n.Ar srcarchive ,\n.Ar srcidx ,\n.Ar start ,\nor\n.Ar length\nare invalid.\n.It Bq Er ZIP_ER_MEMORY\nRequired memory could not be allocated.\n.El\nAdditionally, it can return all error codes from\n.Fn zip_stat_index\nand\n.Fn zip_fopen_index .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_file_add 3 ,\n.Xr zip_file_replace 3 ,\n.Xr zip_source 5\n.Sh HISTORY\n.Fn zip_source_zip_file\nand\n.Fn zip_source_zip_file_create\nwere added in libzip 1.10.0.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_stat.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_stat.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_stat.mdoc -- get information about file\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_STAT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_stat\\fR,\n\\fBzip_stat_index\\fR\n\\- get information about file\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_stat\\fR(\\fIzip_t\\ *archive\\fR, \\fIconst\\ char\\ *fname\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_stat_t\\ *sb\\fR);\n.PD\n.PP\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_stat_index\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR, \\fIzip_flags_t\\ flags\\fR, \\fIzip_stat_t\\ *sb\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_stat\\fR()\nfunction obtains information about the file named\n\\fIfname\\fR\nin\n\\fIarchive\\fR.\nThe\n\\fIflags\\fR\nargument specifies how the name lookup should be done.\nIts values are described in\nzip_name_locate(3).\nAlso,\n\\fRZIP_FL_UNCHANGED\\fR\nmay be\n\\fIor\\fR'ed\nto it to request information about the original file in the archive,\nignoring any changes made.\n.PP\nThe\n\\fBzip_stat_index\\fR()\nfunction obtains information about the file at position\n\\fIindex\\fR.\n.PP\nThe\n\\fIsb\\fR\nargument is a pointer to a\n\\fIstruct zip_stat\\fR\n(shown below), into which information about the file is placed.\n.nf\n.sp\n.RS 0n\nstruct zip_stat {\n    zip_uint64_t valid;                 /* which fields have valid values */\n    const char *name;                   /* name of the file */\n    zip_uint64_t index;                 /* index within archive */\n    zip_uint64_t size;                  /* size of file (uncompressed) */\n    zip_uint64_t comp_size;             /* size of file (compressed) */\n    time_t mtime;                       /* modification time */\n    zip_uint32_t crc;                   /* crc of file data */\n    zip_uint16_t comp_method;           /* compression method used */\n    zip_uint16_t encryption_method;     /* encryption method used */\n    zip_uint32_t flags;                 /* reserved for future use */\n};\n.RE\n.fi\nThe structure pointed to by\n\\fIsb\\fR\nmust be allocated before calling\n\\fBzip_stat\\fR()\nor\n\\fBzip_stat_index\\fR().\n.PP\nThe\n\\fIvalid\\fR\nfield of the structure specifies which other fields are valid.\nCheck if the flag defined by the following defines are in\n\\fIvalid\\fR\nbefore accessing the fields:\n.RS 6n\n.PD 0\n.TP 30n\n\\fRZIP_STAT_NAME\\fR\n\\fIname\\fR\n.TP 30n\n\\fRZIP_STAT_INDEX\\fR\n\\fIindex\\fR\n.TP 30n\n\\fRZIP_STAT_SIZE\\fR\n\\fIsize\\fR\n.TP 30n\n\\fRZIP_STAT_COMP_SIZE\\fR\n\\fIcomp_size\\fR\n.TP 30n\n\\fRZIP_STAT_MTIME\\fR\n\\fImtime\\fR\n.TP 30n\n\\fRZIP_STAT_CRC\\fR\n\\fIcrc\\fR\n.TP 30n\n\\fRZIP_STAT_COMP_METHOD\\fR\n\\fIcomp_method\\fR\n.TP 30n\n\\fRZIP_STAT_ENCRYPTION_METHOD\\fR\n\\fIencryption_method\\fR\n.TP 30n\n\\fRZIP_STAT_FLAGS\\fR\n\\fIflags\\fR\n.RE\n.PD\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\nThe function\n\\fBzip_stat\\fR()\ncan fail for any of the errors specified for the routine\nzip_name_locate(3).\n.PP\nThe function\n\\fBzip_stat_index\\fR()\nfails and sets the error information to\n\\fRZIP_ER_INVAL\\fR\nif\n\\fIindex\\fR\nis invalid.\nIf\n\\fRZIP_FL_UNCHANGED\\fR\nis not set and no information can be obtained from the source\ncallback, the error information is set to\n\\fRZIP_ER_CHANGED\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_get_num_entries(3),\nzip_name_locate(3),\nzip_stat_init(3)\n.SH \"HISTORY\"\n\\fBzip_stat\\fR()\nwas added in libzip 0.6.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.PP\n\\fBzip_stat_index\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\nIn libzip 0.11 the type of\n\\fIflags\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_flags_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_stat.mdoc",
    "content": ".\\\" zip_stat.mdoc -- get information about file\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_STAT 3\n.Os\n.Sh NAME\n.Nm zip_stat ,\n.Nm zip_stat_index\n.Nd get information about file\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_stat \"zip_t *archive\" \"const char *fname\" \"zip_flags_t flags\" \"zip_stat_t *sb\"\n.Ft int\n.Fn zip_stat_index \"zip_t *archive\" \"zip_uint64_t index\" \"zip_flags_t flags\" \"zip_stat_t *sb\"\n.Sh DESCRIPTION\nThe\n.Fn zip_stat\nfunction obtains information about the file named\n.Ar fname\nin\n.Ar archive .\nThe\n.Ar flags\nargument specifies how the name lookup should be done.\nIts values are described in\n.Xr zip_name_locate 3 .\nAlso,\n.Dv ZIP_FL_UNCHANGED\nmay be\n.Em or Ns No 'ed\nto it to request information about the original file in the archive,\nignoring any changes made.\n.Pp\nThe\n.Fn zip_stat_index\nfunction obtains information about the file at position\n.Ar index .\n.Pp\nThe\n.Ar sb\nargument is a pointer to a\n.Ft struct zip_stat\n(shown below), into which information about the file is placed.\n.Bd -literal\nstruct zip_stat {\n    zip_uint64_t valid;                 /* which fields have valid values */\n    const char *name;                   /* name of the file */\n    zip_uint64_t index;                 /* index within archive */\n    zip_uint64_t size;                  /* size of file (uncompressed) */\n    zip_uint64_t comp_size;             /* size of file (compressed) */\n    time_t mtime;                       /* modification time */\n    zip_uint32_t crc;                   /* crc of file data */\n    zip_uint16_t comp_method;           /* compression method used */\n    zip_uint16_t encryption_method;     /* encryption method used */\n    zip_uint32_t flags;                 /* reserved for future use */\n};\n.Ed\nThe structure pointed to by\n.Ar sb\nmust be allocated before calling\n.Fn zip_stat\nor\n.Fn zip_stat_index .\n.Pp\nThe\n.Ar valid\nfield of the structure specifies which other fields are valid.\nCheck if the flag defined by the following defines are in\n.Ar valid\nbefore accessing the fields:\n.Bl -tag -width ZIP_STAT_ENCRYPTION_METHODXX -compact -offset indent\n.It Dv ZIP_STAT_NAME\n.Ar name\n.It Dv ZIP_STAT_INDEX\n.Ar index\n.It Dv ZIP_STAT_SIZE\n.Ar size\n.It Dv ZIP_STAT_COMP_SIZE\n.Ar comp_size\n.It Dv ZIP_STAT_MTIME\n.Ar mtime\n.It Dv ZIP_STAT_CRC\n.Ar crc\n.It Dv ZIP_STAT_COMP_METHOD\n.Ar comp_method\n.It Dv ZIP_STAT_ENCRYPTION_METHOD\n.Ar encryption_method\n.It Dv ZIP_STAT_FLAGS\n.Ar flags\n.El\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error information in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\nThe function\n.Fn zip_stat\ncan fail for any of the errors specified for the routine\n.Xr zip_name_locate 3 .\n.Pp\nThe function\n.Fn zip_stat_index\nfails and sets the error information to\n.Er ZIP_ER_INVAL\nif\n.Ar index\nis invalid.\nIf\n.Dv ZIP_FL_UNCHANGED\nis not set and no information can be obtained from the source\ncallback, the error information is set to\n.Er ZIP_ER_CHANGED .\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_get_num_entries 3 ,\n.Xr zip_name_locate 3 ,\n.Xr zip_stat_init 3\n.Sh HISTORY\n.Fn zip_stat\nwas added in libzip 0.6.\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Pp\n.Fn zip_stat_index\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\nIn libzip 0.11 the type of\n.Ar flags\nwas changed from\n.Vt int\nto\n.Vt zip_flags_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_stat_init.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_stat_init.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_stat_init.mdoc -- init zip_stat structure\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_STAT_INIT\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_stat_init\\fR\n\\- initialize zip_stat structure\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIvoid\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_stat_init\\fR(\\fIzip_stat_t\\ *sb\\fR);\n.PD\n.SH \"DESCRIPTION\"\nThe\n\\fBzip_stat_init\\fR()\nfunction initializes the members of a struct zip_stat.\nThe current members are described in\nzip_stat(3),\nbut this function should be used to initialize it to\nmake sure none are missed.\nThe structure pointed to by\n\\fIsb\\fR\nmust be allocated before calling\n\\fBzip_stat_init\\fR().\n.PP\nThis function should be used by functions provided to\nzip_source_function(3)\nwhen returning\n\\fRZIP_SOURCE_STAT\\fR\ninformation to make sure all fields are initialized.\n.SH \"RETURN VALUES\"\nIf\n\\fIsb\\fR\nis valid, the function is always successful.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_stat(3)\n.SH \"HISTORY\"\n\\fBzip_stat_init\\fR()\nwas added in libzip 0.8.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_stat_init.mdoc",
    "content": ".\\\" zip_stat_init.mdoc -- init zip_stat structure\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_STAT_INIT 3\n.Os\n.Sh NAME\n.Nm zip_stat_init\n.Nd initialize zip_stat structure\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft void\n.Fn zip_stat_init \"zip_stat_t *sb\"\n.Sh DESCRIPTION\nThe\n.Fn zip_stat_init\nfunction initializes the members of a struct zip_stat.\nThe current members are described in\n.Xr zip_stat 3 ,\nbut this function should be used to initialize it to\nmake sure none are missed.\nThe structure pointed to by\n.Ar sb\nmust be allocated before calling\n.Fn zip_stat_init .\n.Pp\nThis function should be used by functions provided to\n.Xr zip_source_function 3\nwhen returning\n.Dv ZIP_SOURCE_STAT\ninformation to make sure all fields are initialized.\n.Sh RETURN VALUES\nIf\n.Ar sb\nis valid, the function is always successful.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_stat 3\n.Sh HISTORY\n.Fn zip_stat_init\nwas added in libzip 0.8.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_unchange.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_unchange.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_unchange.mdoc -- undo changes to file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_UNCHANGE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_unchange\\fR\n\\- undo changes to file in zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_unchange\\fR(\\fIzip_t\\ *archive\\fR, \\fIzip_uint64_t\\ index\\fR);\n.PD\n.SH \"DESCRIPTION\"\nChanges to the file at position\n\\fIindex\\fR\nare reverted.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"ERRORS\"\n\\fBzip_unchange\\fR()\nfails if:\n.TP 19n\n[\\fRZIP_ER_EXISTS\\fR]\nUnchanging the name would result in a duplicate name in the archive.\n.TP 19n\n[\\fRZIP_ER_INVAL\\fR]\n\\fIindex\\fR\nis not a valid file index in\n\\fIzip\\fR.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_unchange_all(3),\nzip_unchange_archive(3)\n.SH \"HISTORY\"\n\\fBzip_unchange\\fR()\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n\\fIindex\\fR\nwas changed from\n\\fIint\\fR\nto\n\\fIzip_uint64_t\\fR.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_unchange.mdoc",
    "content": ".\\\" zip_unchange.mdoc -- undo changes to file in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_UNCHANGE 3\n.Os\n.Sh NAME\n.Nm zip_unchange\n.Nd undo changes to file in zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_unchange \"zip_t *archive\" \"zip_uint64_t index\"\n.Sh DESCRIPTION\nChanges to the file at position\n.Ar index\nare reverted.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh ERRORS\n.Fn zip_unchange\nfails if:\n.Bl -tag -width Er\n.It Bq Er ZIP_ER_EXISTS\nUnchanging the name would result in a duplicate name in the archive.\n.It Bq Er ZIP_ER_INVAL\n.Ar index\nis not a valid file index in\n.Ar zip .\n.El\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_unchange_all 3 ,\n.Xr zip_unchange_archive 3\n.Sh HISTORY\n.Fn zip_unchange\nwas added in libzip 0.6.\nIn libzip 0.10 the type of\n.Ar index\nwas changed from\n.Vt int\nto\n.Vt zip_uint64_t .\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_unchange_all.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_unchange_all.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_unchange_all.mdoc -- undo changes to all files in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_UNCHANGE_ALL\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_unchange_all\\fR\n\\- undo all changes in a zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_unchange_all\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nAll changes to files and global information in\n\\fIarchive\\fR\nare reverted.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_unchange(3),\nzip_unchange_archive(3)\n.SH \"HISTORY\"\n\\fBzip_unchange_all\\fR()\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_unchange_all.mdoc",
    "content": ".\\\" zip_unchange_all.mdoc -- undo changes to all files in zip archive\n.\\\" Copyright (C) 2003-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_UNCHANGE_ALL 3\n.Os\n.Sh NAME\n.Nm zip_unchange_all\n.Nd undo all changes in a zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_unchange_all \"zip_t *archive\"\n.Sh DESCRIPTION\nAll changes to files and global information in\n.Ar archive\nare reverted.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_unchange 3 ,\n.Xr zip_unchange_archive 3\n.Sh HISTORY\n.Fn zip_unchange_all\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zip_unchange_archive.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zip_unchange_archive.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zip_unchange_archive.mdoc -- undo changes to all files in zip archive\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIP_UNCHANGE_ARCHIVE\" \"3\" \"December 18, 2017\" \"NiH\" \"Library Functions Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzip_unchange_archive\\fR\n\\- undo global changes to zip archive\n.SH \"LIBRARY\"\nlibzip (-lzip)\n.SH \"SYNOPSIS\"\n\\fB#include <zip.h>\\fR\n.sp\n\\fIint\\fR\n.br\n.PD 0\n.HP 4n\n\\fBzip_unchange_archive\\fR(\\fIzip_t\\ *archive\\fR);\n.PD\n.SH \"DESCRIPTION\"\nRevert all global changes to the archive\n\\fIarchive\\fR.\nThis reverts changes to the archive comment and global flags.\n.SH \"RETURN VALUES\"\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n\\fIarchive\\fR\nis set to indicate the error.\n.SH \"SEE ALSO\"\nlibzip(3),\nzip_unchange(3),\nzip_unchange_all(3)\n.SH \"HISTORY\"\n\\fBzip_unchange_archive\\fR()\nwas added in libzip 0.7.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zip_unchange_archive.mdoc",
    "content": ".\\\" zip_unchange_archive.mdoc -- undo changes to all files in zip archive\n.\\\" Copyright (C) 2006-2017 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd December 18, 2017\n.Dt ZIP_UNCHANGE_ARCHIVE 3\n.Os\n.Sh NAME\n.Nm zip_unchange_archive\n.Nd undo global changes to zip archive\n.Sh LIBRARY\nlibzip (-lzip)\n.Sh SYNOPSIS\n.In zip.h\n.Ft int\n.Fn zip_unchange_archive \"zip_t *archive\"\n.Sh DESCRIPTION\nRevert all global changes to the archive\n.Ar archive .\nThis reverts changes to the archive comment and global flags.\n.Sh RETURN VALUES\nUpon successful completion 0 is returned.\nOtherwise, \\-1 is returned and the error code in\n.Ar archive\nis set to indicate the error.\n.Sh SEE ALSO\n.Xr libzip 3 ,\n.Xr zip_unchange 3 ,\n.Xr zip_unchange_all 3\n.Sh HISTORY\n.Fn zip_unchange_archive\nwas added in libzip 0.7.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zipcmp.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zipcmp.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zipcmp.mdoc -- compare zip archives\n.\\\" Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIPCMP\" \"1\" \"March 15, 2024\" \"NiH\" \"General Commands Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzipcmp\\fR\n\\- compare contents of zip archives\n.SH \"SYNOPSIS\"\n.HP 7n\n\\fBzipcmp\\fR\n[\\fB\\-ChipqsTtVv\\fR]\n\\fIarchive1\\ archive2\\fR\n.SH \"DESCRIPTION\"\n\\fBzipcmp\\fR\ncompares the zip archives or directories\n\\fIarchive1\\fR\nand\n\\fIarchive2\\fR\nand checks if they contain the same files, comparing their names,\nuncompressed sizes, and CRCs.\nFile order and compressed size differences are ignored.\n.PP\nSupported options:\n.TP 5n\n\\fB\\-C\\fR\nCheck consistency of archives.\nResults in an error if archive is inconsistent or not valid\naccording to the zip specification.\n.TP 5n\n\\fB\\-h\\fR\nDisplay a short help message and exit.\n.TP 5n\n\\fB\\-i\\fR\nCompare names ignoring case distinctions.\n.TP 5n\n\\fB\\-p\\fR\nEnable paranoid checks.\nCompares extra fields, comments, and other meta data.\n(Automatically disabled if one of the archives is a directory.)\nThese checks are skipped for files where the data differs.\n.TP 5n\n\\fB\\-q\\fR\nQuiet mode.\nCompare\n\\fB\\-v\\fR.\n.TP 5n\n\\fB\\-s\\fR\nPrint a summary of how many files where added and removed.\n.TP 5n\n\\fB\\-T\\fR\nAdditionally compare the time stamps of the entries.\n.TP 5n\n\\fB\\-t\\fR\nTest zip files by comparing the contents to their checksums.\n.TP 5n\n\\fB\\-V\\fR\nDisplay version information and exit.\n.TP 5n\n\\fB\\-v\\fR\nVerbose mode.\nPrint details about differences to stdout.\n(This is the default.)\n.SH \"EXIT STATUS\"\n\\fBzipcmp\\fR\nexits 0 if the two archives contain the same files, 1 if they differ,\nand >1 if an error occurred.\n.SH \"SEE ALSO\"\nzipmerge(1),\nziptool(1),\nlibzip(3)\n.SH \"HISTORY\"\n\\fBzipcmp\\fR\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/zipcmp.mdoc",
    "content": ".\\\" zipcmp.mdoc -- compare zip archives\n.\\\" Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd March 15, 2024\n.Dt ZIPCMP 1\n.Os\n.Sh NAME\n.Nm zipcmp\n.Nd compare contents of zip archives\n.Sh SYNOPSIS\n.Nm\n.Op Fl ChipqsTtVv\n.Ar archive1 archive2\n.Sh DESCRIPTION\n.Nm\ncompares the zip archives or directories\n.Ar archive1\nand\n.Ar archive2\nand checks if they contain the same files, comparing their names,\nuncompressed sizes, and CRCs.\nFile order and compressed size differences are ignored.\n.Pp\nSupported options:\n.Bl -tag -width MMM\n.It Fl C\nCheck consistency of archives.\nResults in an error if archive is inconsistent or not valid\naccording to the zip specification.\n.It Fl h\nDisplay a short help message and exit.\n.It Fl i\nCompare names ignoring case distinctions.\n.It Fl p\nEnable paranoid checks.\nCompares extra fields, comments, and other meta data.\n(Automatically disabled if one of the archives is a directory.)\nThese checks are skipped for files where the data differs.\n.It Fl q\nQuiet mode.\nCompare\n.Fl v .\n.It Fl s\nPrint a summary of how many files where added and removed.\n.It Fl T\nAdditionally compare the time stamps of the entries.\n.It Fl t\nTest zip files by comparing the contents to their checksums.\n.It Fl V\nDisplay version information and exit.\n.It Fl v\nVerbose mode.\nPrint details about differences to stdout.\n(This is the default.)\n.El\n.Sh EXIT STATUS\n.Nm\nexits 0 if the two archives contain the same files, 1 if they differ,\nand >1 if an error occurred.\n.Sh SEE ALSO\n.Xr zipmerge 1 ,\n.Xr ziptool 1 ,\n.Xr libzip 3\n.Sh HISTORY\n.Nm\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/man/zipmerge.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/zipmerge.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" zipmerge.mdoc -- merge zip archives\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIPMERGE\" \"1\" \"November 7, 2023\" \"NiH\" \"General Commands Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBzipmerge\\fR\n\\- merge zip archives\n.SH \"SYNOPSIS\"\n.HP 9n\n\\fBzipmerge\\fR\n[\\fB\\-DhIiSsV\\fR]\n\\fItarget-zip\\fR\n\\fIsource-zip\\fR\\ [\\fIsource-zip\\ ...\\fR]\n.SH \"DESCRIPTION\"\n\\fBzipmerge\\fR\ncopies files from the source zip archives\n\\fIsource-zip\\fR\nto the target zip archive\n\\fItarget-zip\\fR.\nBy default, files in the source zip archives overwrite\nexisting files of the same name in the target zip archive.\nBy default, compressed files in the source archive are\ncopied directly without recompression, uncompressed files\nare compressed using the default compression algorithm.\n.PP\nSupported options:\n.TP 5n\n\\fB\\-D\\fR\nIgnore directory components in file name comparisons.\nThis option is slow for archives with many files.\n.TP 5n\n\\fB\\-h\\fR\nDisplay a short help message and exit.\n.TP 5n\n\\fB\\-I\\fR\nIgnore case in file name comparisons\nThis option is slow for archives with many files.\n.TP 5n\n\\fB\\-i\\fR\nAsk before overwriting files.\nSee also\n\\fB\\-s\\fR.\n.TP 5n\n\\fB\\-k\\fR\nDo not compress files that were uncompressed in\n\\fIsource-zip\\fR,\notherwise they are compressed with the default compression method.\n.TP 5n\n\\fB\\-S\\fR\nDo not overwrite files that have the same name, size, and\nCRC32 in both the source and target archives.\n.TP 5n\n\\fB\\-s\\fR\nWhen\n\\fB\\-i\\fR\nis given, do not ask before overwriting files that have the same name, size,\nand CRC32.\n.TP 5n\n\\fB\\-V\\fR\nDisplay version information and exit.\n.SH \"EXIT STATUS\"\n\\fBzipmerge\\fR\nexits 0 on success and >1 if an error occurred.\n.SH \"SEE ALSO\"\nzipcmp(1),\nziptool(1),\nlibzip(3)\n.SH \"HISTORY\"\n\\fBzipmerge\\fR\nwas added in libzip 0.6.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n.SH \"CAVEATS\"\n\\fBzipmerge\\fR\nuses one open file descriptor per zip archive.\nIf you need to merge a lot of zip archives, check your shell's\nfile descriptor ulimit and either increase it or run\n\\fBzipmerge\\fR\nmultiple times with e.g. 1000 source zip archives each time.\n"
  },
  {
    "path": "external/libzip/man/zipmerge.mdoc",
    "content": ".\\\" zipmerge.mdoc -- merge zip archives\n.\\\" Copyright (C) 2004-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd November 7, 2023\n.Dt ZIPMERGE 1\n.Os\n.Sh NAME\n.Nm zipmerge\n.Nd merge zip archives\n.Sh SYNOPSIS\n.Nm\n.Op Fl DhIiSsV\n.Ar target-zip\n.Ar source-zip Op Ar source-zip ...\n.Sh DESCRIPTION\n.Nm\ncopies files from the source zip archives\n.Ar source-zip\nto the target zip archive\n.Ar target-zip .\nBy default, files in the source zip archives overwrite\nexisting files of the same name in the target zip archive.\nBy default, compressed files in the source archive are\ncopied directly without recompression, uncompressed files\nare compressed using the default compression algorithm.\n.Pp\nSupported options:\n.Bl -tag -width MMM\n.It Fl D\nIgnore directory components in file name comparisons.\nThis option is slow for archives with many files.\n.It Fl h\nDisplay a short help message and exit.\n.It Fl I\nIgnore case in file name comparisons\nThis option is slow for archives with many files.\n.It Fl i\nAsk before overwriting files.\nSee also\n.Fl s .\n.It Fl k\nDo not compress files that were uncompressed in\n.Ar source-zip ,\notherwise they are compressed with the default compression method.\n.It Fl S\nDo not overwrite files that have the same name, size, and\nCRC32 in both the source and target archives.\n.It Fl s\nWhen\n.Fl i\nis given, do not ask before overwriting files that have the same name, size,\nand CRC32.\n.It Fl V\nDisplay version information and exit.\n.El\n.Sh EXIT STATUS\n.Nm\nexits 0 on success and >1 if an error occurred.\n.Sh SEE ALSO\n.Xr zipcmp 1 ,\n.Xr ziptool 1 ,\n.Xr libzip 3\n.Sh HISTORY\n.Nm\nwas added in libzip 0.6.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n.Sh CAVEATS\n.Nm\nuses one open file descriptor per zip archive.\nIf you need to merge a lot of zip archives, check your shell's\nfile descriptor ulimit and either increase it or run\n.Nm\nmultiple times with e.g. 1000 source zip archives each time.\n"
  },
  {
    "path": "external/libzip/man/ziptool.html",
    "content": ""
  },
  {
    "path": "external/libzip/man/ziptool.man",
    "content": ".\\\" Automatically generated from an mdoc input file.  Do not edit.\n.\\\" ziptool.mdoc -- modify zip archives in multiple ways\n.\\\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.TH \"ZIPTOOL\" \"1\" \"January 23, 2023\" \"NiH\" \"General Commands Manual\"\n.nh\n.if n .ad l\n.SH \"NAME\"\n\\fBziptool\\fR\n\\- modify zip archives\n.SH \"SYNOPSIS\"\n.HP 8n\n\\fBziptool\\fR\n[\\fB\\-ceghnrst\\fR]\n[\\fB\\-l\\fR\\ \\fIlength\\fR]\n[\\fB\\-o\\fR\\ \\fIoffset\\fR]\n\\fIzip-archive\\fR\n\\fBcommand\\fR\\ [\\fIcommand-args\\ ...\\fR]\n[\\fBcommand\\fR\\ [\\fIcommand-args\\ ...\\fR]\\ ...]\n.SH \"DESCRIPTION\"\n\\fBziptool\\fR\nmodifies the zip archive\n\\fIzip-archive\\fR\naccording to the\n\\fIcommands\\fR\ngiven.\n.PP\nSupported options:\n.TP 13n\n\\fB\\-c\\fR\nCheck zip archive consistency when opening it.\n.TP 13n\n\\fB\\-e\\fR\nError if archive already exists (only useful with\n\\fB\\-n\\fR).\n.TP 13n\n\\fB\\-g\\fR\nGuess file name encoding (for\n\\fBstat\\fR\ncommand).\n.TP 13n\n\\fB\\-h\\fR\nDisplay help.\n.TP 13n\n\\fB\\-l\\fR \\fIlength\\fR\nOnly read\n\\fIlength\\fR\nbytes of archive.\nSee also\n\\fB\\-o\\fR.\n.TP 13n\n\\fB\\-n\\fR\nCreate archive if it doesn't exist.\nSee also\n\\fB\\-e\\fR.\n.TP 13n\n\\fB\\-o\\fR \\fIoffset\\fR\nStart reading input archive from\n\\fIoffset\\fR.\nSee also\n\\fB\\-l\\fR.\n.TP 13n\n\\fB\\-r\\fR\nPrint raw file name encoding without translation (for\n\\fBstat\\fR\ncommand).\n.TP 13n\n\\fB\\-s\\fR\nFollow file name convention strictly (for\n\\fBstat\\fR\ncommand).\n.TP 13n\n\\fB\\-t\\fR\nDisregard current file contents, if any.\n\\fINote\\fR:\nuse this with care, it deletes all existing file contents when\nyou modify the archive.\n.SS \"Commands\"\nFor all commands below, the index is zero-based.\nIn other words, the first entry in the zip archive has index 0.\n.PP\nSupported commands and arguments are:\n.TP 12n\n\\fBadd\\fR \\fIname content\\fR\nAdd file called\n\\fIname\\fR\nusing the string\n\\fIcontent\\fR\nfrom the command line as data.\n.TP 12n\n\\fBadd_dir\\fR \\fIname\\fR\nAdd directory\n\\fIname\\fR.\n.TP 12n\n\\fBadd_file\\fR \\fIname file_to_add offset len\\fR\nAdd file\n\\fIname\\fR\nto archive, using\n\\fIlen\\fR\nbytes from the file\n\\fIfile_to_add\\fR\nas input data, starting at\n\\fIoffset\\fR.\n.TP 12n\n\\fBadd_from_zip\\fR \\fIname archivename index offset len\\fR\nAdd file called\n\\fIname\\fR\nto archive using data from another zip archive\n\\fIarchivename\\fR\nusing the entry with index\n\\fIindex\\fR\nand reading\n\\fIlen\\fR\nbytes from\n\\fIoffset\\fR.\n.TP 12n\n\\fBcat\\fR \\fIindex\\fR\nOutput file contents for entry\n\\fIindex\\fR\nto stdout.\n.TP 12n\n\\fBcount_extra\\fR \\fIindex flags\\fR\nPrint the number of extra fields for archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBcount_extra_by_id\\fR \\fIindex extra_id flags\\fR\nPrint number of extra fields of type\n\\fIextra_id\\fR\nfor archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBdelete\\fR \\fIindex\\fR\nRemove entry at\n\\fIindex\\fR\nfrom zip archive.\n.TP 12n\n\\fBdelete_extra\\fR \\fIindex extra_idx flags\\fR\nRemove extra field number\n\\fIextra_idx\\fR\nfrom archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBdelete_extra_by_id\\fR \\fIindex extra_id extra_index flags\\fR\nRemove extra field number\n\\fIextra_index\\fR\nof type\n\\fIextra_id\\fR\nfrom archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBget_archive_comment\\fR\nPrint archive comment.\n.TP 12n\n\\fBget_archive_flag\\fR \\fIflag\\fR\nPrint state of archive flag\n\\fIflag\\fR.\n.TP 12n\n\\fBget_extra\\fR \\fIindex extra_index flags\\fR\nPrint extra field\n\\fIextra_index\\fR\nfor archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBget_extra_by_id\\fR \\fIindex extra_id extra_index flags\\fR\nPrint extra field\n\\fIextra_index\\fR\nof type\n\\fIextra_id\\fR\nfor archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR.\n.TP 12n\n\\fBget_file_comment\\fR \\fIindex\\fR\nGet file comment for archive entry\n\\fIindex\\fR.\n.TP 12n\n\\fBget_num_entries\\fR \\fIflags\\fR\nPrint number of entries in archive using\n\\fIflags\\fR.\n.TP 12n\n\\fBname_locate\\fR \\fIname flags\\fR\nFind entry in archive with the filename\n\\fIname\\fR\nusing\n\\fIflags\\fR\nand print its index.\n.TP 12n\n\\fBrename\\fR \\fIindex name\\fR\nRename archive entry\n\\fIindex\\fR\nto\n\\fIname\\fR.\n.TP 12n\n\\fBreplace_file_contents\\fR \\fIindex data\\fR\nReplace file contents for archive entry\n\\fIindex\\fR\nwith the string\n\\fIdata\\fR.\n.TP 12n\n\\fBset_archive_comment\\fR \\fIcomment\\fR\nSet archive comment to\n\\fIcomment\\fR.\n.TP 12n\n\\fBget_archive_flag\\fR \\fIflag\\fR \\fIvalue\\fR\nSet archive flag\n\\fIflag\\fR\nto\n\\fIvalue\\fR.\n.TP 12n\n\\fBset_extra\\fR \\fIindex extra_id extra_index flags value\\fR\nSet extra field number\n\\fIextra_index\\fR\nof type\n\\fIextra_id\\fR\nfor archive entry\n\\fIindex\\fR\nusing\n\\fIflags\\fR\nto\n\\fIvalue\\fR.\n.TP 12n\n\\fBset_file_comment\\fR \\fIindex comment\\fR\nSet file comment for archive entry\n\\fIindex\\fR\nto string\n\\fIcomment\\fR.\n.TP 12n\n\\fBset_file_compression\\fR \\fIindex method compression_flags\\fR\nSet file compression method for archive entry\n\\fIindex\\fR\nto\n\\fImethod\\fR\nusing\n\\fIcompression_flags\\fR.\n\\fINote\\fR:\nCurrently,\n\\fIcompression_flags\\fR\nare ignored.\n.TP 12n\n\\fBset_file_encryption\\fR \\fIindex method password\\fR\nSet file encryption method for archive entry\n\\fIindex\\fR\nto\n\\fImethod\\fR\nwith password\n\\fIpassword\\fR.\n.TP 12n\n\\fBset_file_mtime\\fR \\fIindex timestamp\\fR\nSet file modification time for archive entry\n\\fIindex\\fR\nto UNIX mtime\n\\fItimestamp\\fR.\n.TP 12n\n\\fBset_file_mtime_all\\fR \\fItimestamp\\fR\nSet file modification time for all archive entries to UNIX mtime\n\\fItimestamp\\fR.\n.TP 12n\n\\fBset_password\\fR \\fIpassword\\fR\nSet default password for encryption/decryption to\n\\fIpassword\\fR.\n.TP 12n\n\\fBstat\\fR \\fIindex\\fR\nPrint information about archive entry\n\\fIindex\\fR.\n.SS \"Flags\"\nSome commands take flag arguments.\nEach character in the argument sets the corresponding flag.\nUse 0 or the empty string for no flags.\n.PP\nSupported flags are:\n.RS 6n\n.PD 0\n.TP 5n\n\\fI4\\fR\n\\fRZIP_FL_ENC_CP437\\fR\n.TP 5n\n\\fI8\\fR\n\\fRZIP_FL_ENC_UTF_8\\fR\n.TP 5n\n\\fIC\\fR\n\\fRZIP_FL_NOCASE\\fR\n.TP 5n\n\\fIc\\fR\n\\fRZIP_FL_CENTRAL\\fR\n.TP 5n\n\\fId\\fR\n\\fRZIP_FL_NODIR\\fR\n.TP 5n\n\\fIl\\fR\n\\fRZIP_FL_LOCAL\\fR\n.TP 5n\n\\fIr\\fR\n\\fRZIP_FL_ENC_RAW\\fR\n.TP 5n\n\\fIs\\fR\n\\fRZIP_FL_ENC_STRICT\\fR\n.TP 5n\n\\fIu\\fR\n\\fRZIP_FL_UNCHANGED\\fR\n.RE\n.PD\n.SS \"Archive flags\"\n\\fBget_archive_flag\\fR\nand\n\\fBset_archive_flag\\fR\nwork on the following flags:\n.RS 6n\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\n\\fRcreate-or-keep-empty-file-for-archive\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRis-torrentzip\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRrdonly\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRwant-torrentzip\\fR\n.RE\n.PD\n.SS \"Compression Methods\"\nSome commands take compression method arguments.\nSupported methods are:\n.RS 6n\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\n\\fRdefault\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRdeflate\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRstore\\fR\n.RE\n.PD\n.SS \"Encryption Methods\"\nSome commands take encryption method arguments.\nSupported methods are:\n.RS 6n\n.PD 0\n.TP 4n\n\\fB\\(bu\\fR\n\\fRnone\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRAES-128\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRAES-192\\fR\n.TP 4n\n\\fB\\(bu\\fR\n\\fRAES-256\\fR\n.RE\n.PD\n.SH \"EXIT STATUS\"\n.br\nThe \\fBziptool\\fR utility exits\\~0 on success, and\\~>0 if an error occurs.\n.SH \"EXAMPLES\"\nAdd a file called\n\\fIteststring.txt\\fR\nto the zip archive\n\\fItestbuffer.zip\\fR\nwith data\n\\(lqThis is a test.\\en\\(rq\nwhere\n\\(lq\\en\\(rq\nis replaced with a newline character:\n.nf\n.sp\n.RS 6n\nziptool testbuffer.zip add teststring.txt \\\\\"This is a test.\\en\\\\\"\n.RE\n.fi\n.PP\nDelete the first file from the zip archive\n\\fItestfile.zip\\fR:\n.nf\n.sp\n.RS 6n\nziptool testfile.zip delete 0\n.RE\n.fi\n.SH \"SEE ALSO\"\nzipcmp(1),\nzipmerge(1),\nlibzip(3)\n.SH \"HISTORY\"\n\\fBziptool\\fR\nwas added in libzip 1.1.\n.SH \"AUTHORS\"\nDieter Baron <\\fIdillo@nih.at\\fR>\nand\nThomas Klausner <\\fIwiz@gatalith.at\\fR>\n"
  },
  {
    "path": "external/libzip/man/ziptool.mdoc",
    "content": ".\\\" ziptool.mdoc -- modify zip archives in multiple ways\n.\\\" Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner\n.\\\"\n.\\\" This file is part of libzip, a library to manipulate ZIP archives.\n.\\\" The authors can be contacted at <info@libzip.org>\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in\n.\\\"    the documentation and/or other materials provided with the\n.\\\"    distribution.\n.\\\" 3. The names of the authors may not be used to endorse or promote\n.\\\"    products derived from this software without specific prior\n.\\\"    written permission.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n.\\\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n.\\\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n.\\\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n.\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n.\\\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n.\\\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n.\\\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n.\\\"\n.Dd January 23, 2023\n.Dt ZIPTOOL 1\n.Os\n.Sh NAME\n.Nm ziptool\n.Nd modify zip archives\n.Sh SYNOPSIS\n.Nm\n.Op Fl ceghnrst\n.Op Fl l Ar length\n.Op Fl o Ar offset\n.Ar zip-archive\n.Cm command Op Ar command-args ...\n.Op Cm command Oo Ar command-args ... Oc ...\n.Sh DESCRIPTION\n.Nm\nmodifies the zip archive\n.Ar zip-archive\naccording to the\n.Ar commands\ngiven.\n.Pp\nSupported options:\n.Bl -tag -width MoMoffsetMM\n.It Fl c\nCheck zip archive consistency when opening it.\n.It Fl e\nError if archive already exists (only useful with\n.Fl n ) .\n.It Fl g\nGuess file name encoding (for\n.Cm stat\ncommand).\n.It Fl h\nDisplay help.\n.It Fl l Ar length\nOnly read\n.Ar length\nbytes of archive.\nSee also\n.Fl o .\n.It Fl n\nCreate archive if it doesn't exist.\nSee also\n.Fl e .\n.It Fl o Ar offset\nStart reading input archive from\n.Ar offset .\nSee also\n.Fl l .\n.It Fl r\nPrint raw file name encoding without translation (for\n.Cm stat\ncommand).\n.It Fl s\nFollow file name convention strictly (for\n.Cm stat\ncommand).\n.It Fl t\nDisregard current file contents, if any.\n.Em Note :\nuse this with care, it deletes all existing file contents when\nyou modify the archive.\n.El\n.Ss Commands\nFor all commands below, the index is zero-based.\nIn other words, the first entry in the zip archive has index 0.\n.Pp\nSupported commands and arguments are:\n.Bl -tag -width 10n\n.It Cm add Ar name content\nAdd file called\n.Ar name\nusing the string\n.Ar content\nfrom the command line as data.\n.It Cm add_dir Ar name\nAdd directory\n.Ar name .\n.It Cm add_file Ar name file_to_add offset len\nAdd file\n.Ar name\nto archive, using\n.Ar len\nbytes from the file\n.Ar file_to_add\nas input data, starting at\n.Ar offset .\n.It Cm add_from_zip Ar name archivename index offset len\nAdd file called\n.Ar name\nto archive using data from another zip archive\n.Ar archivename\nusing the entry with index\n.Ar index\nand reading\n.Ar len\nbytes from\n.Ar offset .\n.It Cm cat Ar index\nOutput file contents for entry\n.Ar index\nto stdout.\n.It Cm count_extra Ar index flags\nPrint the number of extra fields for archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm count_extra_by_id Ar index extra_id flags\nPrint number of extra fields of type\n.Ar extra_id\nfor archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm delete Ar index\nRemove entry at\n.Ar index\nfrom zip archive.\n.It Cm delete_extra Ar index extra_idx flags\nRemove extra field number\n.Ar extra_idx\nfrom archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm delete_extra_by_id Ar index extra_id extra_index flags\nRemove extra field number\n.Ar extra_index\nof type\n.Ar extra_id\nfrom archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm get_archive_comment\nPrint archive comment.\n.It Cm get_archive_flag Ar flag\nPrint state of archive flag\n.Ar flag .\n.It Cm get_extra Ar index extra_index flags\nPrint extra field\n.Ar extra_index\nfor archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm get_extra_by_id Ar index extra_id extra_index flags\nPrint extra field\n.Ar extra_index\nof type\n.Ar extra_id\nfor archive entry\n.Ar index\nusing\n.Ar flags .\n.It Cm get_file_comment Ar index\nGet file comment for archive entry\n.Ar index .\n.It Cm get_num_entries Ar flags\nPrint number of entries in archive using\n.Ar flags .\n.It Cm name_locate Ar name flags\nFind entry in archive with the filename\n.Ar name\nusing\n.Ar flags\nand print its index.\n.It Cm rename Ar index name\nRename archive entry\n.Ar index\nto\n.Ar name .\n.It Cm replace_file_contents Ar index data\nReplace file contents for archive entry\n.Ar index\nwith the string\n.Ar data .\n.It Cm set_archive_comment Ar comment\nSet archive comment to\n.Ar comment .\n.It Cm get_archive_flag Ar flag Ar value\nSet archive flag\n.Ar flag\nto\n.Ar value .\n.It Cm set_extra Ar index extra_id extra_index flags value\nSet extra field number\n.Ar extra_index\nof type\n.Ar extra_id\nfor archive entry\n.Ar index\nusing\n.Ar flags\nto\n.Ar value .\n.It Cm set_file_comment Ar index comment\nSet file comment for archive entry\n.Ar index\nto string\n.Ar comment .\n.It Cm set_file_compression Ar index method compression_flags\nSet file compression method for archive entry\n.Ar index\nto\n.Ar method\nusing\n.Ar compression_flags .\n.Em Note :\nCurrently,\n.Ar compression_flags\nare ignored.\n.It Cm set_file_encryption Ar index method password\nSet file encryption method for archive entry\n.Ar index\nto\n.Ar method\nwith password\n.Ar password .\n.It Cm set_file_mtime Ar index timestamp\nSet file modification time for archive entry\n.Ar index\nto UNIX mtime\n.Ar timestamp .\n.It Cm set_file_mtime_all Ar timestamp\nSet file modification time for all archive entries to UNIX mtime\n.Ar timestamp .\n.It Cm set_password Ar password\nSet default password for encryption/decryption to\n.Ar password .\n.It Cm stat Ar index\nPrint information about archive entry\n.Ar index .\n.El\n.Ss Flags\nSome commands take flag arguments.\nEach character in the argument sets the corresponding flag.\nUse 0 or the empty string for no flags.\n.Pp\nSupported flags are:\n.Bl -tag -width MMM -compact -offset indent\n.It Ar 4\n.Dv ZIP_FL_ENC_CP437\n.It Ar 8\n.Dv ZIP_FL_ENC_UTF_8\n.It Ar C\n.Dv ZIP_FL_NOCASE\n.It Ar c\n.Dv ZIP_FL_CENTRAL\n.It Ar d\n.Dv ZIP_FL_NODIR\n.It Ar l\n.Dv ZIP_FL_LOCAL\n.It Ar r\n.Dv ZIP_FL_ENC_RAW\n.It Ar s\n.Dv ZIP_FL_ENC_STRICT\n.It Ar u\n.Dv ZIP_FL_UNCHANGED\n.El\n.Ss Archive flags\n.Cm get_archive_flag\nand\n.Cm set_archive_flag\nwork on the following flags:\n.Bl -bullet -compact -offset indent\n.It\n.Dv create-or-keep-empty-file-for-archive\n.It\n.Dv is-torrentzip\n.It\n.Dv rdonly\n.It\n.Dv want-torrentzip\n.El\n.Ss Compression Methods\nSome commands take compression method arguments.\nSupported methods are:\n.Bl -bullet -compact -offset indent\n.It\n.Dv default\n.It\n.Dv deflate\n.It\n.Dv store\n.El\n.Ss Encryption Methods\nSome commands take encryption method arguments.\nSupported methods are:\n.Bl -bullet -compact -offset indent\n.It\n.Dv none\n.It\n.Dv AES-128\n.It\n.Dv AES-192\n.It\n.Dv AES-256\n.El\n.Sh EXIT STATUS\n.Ex -std\n.Sh EXAMPLES\nAdd a file called\n.Pa teststring.txt\nto the zip archive\n.Pa testbuffer.zip\nwith data\n.Dq This is a test.\\en\nwhere\n.Dq \\en\nis replaced with a newline character:\n.Bd -literal -offset indent\nziptool testbuffer.zip add teststring.txt \\\\\"This is a test.\\en\\\\\"\n.Ed\n.Pp\nDelete the first file from the zip archive\n.Pa testfile.zip :\n.Bd -literal -offset indent\nziptool testfile.zip delete 0\n.Ed\n.Sh SEE ALSO\n.Xr zipcmp 1 ,\n.Xr zipmerge 1 ,\n.Xr libzip 3\n.Sh HISTORY\n.Nm\nwas added in libzip 1.1.\n.Sh AUTHORS\n.An -nosplit\n.An Dieter Baron Aq Mt dillo@nih.at\nand\n.An Thomas Klausner Aq Mt wiz@gatalith.at\n"
  },
  {
    "path": "external/libzip/ossfuzz/CMakeLists.txt",
    "content": "set(FUZZ_PROGRAMS\n  zip_read_file_fuzzer\n  zip_read_fuzzer\n  zip_write_encrypt_aes256_file_fuzzer\n  zip_write_encrypt_pkware_file_fuzzer\n)\n\nforeach(PROGRAM IN LISTS FUZZ_PROGRAMS)\n  add_executable(${PROGRAM} ${PROGRAM}.c)\n  target_sources(${PROGRAM} PRIVATE fuzz_main.c)\n  target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})\n  target_link_libraries(${PROGRAM} zip)\nendforeach()\n\nadd_custom_target(list-fuzzers\n        COMMAND echo FUZZERS: ${FUZZ_PROGRAMS}\n)\n"
  },
  {
    "path": "external/libzip/ossfuzz/fuzz_main.c",
    "content": "#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n/* fuzz target entry point, works without libFuzzer */\n\nextern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n\nint\nmain(int argc, char **argv) {\n    FILE *f = NULL;\n    char *buf = NULL;\n    long siz_buf;\n\n    if (argc < 2) {\n        fprintf(stderr, \"no input file\\n\");\n        goto err;\n    }\n\n    f = fopen(argv[1], \"rb\");\n    if (f == NULL) {\n        fprintf(stderr, \"error opening input file %s\\n\", argv[1]);\n        goto err;\n    }\n\n    fseek(f, 0, SEEK_END);\n\n    siz_buf = ftell(f);\n    rewind(f);\n\n    if (siz_buf < 1) {\n        fprintf(stderr, \"zero-byte file not supported\\n\");\n        goto err;\n    }\n\n    buf = (char *)malloc(siz_buf);\n    if (buf == NULL) {\n        fprintf(stderr, \"malloc() failed\\n\");\n        goto err;\n    }\n\n    if (fread(buf, siz_buf, 1, f) != 1) {\n        fprintf(stderr, \"fread() failed\\n\");\n        goto err;\n    }\n    fclose(f);\n    f = NULL;\n\n    (void)LLVMFuzzerTestOneInput((uint8_t *)buf, siz_buf);\n\n err:\n    if (f) {\n        fclose(f);\n    }\n    free(buf);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/ossfuzz/ossfuzz.sh",
    "content": "#!/bin/bash -eu\n# Copyright 2019 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n################################################################################\n\n# This script is meant to be run by\n# https://github.com/google/oss-fuzz/blob/master/projects/libzip/Dockerfile\n\n\nmkdir build\ncd build\ncmake -DBUILD_SHARED_LIBS=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=ON -DBUILD_TOOLS=OFF -DHAVE_CRYPTO=ON ..\nmake -j$(nproc)\n\nfor fuzzer in $(make list-fuzzers | sed -n 's/^FUZZERS: //p')\ndo\n  $CXX $CFLAGS -I. -I../lib \\\n    $SRC/libzip/ossfuzz/$fuzzer.c \\\n      -o $OUT/$fuzzer \\\n      $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lbz2 -llzma -lz -lzstd -v -lssl -lcrypto\ndone\n\nfind $SRC/libzip/regress -name \"*zip\" | \\\n     xargs zip $OUT/zip_read_fuzzer_seed_corpus.zip\ncp $SRC/libzip/ossfuzz/zip_read_fuzzer.dict $OUT/\n\ncp $SRC/libzip/ossfuzz/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip $OUT/\n\nfor pair in \\\n  zip_read_fuzzer:zip_read_file_fuzzer \\\n  zip_write_encrypt_aes256_file_fuzzer:zip_write_encrypt_pkware_file_fuzzer\ndo\n  source=${pair%%:*}\n  target=${pair##*:}\n  for file in .dict _seed_corpus.zip\n  do\n    if [ -f $OUT/$source$file ]\n    then\n      cp $OUT/$source$file $OUT/$target$file\n    fi\n  done\ndone\n\n\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_read_file_fuzzer.c",
    "content": "/*\n  zip_random_uwp.c -- fill the user's buffer with random stuff (UWP version)\n  Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n#include <errno.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <zip.h>\n\n#include \"zip_read_fuzzer_common.h\"\n\n/**\n   This fuzzing target takes input data, creates a ZIP archive from it, checks the archive's consistency,\n   and iterates over the entries in the archive, reading data from each entry.\n**/\n\n#ifdef __cplusplus\nextern \"C\"\n#endif\nint\nLLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    zip_t *za;\n    const char *name = \"test.zip\";\n    FILE *fp;\n    zip_error_t error;\n    int err = 0;\n\n    (void)remove(name);\n    if ((fp = fopen(name, \"wb\")) == NULL) {\n        fprintf(stderr, \"can't create file '%s': %s\\n\", name, strerror(errno));\n        return 0;\n    }\n    if (fwrite(data, 1, size, fp) != size) {\n        fprintf(stderr, \"can't write data to file '%s': %s\\n\", name, strerror(errno));\n        fclose(fp);\n        (void)remove(name);\n        return 0;\n    }\n    if (fclose(fp) < 0) {\n        fprintf(stderr, \"can't close file '%s': %s\\n\", name, strerror(errno));\n        (void)remove(name);\n        return 0;\n    }\n\n    za = zip_open(name, 0, &err);\n    zip_error_init_with_code(&error, err);\n\n    fuzzer_read(za, &error, NULL);\n\n    (void)remove(name);\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_read_fuzzer.c",
    "content": "#include <stdint.h>\n#include <zip.h>\n\n#include \"zip_read_fuzzer_common.h\"\n\n#ifdef __cplusplus\nextern \"C\"\n#endif\nint\nLLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    zip_source_t *src;\n    zip_error_t error;\n    zip_t *za;\n\n    zip_error_init(&error);\n\n    if ((src = zip_source_buffer_create(data, size, 0, &error)) == NULL) {\n        zip_error_fini(&error);\n        return 0;\n    }\n\n    za = zip_open_from_source(src, 0, &error);\n\n    fuzzer_read(za, &error, \"secretpassword\");\n\n    if (za == NULL) {\n        zip_source_free(src);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_read_fuzzer.dict",
    "content": "header_cd=\"\\x50\\x4b\\x01\\x02\"\nheader_local_file_header=\"\\x50\\x4b\\x03\\x04\"\nheader_eocd=\"\\x50\\x4b\\x05\\x06\"\nheader_zip64_eocd=\"\\x50\\x4b\\x06\\x06\"\nheader_zip64_eocd_locator=\"\\x50\\x4b\\x06\\x07\"\nheader_data_descriptor=\"\\x50\\x4b\\x07\\x08\"\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_read_fuzzer_common.h",
    "content": "/*\n  zip_read_fuzzer_common.h -- common function for fuzzers to read all files in an archive\n  Copyright (C) 2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zip.h\"\n\nvoid fuzzer_read(zip_t *za, zip_error_t *error, const char *password) {\n    zip_int64_t i, n, ret;\n    char buf[32768];\n\n    if (za == NULL) {\n        fprintf(stderr, \"Error opening archive: %s\\n\", zip_error_strerror(error));\n        zip_error_fini(error);\n        return;\n    }\n\n    zip_set_default_password(za, password);\n\n    zip_error_fini(error);\n\n    n = zip_get_num_entries(za, 0);\n    for (i = 0; i < n; i++) {\n        zip_file_t *f = zip_fopen_index(za, i, 0);\n        if (f == NULL) {\n            fprintf(stderr, \"Error opening file %d: %s\\n\", (int)i, zip_strerror(za));\n            continue;\n        }\n\n        while ((ret = zip_fread(f, buf, sizeof(buf))) > 0) {\n            ;\n        }\n        if (ret < 0) {\n            fprintf(stderr, \"Error reading file %d: %s\\n\", (int)i, zip_strerror(za));\n        }\n        if (zip_fclose(f) < 0) {\n            fprintf(stderr, \"Error closing file %d: %s\\n\", (int)i, zip_strerror(za));\n            continue;\n        }\n    }\n    if (zip_close(za) < 0) {\n        fprintf(stderr, \"Error closing archive: %s\\n\", zip_strerror(za));\n        zip_discard(za);\n    }\n}\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_write_encrypt_aes256_file_fuzzer.c",
    "content": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <zip.h>\n\n/**\n   This fuzzing target takes input data, creates a ZIP archive, load\n   it to a buffer, adds a file to it with AES-256 encryption and a\n   specified password, and then closes and removes the archive.\n\n   The purpose of this fuzzer is to test security of ZIP archive\n   handling and encryption in the libzip by subjecting it to various\n   inputs, including potentially malicious or malformed data of\n   different file types.\n **/\n\n#ifdef __cplusplus\nextern \"C\"\n#endif\nint\nLLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    const char *path = \"test_aes256.zip\";\n    const char *password = \"password\";\n    const char *file = \"filename\";\n    int error = 0;\n    struct zip *archive;\n\n    (void)remove(path);\n    if ((archive = zip_open(path, ZIP_CREATE, &error)) == NULL) {\n        return -1;\n    }\n\n    struct zip_source *source = zip_source_buffer(archive, data, size, 0);\n    if (source == NULL) {\n        fprintf(stderr, \"failed to create source buffer. %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n\n    int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE);\n    if (index < 0) {\n        fprintf(stderr, \"failed to add file to archive: %s\\n\", zip_strerror(archive));\n        zip_source_free(source);\n        zip_discard(archive);\n        return -1;\n    }\n    if (zip_file_set_encryption(archive, index, ZIP_EM_AES_256, password) < 0) {\n        fprintf(stderr, \"failed to set file encryption: %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n    if (zip_close(archive) < 0) {\n        fprintf(stderr, \"error closing archive: %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n    (void)remove(path);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/ossfuzz/zip_write_encrypt_pkware_file_fuzzer.c",
    "content": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <zip.h>\n\n/**\nThis fuzzing target takes input data, creates a ZIP archive, load\nit to a buffer, adds a file to it with traditional PKWARE\nencryption and a specified password, and then closes and removes\nthe archive.\n\nThe purpose of this fuzzer is to test security of ZIP archive\nhandling and encryption in the libzip by subjecting it to various\ninputs, including potentially malicious or malformed data of\ndifferent file types.\n**/\n\n#ifdef __cplusplus\nextern \"C\"\n#endif\nint\nLLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    const char *path = \"test_pkware.zip\";\n    const char *password = \"password\";\n    const char *file = \"filename\";\n    int error = 0;\n    struct zip *archive;\n\n    (void)remove(path);\n    if ((archive = zip_open(path, ZIP_CREATE, &error)) == NULL) {\n        return -1;\n    }\n\n    struct zip_source *source = zip_source_buffer(archive, data, size, 0);\n    if (source == NULL) {\n        fprintf(stderr, \"failed to create source buffer. %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n\n    int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE);\n    if (index < 0) {\n        fprintf(stderr, \"failed to add file to archive: %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n    if (zip_file_set_encryption(archive, index, ZIP_EM_TRAD_PKWARE, password) < 0) {\n        fprintf(stderr, \"failed to set file encryption: %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n    if (zip_close(archive) < 0) {\n        fprintf(stderr, \"error closing archive: %s\\n\", zip_strerror(archive));\n        zip_discard(archive);\n        return -1;\n    }\n    (void)remove(path);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/CMakeLists.txt",
    "content": "check_function_exists(getopt HAVE_GETOPT)\n\nset(TEST_PROGRAMS\n  add_from_filep\n  can_clone_file\n  fopen_unchanged\n  fseek\n  nonrandomopentest\n  liboverride-test\n)\n\nset(GETOPT_USERS\n  fread\n  tryopen\n)\n\nset(HOLE_USERS\n  hole\n  ziptool_regress\n)\n\nset(ZIP_PROGRAMS ${TEST_PROGRAMS} ${GETOPT_USERS} ${HOLE_USERS})\n\nforeach(PROGRAM IN LISTS ZIP_PROGRAMS)\n  add_executable(${PROGRAM} ${PROGRAM}.c)\n  target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})\n  target_link_libraries(${PROGRAM} zip)\nendforeach()\n\n# both programs using source_hole.c also use getopt\nif(NOT HAVE_GETOPT)\n  foreach(PROGRAM IN LISTS GETOPT_USERS HOLE_USERS)\n    target_sources(${PROGRAM} PRIVATE ../src/getopt.c)\n    target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/src)\n  endforeach()\nendif(NOT HAVE_GETOPT)\n\nforeach(PROGRAM IN LISTS HOLE_USERS)\n  target_sources(${PROGRAM} PRIVATE source_hole.c)\nendforeach()\n\nforeach(PROGRAM IN LISTS FUZZ_PROGRAMS)\n  target_sources(${PROGRAM} PRIVATE fuzz_main.c)\nendforeach()\n\n# for including ziptool.c\ntarget_include_directories(ziptool_regress PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/src)\n\nset(DL_USERS\n  # malloc\n  nonrandomopen\n  liboverride\n)\n\nforeach(PROGRAM IN LISTS DL_USERS)\n  add_library(${PROGRAM} MODULE ${PROGRAM}.c)\n  target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})\nendforeach()\n\nadd_custom_target(cleanup\n    COMMAND ${CMAKE_COMMAND} -DDIR=${PROJECT_BINARY_DIR}/regress -P ${PROJECT_SOURCE_DIR}/regress/cleanup.cmake\n    )\n\nadd_custom_target(testinput\n  ALL\n  VERBATIM\n  COMMAND ${CMAKE_COMMAND} -E tar x ${PROJECT_SOURCE_DIR}/regress/manyfiles-zip.zip\n  COMMAND ${CMAKE_COMMAND} -E tar x ${PROJECT_SOURCE_DIR}/regress/bigzero-zip.zip\n  DEPENDS ${PROJECT_SOURCE_DIR}/regress/manyfiles-zip.zip ${PROJECT_SOURCE_DIR}/regress/bigzero-zip.zip\n)\n\nset_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES\n  bigzero.zip\n  manyfiles-133000.zip\n  manyfiles-65536.zip\n  manyfiles-fewer.zip\n  manyfiles-more.zip\n  manyfiles-zip64-modulo.zip\n  manyfiles-zip64.zip\n  manyfiles.zip\n)\n\nset(path \"$<TARGET_FILE_DIR:zip>;$ENV{PATH}\")\nif (TARGET zlib)\n  set(path \"$<TARGET_FILE_DIR:zlib>;${path}\")\nendif()\nstring(REPLACE \";\" \"\\\\;\" path \"${path}\")\n\nset(ENV{srcdir} ${PROJECT_SOURCE_DIR}/regress)\n\nfile(GLOB EXTRA_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/*.test)\nforeach(FULL_CASE IN LISTS EXTRA_TESTS)\n  get_filename_component(CASE ${FULL_CASE} NAME)\n  add_test(NAME ${CASE} COMMAND ${NIHTEST} -v ${CASE})\n  # TODO: add --bin-sub-directory $<CONFIG>\n  set_tests_properties(${CASE} PROPERTIES SKIP_RETURN_CODE 77)\n  set_tests_properties(${CASE} PROPERTIES ENVIRONMENT \"PATH=${path}\")\nendforeach()\n\nset(XFAIL_TESTS\n#  zipcmp_zip_dir_slash.test\n)\n\nforeach(CASE ${XFAIL_TESTS})\n  set_tests_properties(${CASE} PROPERTIES WILL_FAIL TRUE)\nendforeach()\n\nadd_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})\n\nconfigure_file(nihtest.conf.in nihtest.conf @ONLY)\n"
  },
  {
    "path": "external/libzip/regress/add_dir.test",
    "content": "# add directories to zip\nreturn 0\narguments testdir.zip   add_dir testdir/   add_dir testdir-noslash\nfile testdir.zip {} testdir.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_buffer.test",
    "content": "# add buffer contents as file to zip\nreturn 0\narguments testbuffer.zip add teststring.txt \"This is a test, and it seems to have been successful.\\n\"\nfile testbuffer.zip {} testbuffer.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_file.test",
    "content": "# add file to zip\nreturn 0\narguments -- testfile.zip   add_file testfile.txt testfile.txt 0 -1\nfile testfile.txt testfile.txt\nfile testfile.zip {} testfile.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_file_duplicate.test",
    "content": "# add already existing file to zip, making duplicate names\nreturn 1\narguments -- testfile.zip   add_file testfile.txt testfile.txt 0 -1\nfile testfile.txt testfile.txt\nfile testfile.zip testfile.zip\nstderr\ncan't add file 'testfile.txt': File already exists\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/add_from_file_twice_duplicate.test",
    "content": "# add file to zip twice, making duplicate names\nreturn 1\narguments -- testfile.zip   add_file testfile.txt testfile.txt 0 -1   add_file testfile.txt testfile.txt 0 -1\nfile testfile.txt testfile.txt\nfile testfile.zip {} testfile.zip\nstderr\ncan't add file 'testfile.txt': File already exists\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/add_from_file_unchange.test",
    "content": "# add file to zip, but revert before closing\nreturn 0\narguments -- testfile.zip   add_file testfile.txt testfile.txt 0 -1  unchange 0\nfile testfile.txt testfile.txt\n"
  },
  {
    "path": "external/libzip/regress/add_from_filep.c",
    "content": "/*\n  add_from_filep.c -- test case for adding file to archive\n  Copyright (C) 1999-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <errno.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"zip.h\"\n\nstatic const char *prg;\n\nint\nmain(int argc, char *argv[]) {\n    const char *archive;\n    const char *file;\n    const char *name;\n    zip_t *za;\n    zip_source_t *zs;\n    int err;\n    FILE *fp;\n\n    prg = argv[0];\n\n    if (argc != 3) {\n        fprintf(stderr, \"usage: %s archive file\\n\", prg);\n        return 1;\n    }\n\n    archive = argv[1];\n    file = argv[2];\n\n    if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: can't open zip archive '%s': %s\\n\", prg, archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return 1;\n    }\n\n    if ((fp = fopen(file, \"rb\")) == NULL) {\n        fprintf(stderr, \"%s: can't open input file '%s': %s\\n\", prg, file, strerror(errno));\n        return 1;\n    }\n\n    if ((zs = zip_source_filep(za, fp, 0, -1)) == NULL) {\n        fprintf(stderr, \"%s: error creating file source for '%s': %s\\n\", prg, file, zip_strerror(za));\n        return 1;\n    }\n\n    if ((name = strrchr(file, '/')) == NULL)\n        name = file;\n\n    if (zip_file_add(za, name, zs, 0) == -1) {\n        zip_source_free(zs);\n        fprintf(stderr, \"%s: can't add file '%s': %s\\n\", prg, file, zip_strerror(za));\n        return 1;\n    }\n\n    if (zip_close(za) == -1) {\n        fprintf(stderr, \"%s: can't close zip archive '%s': %s\\n\", prg, archive, zip_strerror(za));\n        return 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/add_from_filep.test",
    "content": "# add file to zip\nprogram add_from_filep\nreturn 0\narguments testfile.zip testfile.txt\nfile testfile.txt testfile.txt\nfile testfile.zip {} testfile.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_stdin.test",
    "content": "# add stdin to zip\narguments -- teststdin.zip add_file teststring.txt /dev/stdin 0 -1\nreturn 0\nfile teststdin.zip {} teststdin.zip\nstdin\nThis is a test, and it seems to have been successful.\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_closed.test",
    "content": "# add deflated file from zip to zip, but close the source before it can be read\nreturn 1\narguments -- testfile.zip   add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1  zin_close 0\nfile testdeflated.zzip testdeflated.zip\nstderr\ncan't close zip archive 'testfile.zip': Containing zip archive was closed\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_deflated.test",
    "content": "# add deflated file from zip to zip\nreturn 0\narguments -- testfile.zip   add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1\nfile testdeflated.zzip testdeflated.zip\nfile testfile.zip {} testdeflated.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_deflated2.test",
    "content": "# add deflated files from zip to zip\nreturn 0\narguments -- testfile.zip   add_from_zip abac-repeat.txt testdeflated.zzip 0 0 -1  add_from_zip abac-repeat2.txt testdeflated.zzip 0 0 -1\nfile testdeflated.zzip testdeflated.zip\nfile testfile.zip {} testdeflated2.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_partial_deflated.test",
    "content": "# add parts of a file from zip to zip\nreturn 0\narguments -- testfile.zip   add_from_zip first firstsecond.zzip 0 0 9   add_from_zip second firstsecond.zzip 0 9 -1\nfile firstsecond.zzip firstsecond.zip\nfile testfile.zip {} firstsecond-split-stored.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_partial_stored.test",
    "content": "# add parts of a file from zip to zip\nreturn 0\narguments -- testfile.zip   add_from_zip first firstsecond.zzip 1 0 9   add_from_zip second firstsecond.zzip 1 9 -1\nfile firstsecond.zzip firstsecond.zip\nfile testfile.zip {} firstsecond-split-stored.zip\n"
  },
  {
    "path": "external/libzip/regress/add_from_zip_stored.test",
    "content": "# add stored file from zip to zip\nreturn 0\narguments -- testfile.zip   add_from_zip abac-repeat.txt teststored.zzip 0 0 -1\nfile teststored.zzip teststored.zip\nfile testfile.zip {} testdeflated.zip\n"
  },
  {
    "path": "external/libzip/regress/add_stored.test",
    "content": "# add file, set compression method to ZIP_CM_STORE\nreturn 0\narguments -n test.zip add foo foo  set_file_compression 0 store 0\nfile test.zip {} foo-stored.zip\n"
  },
  {
    "path": "external/libzip/regress/add_stored_in_memory.test",
    "content": "# add file, set compression method to ZIP_CM_STORE\nreturn 0\narguments -mn test.zip add foo foo  set_file_compression 0 store 0\nfile test.zip {} foo-stored.zip\n"
  },
  {
    "path": "external/libzip/regress/buffer-fragment-read.test",
    "content": "# test reading from a buffer fragment source\nreturn 0\narguments -mF 1024 test.zip  cat 1\nfile test.zip cm-default.zip\nstdout\nuncompressible\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/buffer-fragment-write.test",
    "content": "# rename file inside zip archive\nreturn 0\narguments -mF 100 rename.zip  rename 1 notfile2\nfile rename.zip testcomment.zip rename_ok.zip\n"
  },
  {
    "path": "external/libzip/regress/can_clone_file.c",
    "content": "/*\n can_clone_file.c -- does the current filesystem support cloning\n Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <stdlib.h>\n\n#include \"config.h\"\n\n#ifdef HAVE_CLONEFILE\n#include <errno.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/attr.h>\n#include <sys/mount.h>\n#include <sys/param.h>\n#include <unistd.h>\n#elif defined(HAVE_FICLONERANGE)\n#include <errno.h>\n#include <linux/fs.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <unistd.h>\n#endif\n\nint\nmain(int argc, char *argv[]) {\n#ifdef HAVE_CLONEFILE\n    struct statfs fs;\n    struct attrlist attribute_list;\n    struct {\n        uint32_t size;\n        vol_capabilities_attr_t capabilities;\n    } volume_attributes;\n\n    if (statfs(\".\", &fs) < 0) {\n        fprintf(stderr, \"%s: can't get mount point of current directory: %s\\n\", argv[0], strerror(errno));\n        exit(1);\n    }\n\n    /* Not all volumes support clonefile().  A volume can be tested for\n       clonefile() support by using getattrlist(2) to get the volume\n       capabilities attribute ATTR_VOL_CAPABILITIES, and then testing the\n       VOL_CAP_INT_CLONE flag. */\n\n    memset(&attribute_list, 0, sizeof(attribute_list));\n    attribute_list.bitmapcount = ATTR_BIT_MAP_COUNT;\n    attribute_list.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;\n    memset(&volume_attributes, 0, sizeof(volume_attributes));\n\n    if (getattrlist(fs.f_mntonname, &attribute_list, &volume_attributes, sizeof(volume_attributes), 0) < 0) {\n        fprintf(stderr, \"%s: can't get volume capabilities of '%s': %s\\n\", argv[0], fs.f_mntonname, strerror(errno));\n        exit(1);\n    }\n\n    if (volume_attributes.capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_CLONE) {\n        exit(0);\n    }\n#elif defined(HAVE_FICLONERANGE)\n    char namea[32] = \"a.fioclone.XXXXXX\";\n    char nameb[32] = \"b.fioclone.XXXXXX\";\n    int fda, fdb, ret;\n    struct file_clone_range range;\n\n    if ((fda = mkstemp(namea)) < 0) {\n        fprintf(stderr, \"can't create temp file a: %s\\n\", strerror(errno));\n        exit(1);\n    }\n    if ((fdb = mkstemp(nameb)) < 0) {\n        fprintf(stderr, \"can't create temp file b: %s\\n\", strerror(errno));\n        (void)close(fda);\n        (void)remove(namea);\n        exit(1);\n    }\n    if (write(fda, \"test\\n\", 5) < 0) {\n        fprintf(stderr, \"can't write temp file a: %s\\n\", strerror(errno));\n        (void)close(fda);\n        (void)remove(namea);\n        close(fdb);\n        (void)remove(nameb);\n        exit(1);\n    }\n    range.src_fd = fda;\n    range.src_offset = 0;\n    range.src_length = 0;\n    range.dest_offset = 0;\n    ret = ioctl(fdb, FICLONERANGE, &range);\n    (void)close(fda);\n    (void)close(fdb);\n    (void)remove(namea);\n    (void)remove(nameb);\n    if (ret >= 0) {\n        exit(0);\n    }\n#endif\n\n    exit(1);\n}\n"
  },
  {
    "path": "external/libzip/regress/cancel_45.test",
    "content": "# test default compression stores if smaller; test cancel after 45%\nreturn 1\narguments -n -- test.zip  cancel 45  add compressible aaaaaaaaaaaaaa  add uncompressible uncompressible  add_nul large-compressible 8200  add_file large-uncompressible large-uncompressible 0 -1\nfile large-uncompressible large-uncompressible\nstdout\n0.0% done\n25.0% done\n50.0% done\nend-of-inline-data\nstderr\ncan't close zip archive 'test.zip': Operation cancelled\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/cancel_90.test",
    "content": "# test default compression stores if smaller; test cancel after 90%\nreturn 1\narguments -n -- test.zip  cancel 90  add compressible aaaaaaaaaaaaaa  add uncompressible uncompressible  add_nul large-compressible 8200  add_file large-uncompressible large-uncompressible 0 -1\nfile large-uncompressible large-uncompressible\nstdout\n0.0% done\n25.0% done\n50.0% done\n75.0% done\n100.0% done\nend-of-inline-data\nstderr\ncan't close zip archive 'test.zip': Operation cancelled\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/changing-size-decreases-fixed.test",
    "content": "description size of input file decreases between add and close\narguments test.zip add_file new muchlonger 0 11 extract_as 0 muchlonger\nreturn 1\nfile test.zip changing-size.zip changing-size.zip\nfile muchlonger <inline> <inline>\nmuchlonger\nend-of-inline-data\nshort\nend-of-inline-data\nstderr\ncan't close zip archive 'test.zip': Unexpected length of data\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/changing-size-decreases.test",
    "content": "description size of input file decreases between add and close\narguments test.zip add_file new muchlonger 0 0 extract_as 0 muchlonger\nreturn 1\nfile test.zip changing-size.zip changing-size.zip\nfile muchlonger <inline> <inline>\nmuchlonger\nend-of-inline-data\nshort\nend-of-inline-data\nstderr\ncan't close zip archive 'test.zip': Unexpected length of data\nend-of-inline-data"
  },
  {
    "path": "external/libzip/regress/changing-size-increases-fixed.test",
    "content": "description size of input file increases between add and close\narguments test.zip add_file new short 0 6 extract_as 1 short\nfile test.zip changing-size.zip changing-size-muchlo.zip\nfile short <inline> <inline>\nshort\nend-of-inline-data\nmuchlonger\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/changing-size-increases-unchecked.test",
    "content": "description size of input file increases between add and close\narguments -- test.zip add_file new short 0 -2 extract_as 1 short\nfile test.zip changing-size.zip changing-size-muchlonger.zip\nfile short <inline> <inline>\nshort\nend-of-inline-data\nmuchlonger\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/changing-size-increases.test",
    "content": "description size of input file increases between add and close\narguments test.zip add_file new short 0 0 extract_as 1 short\nfile test.zip changing-size.zip changing-size-muchl.zip\nfile short short <inline>\nmuchlonger\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/check_torrentzip_fail.test",
    "content": "# check if file is torrentzip, fails\nreturn 0\narguments testfile.zzip get_archive_flag is-torrentzip\nfile testfile.zzip testfile.zip\nstdout\n0\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/check_torrentzip_modified.test",
    "content": "# check if file is torrentzip, fails because it was modified afterwards\nreturn 0\narguments testfile.zzip get_archive_flag is-torrentzip\nfile testfile.zzip testfile-torrentzip-modified.zip\nstdout\n0\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/check_torrentzip_success.test",
    "content": "# check if file is torrentzip, succeeds\nreturn 0\narguments testfile.zzip get_archive_flag is-torrentzip\nfile testfile.zzip testfile-torrentzip.zip\nstdout\n1\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/cleanup.cmake",
    "content": "# expect variable DIR\nFILE(GLOB CLEANDIRS \"${DIR}/sandbox-*.d[0-9]*\")\nIF (CLEANDIRS)\n  MESSAGE(STATUS \"Removing ${CLEANDIRS}\")\n  FILE(REMOVE_RECURSE ${CLEANDIRS})\nENDIF()\n\n"
  },
  {
    "path": "external/libzip/regress/clone-buffer-add.test",
    "content": "# test cloning archive from buffer, add new file\nreturn 0\narguments -mF 100 test.zzip  add new \"A new file.\"  set_file_mtime 3 1512998132\nfile test.zzip gap.zip gap-add.zip\n"
  },
  {
    "path": "external/libzip/regress/clone-buffer-delete.test",
    "content": "# test cloning archive from buffer, deleting a file\nreturn 0\narguments -mF 100 test.zzip  delete 2\nfile test.zzip gap.zip gap-delete.zip\n"
  },
  {
    "path": "external/libzip/regress/clone-buffer-replace.test",
    "content": "# test cloning archive from buffer, replacing a file\nreturn 0\narguments -mF 100 test.zzip  replace_file_contents 2 \"A changed file.\"  set_file_mtime 2 1512998082\nfile test.zzip gap.zip gap-replace.zip\n"
  },
  {
    "path": "external/libzip/regress/clone-fs-add.test",
    "content": "# test cloning archive from filesystem, add new file\nprecheck ./can_clone_file\nreturn 0\narguments test.zzip  add new \"A new file.\"  set_file_mtime 3 1512998132\nfile test.zzip gap.zip gap-add.zip\n"
  },
  {
    "path": "external/libzip/regress/clone-fs-delete.test",
    "content": "# test cloning archive from filesystem, deleting a file\nprecheck ./can_clone_file\nreturn 0\narguments test.zzip  delete 2\nfile test.zzip gap.zip gap-delete.zip\n"
  },
  {
    "path": "external/libzip/regress/clone-fs-replace.test",
    "content": "# test cloning archive from filesystem, replacing a file\nprecheck ./can_clone_file\nreturn 0\narguments test.zzip  replace_file_contents 2 \"A changed file.\"  set_file_mtime 2 1512998082\nfile test.zzip gap.zip gap-replace.zip\n"
  },
  {
    "path": "external/libzip/regress/cm-default.test",
    "content": "# test default compression stores if smaller\nreturn 0\narguments -n -- test.zip  add compressible aaaaaaaaaaaaaa  add uncompressible uncompressible  add_nul large-compressible 8200  add_file large-uncompressible large-uncompressible 0 -1\nfile test.zip {} cm-default.zip\nfile large-uncompressible large-uncompressible\n"
  },
  {
    "path": "external/libzip/regress/convert_to_torrentzip.test",
    "content": "# convert file to torrentzip\nreturn 0\narguments testfile.zzip set_archive_flag want-torrentzip 1\nfile testfile.zzip testfile.zip testfile-torrentzip.zip\n"
  },
  {
    "path": "external/libzip/regress/convert_to_torrentzip_ef.test",
    "content": "# convert file to torrentzip, removing extra fields, internal & external file attributes\nreturn 0\narguments testfile.zzip set_archive_flag want-torrentzip 1\nfile testfile.zzip testfile-ef.zip testfile-torrentzip.zip\n"
  },
  {
    "path": "external/libzip/regress/count_entries.test",
    "content": "# zip_open: count entries for archive with >65k entries\narguments manyfiles.zip get_num_entries 0\nreturn 0\nfile manyfiles.zip manyfiles.zip\nstdout\n70000 entries in archive\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/create_empty_keep.test",
    "content": "# delete last entry in zip archive\nreturn 0\narguments -n testfile.zzip  set_archive_flag create-or-keep-file-for-empty-archive 1\nfile testfile.zzip {} testempty.zip\n"
  },
  {
    "path": "external/libzip/regress/decrypt-correct-password-aes128.test",
    "content": "# test AES decryption support, extract file using correct password\nfeatures HAVE_CRYPTO\nreturn 0\narguments encrypt.zzip  set_password foofoofoo  cat 1\nfile encrypt.zzip encrypt-aes128.zip\nstdout\nencrypted\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-correct-password-aes192.test",
    "content": "# test AES decryption support, extract file using correct password\nfeatures HAVE_CRYPTO\nreturn 0\narguments encrypt.zzip  set_password foofoofoo  cat 1\nfile encrypt.zzip encrypt-aes192.zip\nstdout\nencrypted\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-correct-password-aes256.test",
    "content": "# test AES decryption support, extract file using correct password\nfeatures HAVE_CRYPTO\nreturn 0\narguments encrypt.zzip  set_password foofoofoo  cat 1\nfile encrypt.zzip encrypt-aes256.zip\nstdout\nencrypted\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-correct-password-pkware-2.test",
    "content": "# test decryption support, extract file using correct password\nreturn 0\narguments encrypt.zzip  set_password 1234  cat 0\nfile encrypt.zzip encrypt-1234.zip\nstdout\nI would love to try or hear the sample audio your app can produce. I do not want to purchase, because I've purchased so many apps that say they do something and do not deliver.  \n\nCan you please add audio samples with text you've converted? I'd love to see the end results.\n\nThanks!\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-correct-password-pkware.test",
    "content": "# test decryption support, extract file using correct password\nreturn 0\narguments encrypt.zzip  set_password foo  cat 0\nfile encrypt.zzip encrypt.zip\nstdout\nfoo\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-empty-file-pkware.test",
    "content": "# test decryption support, extract empty file using correct password\nreturn 0\narguments empty-pkware.zzip  set_password 1  cat 0\nfile empty-pkware.zzip empty-pkware.zip\nstdout\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-no-password-aes256.test",
    "content": "# test AES decryption support, no password provided\nfeatures HAVE_CRYPTO\nreturn 1\narguments encrypt.zzip  cat 1\nfile encrypt.zzip encrypt-aes256.zip\nstderr\ncan't open file at index '1': No password provided\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-wrong-password-aes128.test",
    "content": "# test AES decryption support, extract file using wrong password\nfeatures HAVE_CRYPTO\nreturn 1\narguments encrypt.zzip  set_password notfoonotfoo  cat 1\nfile encrypt.zzip encrypt-aes128.zip\nstderr\ncan't open file at index '1': Wrong password provided\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-wrong-password-aes192.test",
    "content": "# test AES decryption support, extract file using wrong password\nfeatures HAVE_CRYPTO\nreturn 1\narguments encrypt.zzip  set_password notfoonotfoo  cat 1\nfile encrypt.zzip encrypt-aes192.zip\nstderr\ncan't open file at index '1': Wrong password provided\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-wrong-password-aes256.test",
    "content": "# test AES decryption support, extract file using wrong password\nfeatures HAVE_CRYPTO\nreturn 1\narguments encrypt.zzip  set_password notfoonotfoo  cat 1\nfile encrypt.zzip encrypt-aes256.zip\nstderr\ncan't open file at index '1': Wrong password provided\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-wrong-password-pkware-2.test",
    "content": "# test decryption support, extract file using wrong password (correct: \"1234\")\n# In some cases, like this one, the password, even if incorrect, passes the\n# minimal verification that's possible due to the zip file format specification.\nreturn 1\narguments encrypt.zzip  set_password sample  cat 0\nfile encrypt.zzip encrypt-1234.zip\nstderr\ncan't read file at index '0': Zlib error: data error\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/decrypt-wrong-password-pkware.test",
    "content": "# test decryption support, extract file using wrong password\nreturn 1\narguments encrypt.zzip  set_password notfoo  cat 0\nfile encrypt.zzip encrypt.zip\nstderr\ncan't open file at index '0': Wrong password provided\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/delete_add_same.test",
    "content": "# delete entry in zip archive then add file of same name\n# time is now(), so use zipcmp\nreturn 0\narguments testfile.zip delete 0 add testfile.txt test\nfile testfile.zip testfile.zip test2.zip\n"
  },
  {
    "path": "external/libzip/regress/delete_invalid.test",
    "content": "# delete last entry in zip archive\nreturn 1\narguments testfile.zzip delete 5\nfile testfile.zzip testfile.zip\nstderr\ncan't delete file at index '5': Invalid argument\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/delete_last.test",
    "content": "# delete last entry in zip archive\nreturn 0\narguments testfile.zzip delete 0\nfile testfile.zzip testfile.zip {}\n"
  },
  {
    "path": "external/libzip/regress/delete_last_keep.test",
    "content": "# delete last entry in zip archive\nreturn 0\narguments testfile.zzip  set_archive_flag create-or-keep-file-for-empty-archive 1  delete 0\nfile testfile.zzip testfile.zip testempty.zip\n"
  },
  {
    "path": "external/libzip/regress/delete_multiple_last.test",
    "content": "# delete multiple entries in zip archive, emptying it\nreturn 0\narguments testfile.zzip delete 0 delete 1 delete 2 delete 3\nfile testfile.zzip testcomment.zip {}\n"
  },
  {
    "path": "external/libzip/regress/delete_multiple_partial.test",
    "content": "# delete some entries in zip archive\nreturn 0\narguments testfile.zip delete 1 delete 3\nfile testfile.zip testcomment.zip testcomment13.zip\n"
  },
  {
    "path": "external/libzip/regress/delete_renamed_rename.test",
    "content": "# delete renamed entry in zip archive then rename file to same name\n# file date is now(), so use zipcmp\nreturn 0\narguments testfile.zip rename 0 something  add test test  delete 0  rename 1 testfile.txt\nfile testfile.zip testfile.zip test2.zip\n"
  },
  {
    "path": "external/libzip/regress/encrypt.test",
    "content": "# test encryption support\n# TODO: only checks recognition of encrypted entries for now.\nreturn 0\narguments encrypt.zzip stat 0 stat 1\nfile encrypt.zzip encrypt.zip\nstdout\nname: 'encrypted'\nindex: '0'\nsize: '4'\ncompressed size: '16'\nmtime: 'Mon Apr 24 2006 16:01:34'\ncrc: '7e3265a8'\ncompression method: '0'\nencryption method: '1'\n\nname: 'plain'\nindex: '1'\nsize: '4'\ncompressed size: '4'\nmtime: 'Mon Apr 24 2006 16:01:42'\ncrc: '7e3265a8'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/encryption-nonrandom-aes128.test",
    "content": "features HAVE_CRYPTO\nprecheck ./liboverride-test\ndescription encrypt file without entropy, to make results repeatable\nreturn 0\npreload nonrandomopen.so\narguments encrypt.zzip  set_file_encryption 1 AES-128 no-entropy\nfile encrypt.zzip encrypt-none.zip encrypt-aes128-noentropy.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-nonrandom-aes192.test",
    "content": "features HAVE_CRYPTO\nprecheck ./liboverride-test\ndescription encrypt file without entropy, to make results repeatable\nreturn 0\npreload nonrandomopen.so\narguments encrypt.zzip  set_file_encryption 1 AES-192 no-entropy\nfile encrypt.zzip encrypt-none.zip encrypt-aes192-noentropy.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-nonrandom-aes256.test",
    "content": "features HAVE_CRYPTO\nprecheck ./liboverride-test\ndescription encrypt file without entropy, to make results repeatable\nreturn 0\npreload nonrandomopen.so\narguments encrypt.zzip  set_file_encryption 1 AES-256 no-entropy\nfile encrypt.zzip encrypt-none.zip encrypt-aes256-noentropy.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-nonrandom-pkware-2.test",
    "content": "features HAVE_CRYPTO\nprecheck ./liboverride-test\ndescription encrypt file by Traditional PKWare, set mtime (used in PKWare encryption)\nreturn 0\npreload nonrandomopen.so\narguments encrypt.zzip set_file_mtime 1 1407272201 set_file_encryption 1 PKWARE no-entropy\nfile encrypt.zzip encrypt-none.zip encrypt-pkware-noentropy-2.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-nonrandom-pkware.test",
    "content": "features HAVE_CRYPTO\nprecheck ./liboverride-test\ndescription encrypt file by Traditional PKWARE\nreturn 0\npreload nonrandomopen.so\narguments encrypt.zzip set_file_encryption 1 PKWARE no-entropy\nfile encrypt.zzip encrypt-none.zip encrypt-pkware-noentropy.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-remove.test",
    "content": "# test AES decryption support, remove encryption from file that has it\nfeatures HAVE_CRYPTO\nreturn 0\narguments encrypt.zzip  set_password foofoofoo  set_file_encryption 1 none \"\"\nfile encrypt.zzip encrypt-aes128.zip encrypt-none.zip\n"
  },
  {
    "path": "external/libzip/regress/encryption-stat.test",
    "content": "features HAVE_CRYPTO\ndescription encrypt file, look at stat before commit\nreturn 0\narguments encrypt.zzip  stat 1  set_file_encryption 1 AES-128 no-entropy  stat 1  unchange_all\nfile encrypt.zzip encrypt-none.zip\nstdout\nname: 'encrypted'\nindex: '1'\nsize: '10'\ncompressed size: '10'\nmtime: 'Sat Jan 14 2017 21:27:26'\ncrc: 'fb8c5e55'\ncompression method: '0'\nencryption method: '0'\n\nname: 'encrypted'\nindex: '1'\nsize: '10'\ncompressed size: '10'\nmtime: 'Sat Jan 14 2017 21:27:26'\ncrc: 'fb8c5e55'\ncompression method: '0'\nencryption method: '257'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_add.test",
    "content": "# add extra field\n#args encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent\narguments encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent get_extra_by_id 0 2345 0 c get_extra_by_id 0 2345 0 l\nreturn 0\nfile encrypt.zip encrypt.zip encrypt_plus_extra.zip\nstdout\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_add_multiple.test",
    "content": "# add extra fields\narguments testfile.zip  set_extra 0 2345 65535 cl extra1  set_extra 0 2345 65535 cl extra2  set_extra 0 2345 0 c extra1c  set_extra 0 2345 1 l extra2l  get_extra_by_id 0 2345 0 c  get_extra_by_id 0 2345 1 c  get_extra_by_id 0 2345 0 l  get_extra_by_id 0 2345 1 l\nreturn 0\nfile testfile.zip testfile.zip testfile-plus-extra.zip\nstdout\nExtra field 0x0929: len 7, data 0x65787472613163\nExtra field 0x0929: len 6, data 0x657874726132\nExtra field 0x0929: len 6, data 0x657874726131\nExtra field 0x0929: len 7, data 0x6578747261326c\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_count.test",
    "content": "# count extra fields for index\narguments encrypt.zip count_extra 0 l count_extra 0 c count_extra 0 lc count_extra 1 l count_extra 1 c count_extra 1 lc\nreturn 0\nfile encrypt.zip encrypt.zip\nstdout\nExtra field count: 2\nExtra field count: 2\nExtra field count: 4\nExtra field count: 2\nExtra field count: 2\nExtra field count: 4\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_count_by_id.test",
    "content": "# count extra fields for index\narguments encrypt.zip count_extra_by_id 0 0 l count_extra_by_id 0 1 l count_extra_by_id 0 21589 l count_extra_by_id 0 30805 l count_extra_by_id 0 21844 l count_extra_by_id 0 12345 l count_extra_by_id 0 0 c count_extra_by_id 0 1 c count_extra_by_id 0 21589 c count_extra_by_id 0 30805 c count_extra_by_id 0 21844 c count_extra_by_id 0 12345 c count_extra_by_id 0 0 cl count_extra_by_id 0 1 cl count_extra_by_id 0 21589 cl count_extra_by_id 0 30805 cl count_extra_by_id 0 21844 cl count_extra_by_id 0 12345 cl\nreturn 0\nfile encrypt.zip encrypt.zip\nstdout\nExtra field count: 0\nExtra field count: 0\nExtra field count: 1\nExtra field count: 1\nExtra field count: 0\nExtra field count: 0\nExtra field count: 0\nExtra field count: 0\nExtra field count: 1\nExtra field count: 1\nExtra field count: 0\nExtra field count: 0\nExtra field count: 0\nExtra field count: 0\nExtra field count: 2\nExtra field count: 2\nExtra field count: 0\nExtra field count: 0\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_count_ignore_zip64.test",
    "content": "# count extra fields for index\narguments bigzero.zip count_extra 0 l count_extra 0 c count_extra 0 lc\nreturn 0\nfile bigzero.zip bigzero.zip\nstdout\nExtra field count: 0\nExtra field count: 0\nExtra field count: 0\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_delete.test",
    "content": "# delete extra field by index\narguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l delete_extra 0 2 c delete_extra 0 0 l get_extra 0 0 c get_extra 0 1 c get_extra 0 0 l get_extra 0 1 l\nfile encrypt.zip encrypt_plus_extra.zip encrypt.zip\nreturn 0\nstdout\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_delete_by_id.test",
    "content": "# delete extra field by id and index\n#args encrypt.zip set_extra 0 2345 65535 cl extrafieldcontent\narguments encrypt.zip delete_extra_by_id 0 2345 0 c delete_extra_by_id 0 2345 0 l get_extra_by_id 0 2345 0 c\nreturn 1\nfile encrypt.zip encrypt_plus_extra.zip encrypt.zip\nstderr\ncan't get extra field data for file at index 0, extra field id 2345, ef index 0, flags 512: No such file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_field_align.test",
    "content": "# try opening simulated Android APK zipaligned files, and similar inconsistent files\nprogram tryopen\nfile extra_field_align_1-0.zzip extra_field_align_1-0.zip\nfile extra_field_align_1-ff.zzip extra_field_align_1-ff.zip\nfile extra_field_align_2-0.zzip extra_field_align_2-0.zip\nfile extra_field_align_2-ff.zzip extra_field_align_2-ff.zip\nfile extra_field_align_3-0.zzip extra_field_align_3-0.zip\nfile extra_field_align_3-ff.zzip extra_field_align_3-ff.zip\nfile extra_field_align_4-ff.zzip extra_field_align_4-ff.zip\nfile extra_field_align_1-ef_00.zzip extra_field_align_1-ef_00.zip\nfile extra_field_align_1-ef_ff.zzip extra_field_align_1-ef_ff.zip\nfile extra_field_align_2-ef_00.zzip extra_field_align_2-ef_00.zip\nfile extra_field_align_2-ef_ff.zzip extra_field_align_2-ef_ff.zip\nfile extra_field_align_3-ef_00.zzip extra_field_align_3-ef_00.zip\nfile extra_field_align_3-ef_ff.zzip extra_field_align_3-ef_ff.zip\narguments -s -c extra_field_align_1-0.zzip extra_field_align_1-ff.zzip extra_field_align_2-0.zzip extra_field_align_2-ff.zzip extra_field_align_3-0.zzip extra_field_align_3-ff.zzip extra_field_align_4-ff.zzip extra_field_align_1-ef_00.zzip extra_field_align_1-ef_ff.zzip extra_field_align_2-ef_00.zzip extra_field_align_2-ef_ff.zzip extra_field_align_3-ef_00.zzip extra_field_align_3-ef_ff.zzip\nreturn 1\nstdout\nopening 'extra_field_align_1-0.zzip' succeeded, 1 entries\nopening 'extra_field_align_1-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nopening 'extra_field_align_2-0.zzip' succeeded, 1 entries\nopening 'extra_field_align_2-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nopening 'extra_field_align_3-0.zzip' succeeded, 1 entries\nopening 'extra_field_align_3-ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nopening 'extra_field_align_4-ff.zzip' succeeded, 1 entries\nopening 'extra_field_align_1-ef_00.zzip' succeeded, 1 entries\nopening 'extra_field_align_1-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nopening 'extra_field_align_2-ef_00.zzip' succeeded, 1 entries\nopening 'extra_field_align_2-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nopening 'extra_field_align_3-ef_00.zzip' succeeded, 1 entries\nopening 'extra_field_align_3-ef_ff.zzip' returned error Zip archive inconsistent: entry 0: garbage at end of extra fields\nend-of-inline-data\nstderr\n6 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_get.test",
    "content": "# get extra fields for index\narguments encrypt.zip get_extra 0 0 l get_extra 0 0 c get_extra 0 1 l get_extra 0 1 c get_extra 0 2 l\nreturn 1\nfile encrypt.zip encrypt.zip\nstdout\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x7855: len 0\nend-of-inline-data\nstderr\ncan't get extra field data for file at index 0, extra field 2, flags 256: No such file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_get_by_id.test",
    "content": "# get extra_by_id fields for index\narguments encrypt.zip get_extra_by_id 0 21589 0 l get_extra_by_id 0 30805 0 l get_extra_by_id 0 21589 0 c get_extra_by_id 0 30805 0 c get_extra_by_id 0 21544 0 c\nreturn 1\nfile encrypt.zip encrypt.zip\nstdout\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nend-of-inline-data\nstderr\ncan't get extra field data for file at index 0, extra field id 21544, ef index 0, flags 512: No such file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_set.test",
    "content": "# set extra field\narguments -- encrypt get_extra 0 0 c get_extra 0 1 c get_extra 0 0 l get_extra 0 1 l set_extra 0 2345 -1 l extrafieldcontent set_extra 0 2345 -1 c extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l\nfile encrypt encrypt.zip encrypt_plus_extra.zip\nreturn 0\nstdout\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_set_modify_c.test",
    "content": "# change existing central extra field\narguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l set_extra 0 2345 0 c Extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l\nfile encrypt.zip encrypt_plus_extra.zip encrypt_plus_extra_modified_c.zip\nreturn 0\nstdout\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x45787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/extra_set_modify_l.test",
    "content": "# change existing local extra field\narguments encrypt.zip get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l set_extra 0 2345 0 l Extrafieldcontent get_extra 0 0 c get_extra 0 1 c get_extra 0 2 c get_extra 0 0 l get_extra 0 1 l get_extra 0 2 l\nfile encrypt.zip encrypt_plus_extra.zip encrypt_plus_extra_modified_l.zip\nreturn 0\nstdout\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nExtra field 0x5455: len 5, data 0x033dda4c44\nExtra field 0x7855: len 0\nExtra field 0x0929: len 17, data 0x65787472616669656c64636f6e74656e74\nExtra field 0x0929: len 17, data 0x45787472616669656c64636f6e74656e74\nExtra field 0x5455: len 9, data 0x033dda4c444dda4c44\nExtra field 0x7855: len 4, data 0x64001400\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fdopen_ok.test",
    "content": "# zip_fdopen: stdin opens fine\n#program ../src/ziptool\narguments /dev/stdin stat 0\nreturn 0\nfile test.zip test.zip\nstdin test.zip\nstdout\nname: 'test'\nindex: '0'\nsize: '5'\ncompressed size: '5'\nmtime: 'Mon Oct 06 2003 15:46:42'\ncrc: '3bb935c6'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/file_comment_encmismatch.test",
    "content": "# set file comment to UTF-8 for CP437 encoded filename (adds InfoZIP extra field)\nreturn 0\narguments -i testfile.zip dummy\nstdin\nset_file_comment 0 ÄÖÜßäöü\nend-of-inline-data\nfile testfile.zip test-cp437.zip test-cp437-comment-utf-8.zip\n"
  },
  {
    "path": "external/libzip/regress/fopen_multiple.test",
    "content": "# read contents from multiply opened unchanged file\nreturn 0\narguments test_open_multiple.zip fopen stuff fopen stuff fread 0 2 fread 1 4 fread 0 3 fread 1 3 fread 0 3 fread 1 1 unchange_all\nfile test_open_multiple.zip test_open_multiple.zip\nstdout\nopened 'stuff' as file 0\nopened 'stuff' as file 1\nababcdcdeefgfghh\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fopen_multiple_reopen.test",
    "content": "# read contents from multiply reopened changed file\nreturn 0\narguments test_open_multiple.zip replace_file_contents 0 12345678 fopen stuff fopen stuff fread 0 2 fread 1 4 fread 0 3 fread 1 3 fread 0 3 fread 1 1 unchange_all\nfile test_open_multiple.zip test_open_multiple.zip\nstdout\nopened 'stuff' as file 0\nopened 'stuff' as file 1\n1212343455676788\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fopen_unchanged.c",
    "content": "/*\n  fopen_unchanged.c -- test case for adding file and reading from unchanged\n  Copyright (C) 2012-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zip.h\"\n\nconst char *teststr = \"This is a test.\\n\";\nconst char *file = \"teststring.txt\";\n\nint\nmain(int argc, char *argv[]) {\n    const char *archive;\n    zip_t *za;\n    zip_source_t *zs;\n    int err;\n\n    if (argc != 2) {\n        fprintf(stderr, \"usage: %s archive\\n\", argv[0]);\n        return 1;\n    }\n\n    archive = argv[1];\n\n    if ((za = zip_open(archive, ZIP_CREATE, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"can't open zip archive '%s': %s\\n\", archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return 1;\n    }\n\n    if ((zs = zip_source_buffer(za, teststr, strlen(teststr), 0)) == NULL) {\n        fprintf(stderr, \"can't create zip_source from buffer: %s\\n\", zip_strerror(za));\n        exit(1);\n    }\n\n    if (zip_file_add(za, file, zs, 0) == -1) {\n        fprintf(stderr, \"can't add file '%s': %s\\n\", file, zip_strerror(za));\n        (void)zip_source_free(zs);\n        (void)zip_close(za);\n        return 1;\n    }\n\n    if (zip_fopen(za, file, ZIP_FL_UNCHANGED) == NULL) {\n        fprintf(stderr, \"can't zip_fopen file '%s': %s\\n\", file, zip_strerror(za));\n        (void)zip_discard(za);\n        return 1;\n    }\n\n    if (zip_close(za) == -1) {\n        fprintf(stderr, \"can't close zip archive '%s': %s\\n\", archive, zip_strerror(za));\n        return 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/fopen_unchanged.test",
    "content": "# add buffer contents as file to zip, then read unchanged from it\nprogram fopen_unchanged\nreturn 1\narguments testbuffer.zip\nstderr\ncan't zip_fopen file 'teststring.txt': No such file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fread.c",
    "content": "/*\n  fread.c -- test cases for reading from zip archives\n  Copyright (C) 2004-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"config.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\n\n#include \"zip.h\"\n\nenum when { WHEN_NEVER, WHEN_OPEN, WHEN_READ, WHEN_CLOSE };\n\nconst char *when_name[] = {\"no\", \"zip_fopen\", \"zip_fread\", \"zip_fclose\"};\n\nstatic int do_read(zip_t *z, const char *name, zip_flags_t flags, enum when when_ex, int ze_ex, int se_ex);\n\nint verbose;\n\nconst char *progname;\n#define USAGE \"usage: %s [-v] archive\\n\"\n\nint\nmain(int argc, char *argv[]) {\n    int fail, ze;\n    int c;\n    zip_t *z;\n    zip_source_t *zs;\n    char *archive;\n    zip_int64_t idx;\n\n    verbose = 0;\n    fail = 0;\n\n    progname = argv[0];\n\n    while ((c = getopt(argc, argv, \"v\")) != -1) {\n        switch (c) {\n        case 'v':\n            verbose = 1;\n            break;\n\n        default:\n            fprintf(stderr, USAGE, progname);\n            return 1;\n        }\n    }\n\n\n    if (argc - optind != 1) {\n        fprintf(stderr, USAGE, progname);\n        return 1;\n    }\n\n    archive = argv[optind];\n\n    if ((z = zip_open(archive, 0, &ze)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, ze);\n        fprintf(stderr, \"%s: can't open zip archive '%s': %s\\n\", progname, archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return 1;\n    }\n\n    fail += do_read(z, \"storedok\", 0, WHEN_NEVER, 0, 0);\n    fail += do_read(z, \"deflateok\", 0, WHEN_NEVER, 0, 0);\n    fail += do_read(z, \"storedcrcerror\", 0, WHEN_READ, ZIP_ER_CRC, 0);\n    fail += do_read(z, \"deflatecrcerror\", 0, WHEN_READ, ZIP_ER_CRC, 0);\n    fail += do_read(z, \"deflatezliberror\", 0, WHEN_READ, ZIP_ER_ZLIB, -3);\n#ifndef __clang_analyzer__ /* This test intentionally violates nullability. */\n    fail += do_read(z, NULL, 0, WHEN_OPEN, ZIP_ER_INVAL, 0);\n#endif\n    fail += do_read(z, \"nosuchfile\", 0, WHEN_OPEN, ZIP_ER_NOENT, 0);\n    fail += do_read(z, \"deflatezliberror\", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0);\n    fail += do_read(z, \"deflatecrcerror\", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0);\n    fail += do_read(z, \"storedcrcerror\", ZIP_FL_COMPRESSED, WHEN_READ, ZIP_ER_CRC, 0);\n    fail += do_read(z, \"storedok\", ZIP_FL_COMPRESSED, WHEN_NEVER, 0, 0);\n\n    fail += do_read(z, \"cryptok\", 0, WHEN_OPEN, ZIP_ER_NOPASSWD, 0);\n    zip_set_default_password(z, \"crypt\");\n    fail += do_read(z, \"cryptok\", 0, WHEN_NEVER, 0, 0);\n    zip_set_default_password(z, \"wrong\");\n    fail += do_read(z, \"cryptok\", 0, WHEN_OPEN, ZIP_ER_WRONGPASSWD, 0);\n    zip_set_default_password(z, NULL);\n\n    zs = zip_source_buffer(z, \"asdf\", 4, 0);\n    if ((idx = zip_name_locate(z, \"storedok\", 0)) < 0) {\n        fprintf(stderr, \"%s: can't locate 'storedok' in zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n        fail++;\n    }\n    else {\n        if (zip_file_replace(z, (zip_uint64_t)idx, zs, 0) < 0) {\n            fprintf(stderr, \"%s: can't replace 'storedok' in zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n            fail++;\n        }\n        else {\n            fail += do_read(z, \"storedok\", 0, WHEN_NEVER, 0, 0);\n            fail += do_read(z, \"storedok\", ZIP_FL_UNCHANGED, WHEN_NEVER, 0, 0);\n        }\n    }\n    if ((idx = zip_name_locate(z, \"storedok\", 0)) < 0) {\n        fprintf(stderr, \"%s: can't locate 'storedok' in zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n        fail++;\n    }\n    else {\n        if (zip_delete(z, (zip_uint64_t)idx) < 0) {\n            fprintf(stderr, \"%s: can't replace 'storedok' in zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n            fail++;\n        }\n        else {\n            fail += do_read(z, \"storedok\", 0, WHEN_OPEN, ZIP_ER_NOENT, 0);\n            fail += do_read(z, \"storedok\", ZIP_FL_UNCHANGED, WHEN_NEVER, 0, 0);\n        }\n    }\n    zs = zip_source_buffer(z, \"asdf\", 4, 0);\n    if (zip_file_add(z, \"new_file\", zs, 0) < 0) {\n        fprintf(stderr, \"%s: can't add file to zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n        fail++;\n    }\n    else {\n        fail += do_read(z, \"new_file\", 0, WHEN_NEVER, 0, 0);\n    }\n\n    zip_unchange_all(z);\n    if (zip_close(z) == -1) {\n        fprintf(stderr, \"%s: can't close zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n        return 1;\n    }\n\n    exit(fail ? 1 : 0);\n}\n\n\nstatic int\ndo_read(zip_t *z, const char *name, zip_flags_t flags, enum when when_ex, int ze_ex, int se_ex) {\n    zip_file_t *zf;\n    enum when when_got;\n    zip_error_t error_got, error_ex;\n    zip_error_t *zf_error;\n    int err;\n    char b[8192];\n    zip_int64_t n;\n\n    when_got = WHEN_NEVER;\n    zip_error_init(&error_got);\n    zip_error_init(&error_ex);\n    zip_error_set(&error_ex, ze_ex, se_ex);\n\n    if ((zf = zip_fopen(z, name, flags)) == NULL) {\n        when_got = WHEN_OPEN;\n        zf_error = zip_get_error(z);\n        zip_error_set(&error_got, zip_error_code_zip(zf_error), zip_error_code_system(zf_error));\n    }\n    else {\n        while ((n = zip_fread(zf, b, sizeof(b))) > 0)\n            ;\n        if (n < 0) {\n            when_got = WHEN_READ;\n            zf_error = zip_file_get_error(zf);\n            zip_error_set(&error_got, zip_error_code_zip(zf_error), zip_error_code_system(zf_error));\n        }\n        err = zip_fclose(zf);\n        if (when_got == WHEN_NEVER && err != 0) {\n            when_got = WHEN_CLOSE;\n            zip_error_init_with_code(&error_got, err);\n        }\n    }\n\n    if (when_got != when_ex || zip_error_code_zip(&error_got) != zip_error_code_zip(&error_ex) || zip_error_code_system(&error_got) != zip_error_code_system(&error_ex)) {\n        printf(\"%s: %s: got %s error (%s), expected %s error (%s)\\n\", progname, name, when_name[when_got], zip_error_strerror(&error_got), when_name[when_ex], zip_error_strerror(&error_ex));\n        zip_error_fini(&error_got);\n        zip_error_fini(&error_ex);\n        return 1;\n    }\n    else if (verbose)\n        printf(\"%s: %s: passed\\n\", progname, name);\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/fread.test",
    "content": "# various tests for zip_fread\nprogram fread\narguments broken.zip\nreturn 0\nfile broken.zip broken.zip\n"
  },
  {
    "path": "external/libzip/regress/fseek.c",
    "content": "/*\n  fseek.c -- test tool for seeking in zip archives\n  Copyright (C) 2016-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdlib.h>\n\n#include \"zip.h\"\n\nconst char *progname;\n#define USAGE \"usage: %s archive index offset\\n\"\n\nint\nmain(int argc, char *argv[]) {\n    int ze;\n    zip_t *z;\n    zip_file_t *zf;\n    char *archive;\n    zip_int64_t offset, n;\n    zip_uint64_t index;\n    char b[1024];\n\n    progname = argv[0];\n\n    if (argc != 4) {\n        fprintf(stderr, USAGE, progname);\n        return 1;\n    }\n\n    archive = argv[1];\n    index = strtoull(argv[2], NULL, 10);\n    offset = (zip_int64_t)strtoull(argv[3], NULL, 10);\n\n    if ((z = zip_open(archive, 0, &ze)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, ze);\n        fprintf(stderr, \"%s: can't open zip archive '%s': %s\\n\", progname, archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return 1;\n    }\n\n    if ((zf = zip_fopen_index(z, index, 0)) == NULL) {\n        fprintf(stderr, \"%s: can't open file in archive '%s': %s\\n\", progname, archive, zip_error_strerror(zip_file_get_error(zf)));\n        zip_close(z);\n        return 1;\n    }\n\n    if (zip_fseek(zf, offset, SEEK_SET) < 0) {\n        fprintf(stderr, \"%s: zip_fseek failed: %s\\n\", progname, zip_error_strerror(zip_file_get_error(zf)));\n        zip_fclose(zf);\n        zip_close(z);\n        return 1;\n    }\n\n    while ((n = zip_fread(zf, b, sizeof(b))) > 0) {\n        printf(\"%.*s\", (int)n, b);\n    }\n    if (n < 0) {\n        fprintf(stderr, \"%s: zip_fread failed: %s\\n\", progname, zip_error_strerror(zip_file_get_error(zf)));\n        zip_fclose(zf);\n        zip_close(z);\n        return 1;\n    }\n\n    if (zip_fclose(zf) == -1) {\n        fprintf(stderr, \"%s: can't close zip archive entry %\" PRIu64 \" in '%s': %s\\n\", progname, index, archive, zip_strerror(z));\n        return 1;\n    }\n\n    if (zip_close(z) == -1) {\n        fprintf(stderr, \"%s: can't close zip archive '%s': %s\\n\", progname, archive, zip_strerror(z));\n        return 1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/fseek_deflated.test",
    "content": "# unsuccessful fseek test because data is compressed\nprogram fseek\narguments test.zip 0 2\nreturn 1\nfile test.zip testdeflated.zip\nstderr\nzip_fseek failed: Operation not supported\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fseek_fail.test",
    "content": "# successful fseek test\nprogram fseek\narguments test.zip 0 8\nreturn 1\nfile test.zip test.zip\nstderr\nzip_fseek failed: Invalid argument\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/fseek_ok.test",
    "content": "# successful fseek test\nprogram fseek\narguments test.zip 0 2\nreturn 0\nfile test.zip test.zip\nstdout\nst\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/get_comment.test",
    "content": "# show comments of a zip archive\nreturn 0\narguments testcomment.zip   get_archive_comment   get_file_comment 0   get_file_comment 1   get_file_comment 2   get_file_comment 3\nfile testcomment.zip testcomment.zip\nstdout\nArchive comment: This is the archive comment for the file.\r\n\r\nLong.\r\n\r\nLonger.\r\n\nNo comment for 'file1'\nFile comment for 'file2': First one had no comment.\nFile comment for 'file3': Third one.\nFile comment for 'file4': Last.\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/get_comment_long.test",
    "content": "# show long archive comment of a zip archive\nreturn 0\narguments testfile.zip   get_archive_comment\nfile testfile.zip testfile-long-comment.zip\nstdout\nArchive comment: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/hmac-error.test",
    "content": "description test file that has an HMAC error\nreturn 1\narguments hmac-error.zip  set_password 1234  cat 0\nfile hmac-error.zip hmac-error.zip\nstdout\nThe quick brown fox jumps over t qu\u0004azy dog\nend-of-inline-data\nstderr\ncan't read file at index '0': CRC error\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/hole.c",
    "content": "/*\n hole.c -- convert huge files with mostly NULs to/from source_hole\n Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include \"config.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\n\n#include \"zip.h\"\n\n/* public API */\n\nzip_source_t *source_hole_create(const char *, int flags, zip_error_t *);\n\nconst char *progname;\n\n\nstatic int\ncopy_source(zip_source_t *from, zip_source_t *to) {\n    zip_uint8_t buf[8192];\n    zip_int64_t n;\n\n    if (zip_source_open(from) < 0) {\n        fprintf(stderr, \"%s: can't open source for reading: %s\\n\", progname, zip_error_strerror(zip_source_error(from)));\n        return -1;\n    }\n\n    if (zip_source_begin_write(to) < 0) {\n        fprintf(stderr, \"%s: can't open source for writing: %s\\n\", progname, zip_error_strerror(zip_source_error(to)));\n        zip_source_close(from);\n        return -1;\n    }\n\n    while ((n = zip_source_read(from, buf, sizeof(buf))) > 0) {\n        if (zip_source_write(to, buf, (zip_uint64_t)n) != n) {\n            fprintf(stderr, \"%s: can't write to source: %s\\n\", progname, zip_error_strerror(zip_source_error(to)));\n            zip_source_close(from);\n            zip_source_rollback_write(to);\n            return -1;\n        }\n    }\n\n    if (n < 0) {\n        fprintf(stderr, \"%s: can't read from source: %s\\n\", progname, zip_error_strerror(zip_source_error(from)));\n        zip_source_close(from);\n        zip_source_rollback_write(to);\n        return -1;\n    }\n\n    zip_source_close(from);\n\n    if (zip_source_commit_write(to) < 0) {\n        fprintf(stderr, \"%s: can't commit source: %s\\n\", progname, zip_error_strerror(zip_source_error(to)));\n        zip_source_rollback_write(to);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nstatic zip_source_t *\nopen_compressed(const char *fname, int flags) {\n    zip_error_t error;\n    zip_source_t *src;\n\n    zip_error_init(&error);\n\n    if ((src = source_hole_create(fname, flags, &error)) == NULL) {\n        fprintf(stderr, \"%s: can't open compressed file %s: %s\\n\", progname, fname, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        exit(1);\n    }\n\n    return src;\n}\n\n\nstatic zip_source_t *\nopen_file(const char *fname) {\n    zip_error_t error;\n    zip_source_t *src;\n\n    zip_error_init(&error);\n\n    if ((src = zip_source_file_create(fname, 0, 0, &error)) == NULL) {\n        fprintf(stderr, \"%s: can't open file %s: %s\\n\", progname, fname, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        exit(1);\n    }\n\n    return src;\n}\n\n\nstatic void\nusage(void) {\n    fprintf(stderr, \"usage: %s [-du] in out\\n\", progname);\n    fprintf(stderr, \"\\nOptions:\\n  -d  decompress in\\n  -u  update in\\n\");\n    exit(1);\n}\n\n\nint\nmain(int argc, char **argv) {\n    zip_source_t *from;\n    zip_source_t *to;\n    int c, err;\n    int compress = 1;\n    int decompress = 0;\n\n    progname = argv[0];\n\n    while ((c = getopt(argc, argv, \"du\")) != -1) {\n        switch (c) {\n        case 'd':\n            compress = 0;\n            decompress = 1;\n            break;\n\n        case 'u':\n            compress = 1;\n            decompress = 1;\n            break;\n\n        default:\n            usage();\n            break;\n        }\n    }\n\n    if (optind + 2 != argc) {\n        usage();\n    }\n\n    if (decompress) {\n        from = open_compressed(argv[optind], 0);\n    }\n    else {\n        from = open_file(argv[optind]);\n    }\n\n    if (compress) {\n        to = open_compressed(argv[optind + 1], ZIP_CREATE);\n    }\n    else {\n        to = open_file(argv[optind + 1]);\n    }\n\n    err = copy_source(from, to);\n\n    zip_source_free(from);\n    zip_source_free(to);\n\n    exit(err < 0 ? 1 : 0);\n}\n"
  },
  {
    "path": "external/libzip/regress/junk_at_end.test",
    "content": "# test archive with junk at end of file\narguments -l 412 junk-at-end.zzip get_num_entries 0\nreturn 0\nfile junk-at-end.zzip junk-at-end.zip\nstdout\n3 entries in archive\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/junk_at_start.test",
    "content": "# test archive with junk at start of file\narguments -o 4 junk-at-start.zzip get_num_entries 0\nreturn 0\nfile junk-at-start.zzip junk-at-start.zip\nstdout\n3 entries in archive\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/liboverride-test.c",
    "content": "/*\n  liboverride.c -- override function called by zip_open()\n\n  Copyright (C) 2017-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of ckmame, a program to check rom sets for MAME.\n  The authors can be contacted at <ckmame@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The name of the author may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef _WIN32\nint main(int argc, const char *argv[]) {\n    /* Symbol override is not supported on Windows. */\n    if (argc > 1 && strcmp(argv[1], \"-v\") == 0) {\n        printf(\"not supported on Windows\\n\");\n    }\n    exit(1);\n}\n#else\n\n#include <errno.h>\n#include <unistd.h>\n\n#include \"zip.h\"\n\n/*\n Some systems bind functions called and defined within a shared library, so the override doesn't work. This program calls zip_open and checks whether the override worked.\n */\n\nint\nmain(int argc, const char *argv[]) {\n    int verbose = 0;\n    int error_code;\n    \n    if (argc > 1 && strcmp(argv[1], \"-v\") == 0) {\n        verbose = 1;\n    }\n    \n    if (getenv(\"LIBOVERRIDE_SET\") == NULL) {\n        char *cwd = getcwd(NULL, 0);\n        size_t so_size = strlen(cwd) + 64;\n        char *so = (char *)malloc(so_size);\n        if (so == NULL) {\n            if (verbose) {\n                printf(\"malloc failed\\n\");\n            }\n            exit(2);\n        }\n        snprintf(so, so_size, \"%s/libliboverride.so\", cwd);\n        setenv(\"LIBOVERRIDE_SET\", \"1\", 1);\n        setenv(\"LD_PRELOAD\", so, 1);\n        execv(argv[0], (void *)argv);\n        if (verbose) {\n            printf(\"exec failed: %s\\n\", strerror(errno));\n        }\n        exit(2);\n    }\n    \n    if (zip_open(\"nosuchfile\", 0, &error_code) != NULL) {\n        /* We expect failure. */\n        if (verbose) {\n            printf(\"open succeeded\\n\");\n        }\n        exit(1);\n    }\n    if (error_code != 32000) {\n        /* Override didn't take, we didn't get its magic error code. */\n        if (verbose) {\n            printf(\"got unexpected error %d\\n\", error_code);\n        }\n        exit(1);\n    }\n    \n    if (verbose) {\n        printf(\"success\\n\");\n    }\n    exit(0);\n}\n\n#endif /* not Windows */\n"
  },
  {
    "path": "external/libzip/regress/liboverride.c",
    "content": "/*\n  liboverride.c -- override function called by zip_open()\n\n  Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner\n\n  This file is part of ckmame, a program to check rom sets for MAME.\n  The authors can be contacted at <ckmame@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The name of the author may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n/*\n Some systems bind functions called and defined within a shared library, so the override doesn't work. This overrides a function called by zip_open to return an invalid error code so we can check whether the override works.\n */\n\nzip_source_t *\nzip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {\n    if (error != NULL) {\n        error->zip_err = 32000;\n    }\n    \n    return NULL;\n}\n"
  },
  {
    "path": "external/libzip/regress/malloc.c",
    "content": "/*\n  malloc.c -- override *alloc() to allow testing special cases\n  Copyright (C) 2015-2021 Dieter Baron and Thomas Klausner\n\n  This file is part of ckmame, a program to check rom sets for MAME.\n  The authors can be contacted at <ckmame@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The name of the author may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n/* #include <string.h> */\n#include <errno.h>\n#define __USE_GNU\n#include <dlfcn.h>\n#undef __USE_GNU\n\n#include \"config.h\"\n\n#if !defined(RTLD_NEXT)\n#define RTLD_NEXT RTLD_DEFAULT\n#endif\n\n#if defined(HAVE___PROGNAME)\nextern char *__progname;\n#endif\n\n#if defined(HAVE_GETPROGNAME)\n/* all fine */\n#else\nconst char *\ngetprogname(void) {\n#if defined(HAVE___PROGNAME)\n    return __progname;\n#else\n    return NULL;\n#endif\n}\n#endif\n\nstatic int inited = 0;\nstatic size_t count = 0;\nstatic size_t max_count = 0;\nstatic size_t min_size = 0;\nstatic void *(*real_malloc)(size_t size) = NULL;\nstatic void *(*real_calloc)(size_t number, size_t size) = NULL;\nstatic void *(*real_realloc)(void *ptr, size_t size) = NULL;\n\nstatic const char *myname = NULL;\n\n/* TODO: add sentinel -- check if particular size is malloced before doing other stuff */\n/* TODO: catch free for sentinel too */\n/* TODO: optionally, catch malloc of particular size */\n\nstatic void\ninit(void) {\n    char *foo;\n    myname = getprogname();\n    if (!myname)\n        myname = \"(unknown)\";\n    if ((foo = getenv(\"MALLOC_MAX_COUNT\")) != NULL)\n        max_count = strtoul(foo, NULL, 0);\n    if ((foo = getenv(\"MALLOC_MIN_SIZE\")) != NULL)\n        min_size = strtoul(foo, NULL, 0);\n    real_calloc = dlsym(RTLD_NEXT, \"calloc\");\n    if (!real_calloc)\n        abort();\n    real_malloc = dlsym(RTLD_NEXT, \"malloc\");\n    if (!real_malloc)\n        abort();\n    real_realloc = dlsym(RTLD_NEXT, \"realloc\");\n    if (!real_realloc)\n        abort();\n    inited = 1;\n}\n\nvoid *\ncalloc(size_t number, size_t size) {\n    void *ret;\n\n    if (!inited) {\n        init();\n    }\n\n    if (number >= min_size / size && count >= max_count) {\n        errno = ENOMEM;\n        return NULL;\n    }\n\n    ret = real_calloc(number, size);\n    if (size >= min_size) {\n        count++;\n    }\n\n    return ret;\n}\n\nvoid *\nmalloc(size_t size) {\n    void *ret;\n\n    if (!inited) {\n        init();\n    }\n\n    if (size >= min_size && count >= max_count) {\n        errno = ENOMEM;\n        return NULL;\n    }\n\n    ret = real_malloc(size);\n    if (size >= min_size) {\n        count++;\n    }\n\n    return ret;\n}\n\nvoid *\nrealloc(void *ptr, size_t size) {\n    void *ret;\n\n    if (!inited) {\n        init();\n    }\n\n    if (size >= min_size && count >= max_count) {\n        errno = ENOMEM;\n        return NULL;\n    }\n\n    ret = real_realloc(ptr, size);\n    if (size >= min_size) {\n        count++;\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "external/libzip/regress/mtime-dstpoint.test",
    "content": "description change method from stored to deflated, which will change the timestamp because it is at a DST point and not valid in that time zone\nenvironment-set TZ America/New_York\n# setting it to a European timezone, where there is no DST change at this point, works\n#environment-set TZ Europe/Zurich\nreturn 0\narguments test.zzip  set_file_compression 0 deflate 0\nfile test.zzip mtime-dstpoint.zip mtime-dstpoint-deflated.zip\n"
  },
  {
    "path": "external/libzip/regress/mtime-post-dstpoint.test",
    "content": "description change method from stored to deflated, for a file one hour after DST change\nenvironment-set TZ America/New_York\nreturn 0\narguments test.zzip  set_file_compression 0 deflate 0\nfile test.zzip mtime-post-dstpoint.zip mtime-post-dstpoint-deflated.zip\n"
  },
  {
    "path": "external/libzip/regress/mtime-pre-dstpoint.test",
    "content": "description change method from stored to deflated, for a file one hour before DST change\nenvironment-set TZ America/New_York\nreturn 0\narguments test.zzip  set_file_compression 0 deflate 0\nfile test.zzip mtime-pre-dstpoint.zip mtime-pre-dstpoint-deflated.zip\n"
  },
  {
    "path": "external/libzip/regress/name_locate-cp437.test",
    "content": "description tests for various encoding flags for zip_name_locate\narguments -x test.zip  name_locate \"9192939495969798999A9B9C9D9E9FA0\" 0  name_locate \"9192939495969798999A9B9C9D9E9FA0\" 4  name_locate \"9192939495969798999A9B9C9D9E9FA0\" 8  name_locate \"9192939495969798999A9B9C9D9E9FA0\" r  name_locate \"9192939495969798999A9B9C9D9E9FA0\" s\nreturn 0\nfile test.zip test-cp437.zip\nstdout\nname '9192939495969798999A9B9C9D9E9FA0' using flags '0' found at index 9\nname '9192939495969798999A9B9C9D9E9FA0' using flags '4' found at index 9\nname '9192939495969798999A9B9C9D9E9FA0' using flags 'r' found at index 9\nname '9192939495969798999A9B9C9D9E9FA0' using flags 's' found at index 9\nend-of-inline-data\nstderr\ncan't find entry with name '9192939495969798999A9B9C9D9E9FA0' using flags '8'\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/name_locate-utf8.test",
    "content": "description tests for various encoding flags for zip_name_locate\narguments -i test.zip dummy\nstdin\nname_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 0  name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 4  name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá 8  name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá r  name_locate æÆôöòûùÿÖÜ¢£¥₧ƒá s\nend-of-inline-data\nreturn 0\nfile test.zip test-cp437.zip\nstdout\nname 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '0' found at index 9\nname 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '8' found at index 9\nname 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags 's' found at index 9\nend-of-inline-data\nstderr\ncan't find entry with name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags '4'\ncan't find entry with name 'æÆôöòûùÿÖÜ¢£¥₧ƒá' using flags 'r'\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/name_locate.test",
    "content": "# various tests for zip_name_locate\narguments test.zip  name_locate nosuchfile 0  name_locate test 0  name_locate \"\" 0  name_locate TeSt 0  name_locate TeSt C  name_locate testdir/test2 0  name_locate tesTdir/tESt2 C  name_locate testdir/test2 d  name_locate tesTdir/tESt2 dC  name_locate test2 0  name_locate test2 d  name_locate TeST2 dC  delete 0  name_locate test 0  name_locate test u  add new teststring  name_locate new 0  name_locate new u  add \"\" teststring  name_locate \"\" 0  unchange_all  name_locate test 0  name_locate new 0\n# delete 0\n# add \"new\"\n# add \"\"\n# unchange all\nreturn 0\nfile test.zip test.zip\nstdout\nname 'test' using flags '0' found at index 0\nname 'TeSt' using flags 'C' found at index 0\nname 'testdir/test2' using flags '0' found at index 2\nname 'tesTdir/tESt2' using flags 'C' found at index 2\nname 'test2' using flags 'd' found at index 2\nname 'TeST2' using flags 'dC' found at index 2\nname 'test' using flags 'u' found at index 0\nname 'new' using flags '0' found at index 3\nname '' using flags '0' found at index 4\nname 'test' using flags '0' found at index 0\nend-of-inline-data\nstderr\ncan't find entry with name 'nosuchfile' using flags '0'\ncan't find entry with name '' using flags '0'\ncan't find entry with name 'TeSt' using flags '0'\ncan't find entry with name 'testdir/test2' using flags 'd'\ncan't find entry with name 'tesTdir/tESt2' using flags 'dC'\ncan't find entry with name 'test2' using flags '0'\ncan't find entry with name 'test' using flags '0'\ncan't find entry with name 'new' using flags 'u'\ncan't find entry with name 'new' using flags '0'\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/nihtest.conf.in",
    "content": "[settings]\nfeatures-files = @PROJECT_BINARY_DIR@/config.h\ntest-input-directories = @CMAKE_CURRENT_SOURCE_DIR@\nprogram-directories = @PROJECT_BINARY_DIR@/regress\n    @PROJECT_BINARY_DIR@/regress/Release\n    @PROJECT_BINARY_DIR@/regress/Debug\n    @PROJECT_BINARY_DIR@/src\n    @PROJECT_BINARY_DIR@/src/Release\n    @PROJECT_BINARY_DIR@/src/Debug\ndefault-program = ziptool_regress\ndefault-stderr-replace = \"^([A-Z]:)?[^ :]*: \" \"\"\n\n[comparators]\nzip.zip = zipcmp -pv\n"
  },
  {
    "path": "external/libzip/regress/nonrandomopen.c",
    "content": "/*\n  nonrandomopen.c -- override zip_secure_random\n\n  Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner\n\n  This file is part of ckmame, a program to check rom sets for MAME.\n  The authors can be contacted at <ckmame@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The name of the author may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <string.h>\n\n#include \"zipint.h\"\n\nbool\nzip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {\n    memset(buffer, 0, length);\n\n    return true;\n}\n"
  },
  {
    "path": "external/libzip/regress/nonrandomopentest.c",
    "content": "/*\n  nonrandomopentest.c -- test nonrandomopen.so\n  Copyright (C) 2017-2021 Dieter Baron and Thomas Klausner\n\n  This file is part of ckmame, a program to check rom sets for MAME.\n  The authors can be contacted at <ckmame@nih.at>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The name of the author may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"zipint.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n\nint\nmain(int argc, const char *argv[]) {\n    zip_uint8_t buf[1024];\n    int i;\n\n#ifdef HAVE_CRYPTO\n    if (!zip_secure_random(buf, sizeof(buf))) {\n        fprintf(stderr, \"zip_secure_random returned false\\n\");\n        exit(1);\n    }\n    for (i = 0; i < sizeof(buf); i++) {\n        if (buf[i] != 0) {\n            fprintf(stderr, \"non-zero byte found\\n\");\n            exit(1);\n        }\n    }\n#endif\n    exit(0);\n}\n"
  },
  {
    "path": "external/libzip/regress/open_archive_comment_wrong.test",
    "content": "# zip_open: file with wrong archive comment length, no consistency check: opens fine\nprogram tryopen\narguments incons-archive-comment-longer.zip incons-archive-comment-shorter.zip\nreturn 0\nfile incons-archive-comment-longer.zip incons-archive-comment-longer.zip\nfile incons-archive-comment-shorter.zip incons-archive-comment-shorter.zip\nstdout\nopening 'incons-archive-comment-longer.zip' succeeded, 1 entries\nopening 'incons-archive-comment-shorter.zip' succeeded, 1 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_cons_extrabytes.test",
    "content": "# zip_open: file has extra bytes at end of archive\nprogram tryopen\nfile testextrabytes.zzip testextrabytes.zip\narguments -c testextrabytes.zzip\nreturn 1\nstdout\nopening 'testextrabytes.zzip' returned error 21/2\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_empty.test",
    "content": "# zip_open: file contains no entry, but is valid\nprogram tryopen\nfile testempty.zip testempty.zip\narguments testempty.zip\nreturn 0\nstdout\nopening 'testempty.zip' succeeded, 0 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_empty_2.test",
    "content": "# zip_open: 0 size file is recognized as empty zip\nprogram tryopen\nfile testfile.txt testfile.txt\narguments testfile.txt\nreturn 1\nstdout\nopening 'testfile.txt' returned error 19\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_extrabytes.test",
    "content": "# zip_open: file has extra bytes at end of archive\nprogram tryopen\nfile testextrabytes.zzip testextrabytes.zip\narguments testextrabytes.zzip\nreturn 0\nstdout\nopening 'testextrabytes.zzip' succeeded, 1 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_file_count.test",
    "content": "# zip_open: various inconsistent files\nprogram tryopen\nfile incons-file-count-high.zzip incons-file-count-high.zip\nfile incons-file-count-low.zzip incons-file-count-low.zip\nfile incons-file-count-overflow.zzip incons-file-count-overflow.zip\narguments incons-file-count-high.zzip incons-file-count-low.zzip incons-file-count-overflow.zzip\nreturn 1\nstdout\nopening 'incons-file-count-high.zzip' returned error 21/5\nopening 'incons-file-count-low.zzip' returned error 21/5\nopening 'incons-file-count-overflow.zzip' returned error 21/11\nend-of-inline-data\nstderr\n3 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_filename_duplicate.test",
    "content": "# zip_open: file opens fine even though same file name appears twice\nprogram tryopen\narguments filename_duplicate.zzip\nreturn 0\nfile filename_duplicate.zzip filename_duplicate.zip\nstdout\nopening 'filename_duplicate.zzip' succeeded, 2 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_filename_duplicate_consistency.test",
    "content": "# zip_open: file opens fine even though same file name appears twice\nprogram tryopen\narguments -c filename_duplicate.zzip\nreturn 1\nfile filename_duplicate.zzip filename_duplicate.zip\nstdout\nopening 'filename_duplicate.zzip' returned error 10\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_filename_duplicate_empty.test",
    "content": "# zip_open: file opens fine even though same file name (empty file name) appears twice\nprogram tryopen\narguments filename_duplicate_empty.zzip\nreturn 0\nfile filename_duplicate_empty.zzip filename_duplicate_empty.zip\nstdout\nopening 'filename_duplicate_empty.zzip' succeeded, 2 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_filename_duplicate_empty_consistency.test",
    "content": "# zip_open: file opens fine even though same file name (empty file name) appears twice\nprogram tryopen\narguments -c filename_duplicate_empty.zzip\nreturn 1\nfile filename_duplicate_empty.zzip filename_duplicate_empty.zip\nstdout\nopening 'filename_duplicate_empty.zzip' returned error 10\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_filename_empty.test",
    "content": "# zip_open: file opens fine even though file name has length 0\nprogram tryopen\narguments filename_empty.zip\nreturn 0\nfile filename_empty.zip filename_empty.zip\nstdout\nopening 'filename_empty.zip' succeeded, 1 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_incons.test",
    "content": "# zip_open: various inconsistent files\nprogram tryopen\nfile incons-archive-comment-longer.zzip incons-archive-comment-longer.zip\nfile incons-archive-comment-shorter.zzip incons-archive-comment-shorter.zip\nfile incons-cdoffset.zzip incons-cdoffset.zip\nfile incons-cdsize-large.zzip incons-cdsize-large.zip\nfile incons-cdsize-small.zzip incons-cdsize-large.zip\nfile incons-central-compression-method.zzip incons-central-compression-method.zip\nfile incons-central-compsize-larger.zzip incons-central-compsize-larger.zip\nfile incons-central-compsize-larger-toolarge.zzip incons-central-compsize-larger-toolarge.zip\nfile incons-central-compsize-smaller.zzip incons-central-compsize-smaller.zip\nfile incons-central-crc.zzip incons-central-crc.zip\nfile incons-central-date.zzip incons-central-date.zip\nfile incons-central-file-comment-longer.zzip incons-central-file-comment-longer.zip\nfile incons-central-file-comment-shorter.zzip incons-central-file-comment-shorter.zip\nfile incons-central-file-comment-utf8-ascii.zzip incons-central-file-comment-utf8-ascii.zip\nfile incons-central-magic-bad.zzip incons-central-magic-bad.zip\nfile incons-central-magic-bad2.zzip incons-central-magic-bad2.zip\nfile incons-central-size-larger.zzip incons-central-size-larger.zip\nfile incons-data.zzip incons-data.zip\nfile incons-ef-central-size-wrong.zzip incons-ef-central-size-wrong.zip\nfile incons-ef-local-dupe-utf8comment.zzip incons-ef-local-dupe-utf8comment.zip\nfile incons-ef-local-dupe-utf8name.zzip incons-ef-local-dupe-utf8name.zip\nfile incons-ef-local-dupe-zip64-v1.zzip incons-ef-local-dupe-zip64-v1.zip\nfile incons-ef-local-dupe-zip64-v2.zzip incons-ef-local-dupe-zip64-v2.zip\nfile incons-ef-local-id-size.zzip incons-ef-local-id-size.zip\nfile incons-ef-local-id.zzip incons-ef-local-id.zip\nfile incons-ef-local-size.zzip incons-ef-local-size.zip\nfile incons-ef-local-utf8name-ascii.zzip incons-ef-local-utf8name-ascii.zip\nfile incons-eocd64.zzip incons-eocd64.zip\nfile incons-eocd-magic-bad.zzip incons-eocd-magic-bad.zip\nfile incons-file-count-high.zzip incons-file-count-high.zip\nfile incons-file-count-low.zzip incons-file-count-low.zip\nfile incons-file-count-overflow.zzip incons-file-count-overflow.zip\nfile incons-gap-before-cd.zzip incons-gap-before-cd.zip\nfile incons-gap-before-eocd.zzip incons-gap-before-eocd.zip\nfile incons-gap-before-local.zzip incons-gap-before-local.zip\nfile incons-local-compression-method.zzip incons-local-compression-method.zip\nfile incons-local-compsize-larger.zzip incons-local-compsize-larger.zip\nfile incons-local-compsize-smaller.zzip incons-local-compsize-smaller.zip\nfile incons-local-crc.zzip incons-local-crc.zip\nfile incons-local-filename-long.zzip incons-local-filename-long.zip\nfile incons-local-filename-missing.zzip incons-local-filename-missing.zip\nfile incons-local-filename-nil-byte.zzip incons-local-filename-nil-byte.zip\nfile incons-local-filename-short.zzip incons-local-filename-short.zip\nfile incons-local-filename.zzip incons-local-filename.zip\nfile incons-local-magic-bad.zzip incons-local-magic-bad.zip\nfile incons-local-size-larger.zzip incons-local-size-larger.zip\nfile incons-stored-size.zzip incons-stored-size.zip\nfile incons-streamed.zzip incons-streamed.zip\nfile incons-streamed-2.zzip incons-streamed-2.zip\narguments -s -c incons-archive-comment-longer.zzip incons-archive-comment-shorter.zzip incons-cdoffset.zzip incons-cdsize-large.zzip incons-cdsize-small.zzip incons-central-compression-method.zzip incons-central-compsize-larger-toolarge.zzip incons-central-compsize-larger.zzip incons-central-compsize-smaller.zzip incons-central-crc.zzip incons-central-date.zzip incons-central-file-comment-longer.zzip incons-central-file-comment-shorter.zzip incons-central-file-comment-utf8-ascii.zzip incons-central-magic-bad.zzip incons-central-magic-bad2.zzip incons-central-size-larger.zzip incons-data.zzip incons-ef-central-size-wrong.zzip incons-ef-local-dupe-utf8comment.zzip incons-ef-local-dupe-utf8name.zzip incons-ef-local-dupe-zip64-v1.zzip incons-ef-local-dupe-zip64-v2.zzip incons-ef-local-id-size.zzip incons-ef-local-id.zzip incons-ef-local-size.zzip incons-ef-local-utf8name-ascii.zzip incons-eocd64.zzip incons-eocd-magic-bad.zzip incons-file-count-high.zzip incons-file-count-low.zzip incons-file-count-overflow.zzip incons-gap-before-cd.zzip incons-gap-before-eocd.zzip incons-gap-before-local.zzip incons-local-compression-method.zzip incons-local-compsize-larger.zzip incons-local-compsize-smaller.zzip incons-local-crc.zzip incons-local-filename-long.zzip incons-local-filename-missing.zzip incons-local-filename-nil-byte.zzip incons-local-filename-short.zzip incons-local-filename.zzip incons-local-magic-bad.zzip incons-local-size-larger.zzip incons-stored-size.zzip incons-streamed.zzip incons-streamed-2.zzip\nreturn 1\n# tryopen does not test checksums, so this is fine.\n# different extra fields local vs. central is fine\nstdout\nopening 'incons-archive-comment-longer.zzip' returned error Zip archive inconsistent: archive comment length incorrect\nopening 'incons-archive-comment-shorter.zzip' returned error Zip archive inconsistent: archive comment length incorrect\nopening 'incons-cdoffset.zzip' returned error Possibly truncated or corrupted zip archive\nopening 'incons-cdsize-large.zzip' returned error Zip archive inconsistent: central directory overlaps EOCD, or there is space between them\nopening 'incons-cdsize-small.zzip' returned error Zip archive inconsistent: central directory overlaps EOCD, or there is space between them\nopening 'incons-central-compression-method.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-central-compsize-larger-toolarge.zzip' returned error Possibly truncated or corrupted zip archive\nopening 'incons-central-compsize-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-central-compsize-smaller.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-central-crc.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-central-date.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-central-file-comment-longer.zzip' returned error Zip archive inconsistent: entry 0: variable size fields overflow header\nopening 'incons-central-file-comment-shorter.zzip' returned error Zip archive inconsistent: entry 1: central header invalid\nopening 'incons-central-file-comment-utf8-ascii.zzip' succeeded, 1 entries\nopening 'incons-central-magic-bad.zzip' returned error Possibly truncated or corrupted zip archive\nopening 'incons-central-magic-bad2.zzip' returned error Possibly truncated or corrupted zip archive\nopening 'incons-central-size-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-data.zzip' succeeded, 1 entries\nopening 'incons-ef-central-size-wrong.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid\nopening 'incons-ef-local-dupe-utf8comment.zzip' succeeded, 1 entries\nopening 'incons-ef-local-dupe-utf8name.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-ef-local-dupe-zip64-v1.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-ef-local-dupe-zip64-v2.zzip' succeeded, 1 entries\nopening 'incons-ef-local-id-size.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid\nopening 'incons-ef-local-id.zzip' succeeded, 1 entries\nopening 'incons-ef-local-size.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid\nopening 'incons-ef-local-utf8name-ascii.zzip' returned error Zip archive inconsistent: entry 0: UTF-8 filename is ASCII and doesn't match filename\nopening 'incons-eocd64.zzip' returned error Zip archive inconsistent: EOCD64 and EOCD do not match\nopening 'incons-eocd-magic-bad.zzip' returned error Possibly truncated or corrupted zip archive\nopening 'incons-file-count-high.zzip' returned error Zip archive inconsistent: central directory count of entries is incorrect\nopening 'incons-file-count-low.zzip' returned error Zip archive inconsistent: central directory count of entries is incorrect\nopening 'incons-file-count-overflow.zzip' returned error Zip archive inconsistent: invalid value in central directory\nopening 'incons-gap-before-cd.zzip' succeeded, 1 entries\nopening 'incons-gap-before-eocd.zzip' succeeded, 1 entries\nopening 'incons-gap-before-local.zzip' succeeded, 2 entries\nopening 'incons-local-compression-method.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-compsize-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-compsize-smaller.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-crc.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-filename-long.zzip' returned error Premature end of file\nopening 'incons-local-filename-missing.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-filename-nil-byte.zzip' succeeded, 1 entries\nopening 'incons-local-filename-short.zzip' returned error Zip archive inconsistent: entry 0: extra field length is invalid\nopening 'incons-local-filename.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-local-magic-bad.zzip' returned error Not a zip archive\nopening 'incons-local-size-larger.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-stored-size.zzip' returned error Zip archive inconsistent: entry 0: compressed and uncompressed sizes don't match for stored file\nopening 'incons-streamed.zzip' returned error Zip archive inconsistent: entry 0: local and central headers do not match\nopening 'incons-streamed-2.zzip' returned error Zip archive inconsistent: entry 0: local header and data descriptor do not match\nend-of-inline-data\nstderr\n40 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_many_fail.test",
    "content": "# zip_open: files with >65k that have issues\nprogram tryopen\narguments manyfiles-zip64-modulo.zzip manyfiles-fewer.zzip manyfiles-more.zzip\nreturn 1\nfile manyfiles-zip64-modulo.zzip manyfiles-zip64-modulo.zip\nfile manyfiles-fewer.zzip manyfiles-fewer.zip\nfile manyfiles-more.zzip manyfiles-more.zip\nstdout\nopening 'manyfiles-zip64-modulo.zzip' returned error 21/5\nopening 'manyfiles-fewer.zzip' returned error 21/5\nopening 'manyfiles-more.zzip' returned error 21/5\nend-of-inline-data\nstderr\n3 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_many_ok.test",
    "content": "# zip_open: files open fine, have > 65k entries\nprogram tryopen\narguments manyfiles.zip manyfiles-zip64.zip manyfiles-133000.zip manyfiles-65536.zip\nreturn 0\nfile manyfiles.zip manyfiles.zip\nfile manyfiles-zip64.zip manyfiles-zip64.zip\nfile manyfiles-133000.zip manyfiles-133000.zip\nfile manyfiles-65536.zip manyfiles-65536.zip\nstdout\nopening 'manyfiles.zip' succeeded, 70000 entries\nopening 'manyfiles-zip64.zip' succeeded, 70000 entries\nopening 'manyfiles-133000.zip' succeeded, 133000 entries\nopening 'manyfiles-65536.zip' succeeded, 65536 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_multidisk.test",
    "content": "# zip_open: file is part of a multi-disk zip archive\nprogram tryopen\narguments test.piz\nreturn 1\nfile test.piz multidisk.zip\nstdout\nopening 'test.piz' returned error 1\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_new_but_exists.test",
    "content": "# zip_open: file shall be created but already exists\nprogram tryopen\narguments -e test.zip\nreturn 1\nfile test.zip test.zip\nstdout\nopening 'test.zip' returned error 10\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_new_ok.test",
    "content": "# zip_open: create new archive\nprogram tryopen\narguments -n new.zip\nreturn 0\nstdout\nopening 'new.zip' succeeded, 0 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_nonarchive.test",
    "content": "# zip_open: file is not a zip archive\nprogram tryopen\nfile CMakeLists.txt CMakeLists.txt\narguments CMakeLists.txt\nreturn 1\nstdout\nopening 'CMakeLists.txt' returned error 19\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_nosuchfile.test",
    "content": "# zip_open: file doesn't exist\nprogram tryopen\narguments nosuchfile\nreturn 1\nstdout\nopening 'nosuchfile' returned error 9\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_ok.test",
    "content": "# zip_open: file opens fine\nprogram tryopen\narguments test.zip\nreturn 0\nfile test.zip test.zip\nstdout\nopening 'test.zip' succeeded, 3 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_too_short.test",
    "content": "# zip_open: file is too short for even a central directory entry\nprogram tryopen\narguments test.piz\nreturn 1\nfile test.piz bogus.zip\nstdout\nopening 'test.piz' returned error 19\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_truncate.test",
    "content": "# zip_open: file opens fine and gets truncated\nprogram tryopen\narguments -t test.zip\nreturn 0\nfile test.zip test.zip {}\nstdout\nopening 'test.zip' succeeded, 0 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_truncated.test",
    "content": "# zip_open: try opening an incomplete zip archive\nprogram tryopen\narguments test.zzip\nreturn 1\nfile test.zzip testfile-truncated.zip\nstdout\nopening 'test.zzip' returned error 35\nend-of-inline-data\nstderr\n1 errors\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_zip64_3mf.test",
    "content": "# zip_open: ZIP64 file opens fine even when most eocd entries are 0xff (3MF format)\nprogram tryopen\narguments test.zip\nreturn 0\nfile test.zip zip64-3mf.zip\nstdout\nopening 'test.zip' succeeded, 1 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/open_zip64_ok.test",
    "content": "# zip_open: ZIP64 file opens fine\nprogram tryopen\narguments test.zip\nreturn 0\nfile test.zip zip64.zip\nstdout\nopening 'test.zip' succeeded, 1 entries\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/preload.test",
    "content": "description test if preload works\nprogram nonrandomopentest\nreturn 0\npreload nonrandomopen.so\n"
  },
  {
    "path": "external/libzip/regress/progress.test",
    "content": "# test default compression stores if smaller; print progress\nreturn 0\narguments -n -- test.zip  print_progress  add compressible aaaaaaaaaaaaaa  add uncompressible uncompressible  add_nul large-compressible 8200  add_file large-uncompressible large-uncompressible 0 -1\nfile test.zip {} cm-default.zip\nfile large-uncompressible large-uncompressible\nstdout\n0.0% done\n25.0% done\n50.0% done\n75.0% done\n100.0% done\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/read_incons.test",
    "content": "arguments -c test.zip cat 0\nreturn 1\nfile test.zip incons-trailing-garbage.zip\nstdout\ntest\nend-of-inline-data\nstderr\ncan't read file at index '0': Zip archive inconsistent: garbage at end of compressed data\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/read_seek_read.test",
    "content": "# read past EOF, seek to beginning, read again\nreturn 0\narguments test.zip fopen test  fread 0 10  fseek 0 0 set  fread 0 5\nfile test.zip test.zip\nstdout\nopened 'test' as file 0\ntest\ntest\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/rename_ascii.test",
    "content": "# rename file to ASCII name in zip archive\nreturn 0\narguments testfile rename 0 testfile.txt\nfile testfile testfile-UTF8.zip testfile.zip\n"
  },
  {
    "path": "external/libzip/regress/rename_cp437.test",
    "content": "# rename file to CP437 name in zip archive (fails)\nreturn 0\narguments -x testfile.zip rename 0 \"8182838485868788898A8B8C8D8E8F90\"\nfile testfile.zip testfile.zip testfile-cp437.zip\n"
  },
  {
    "path": "external/libzip/regress/rename_deleted.test",
    "content": "# rename deleted entry in zip archive (fails)\nreturn 1\narguments testfile.zip delete 1 delete 3 rename 1 othername\nfile testfile.zip testcomment.zip testcomment13.zip\nstderr\ncan't rename file at index '1' to 'othername': Entry has been deleted\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/rename_fail.test",
    "content": "# rename file inside zip archive, but file name already exists\nreturn 1\narguments rename.zip   rename 0 file4\nfile rename.zip testcomment.zip\nstderr\ncan't rename file at index '0' to 'file4': File already exists\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/rename_ok.test",
    "content": "# rename file inside zip archive\nreturn 0\narguments rename.zip  rename 1 notfile2\nfile rename.zip testcomment.zip rename_ok.zip\n"
  },
  {
    "path": "external/libzip/regress/rename_utf8.test",
    "content": "# rename file to UTF-8 name in zip archive\nreturn 0\narguments -i testfile dummy\nstdin\nrename 0 ÄÖÜßäöü\nend-of-inline-data\nfile testfile testfile.zip testfile-UTF8.zip\n"
  },
  {
    "path": "external/libzip/regress/rename_utf8_encmismatch.test",
    "content": "# rename file to UTF-8 name in zip archive with CP437 comment (sets InfoZIP UTF-8 Name Extension)\nreturn 0\narguments -i testfile dummy\nstdin\nrename 0 ÄÖÜßäöü\nend-of-inline-data\nfile testfile test-cp437-fc.zip test-cp437-fc-utf-8-filename.zip\n"
  },
  {
    "path": "external/libzip/regress/reopen.test",
    "content": "description check the reopen functionality\nreturn 0\narguments -- testbuffer.zip cat 0 replace_file_contents 0 \"Overwritten\\n\" cat 0 add newfile.txt \"A new file\\n\" cat 1\nfile testbuffer.zip testbuffer.zip testbuffer_reopen.zip\nstdout\nThis is a test, and it seems to have been successful.\nOverwritten\nA new file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/reopen_partial.test",
    "content": "description check the reopen functionality (partial reads)\nreturn 0\narguments -- testbuffer.zip cat 0 replace_file_contents 0 \"Overwritten\\n\" cat_partial 0 4 5 add newfile.txt \"A new file\\n\" cat_partial 1 2 3\nfile testbuffer.zip testbuffer.zip testbuffer_reopen.zip\nstdout\nThis is a test, and it seems to have been successful.\nwrittnew\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/reopen_partial_rest.test",
    "content": "description check the reopen functionality (partial reads with -1 length)\nreturn 0\narguments -- testbuffer.zip cat 0 replace_file_contents 0 \"Overwritten\\n\" cat_partial 0 4 -1 add newfile.txt \"A new file\\n\" cat_partial 1 2 -1\nfile testbuffer.zip testbuffer.zip testbuffer_reopen.zip\nstdout\nThis is a test, and it seems to have been successful.\nwritten\nnew file\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/replace_set_stored.test",
    "content": "# replace file, set compression method to ZIP_CM_STORE (like it was before)\nreturn 0\narguments -n test.zip  replace_file_contents 0 aaaaaaaa  set_file_compression 0 store 0\nfile test.zip aaaaaaaa-stored.zip\n"
  },
  {
    "path": "external/libzip/regress/set_comment_all.test",
    "content": "# change local and global comments in a zip archive\nreturn 0\narguments testcomment.zip  set_archive_comment \"This is the new,\\r\\nmultiline archive comment.\\r\\nAin't it nice?\"  set_file_comment 0 \"File comment no 0\"  set_file_comment 1 \"File comment no 1\"  set_file_comment 2 \"File comment no 2\"  set_file_comment 3 \"File comment no 3\"\nfile testcomment.zip testcomment.zip testchanged.zip\n"
  },
  {
    "path": "external/libzip/regress/set_comment_localonly.test",
    "content": "# change file comments in a zip archive\nreturn 0\narguments testcomment.zip  set_file_comment 0 \"File comment no 0\"  set_file_comment 1 \"File comment no 1\"  set_file_comment 3 \"File comment no 3\"  set_file_comment 2 \"\"  \nfile testcomment.zip testcomment.zip testchangedlocal.zip\n"
  },
  {
    "path": "external/libzip/regress/set_comment_removeglobal.test",
    "content": "# remove archive comment\nreturn 0\narguments testcomment.zip  set_archive_comment \"\"\nfile testcomment.zip testcomment.zip testcommentremoved.zip\n"
  },
  {
    "path": "external/libzip/regress/set_comment_revert.test",
    "content": "# start changing local and global comments, but revert before closing\nreturn 0\narguments testcomment.zip  set_archive_comment \"some long string, a bit longer than this at least\"  set_file_comment 0 \"File comment no 0\"  set_file_comment 1 \"File comment no 1\"  set_file_comment 3 \"File comment no 3\"  set_file_comment 2 \"\"   unchange_all\nfile testcomment.zip testcomment.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_bzip2_to_deflate.test",
    "content": "# change method from bzip2 to deflated\nfeatures HAVE_LIBBZ2\nreturn 0\narguments test.zip  set_file_compression 0 deflate 0\nfile test.zip testbzip2.zip testdeflated.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_deflate_to_bzip2.test",
    "content": "# change method from deflated to bzip2\nfeatures HAVE_LIBBZ2\nreturn 0\narguments test.zip  set_file_compression 0 bzip2 0\nfile test.zip testdeflated.zip testbzip2.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_deflate_to_deflate.test",
    "content": "# change method from deflated to deflated (no change)\nreturn 0\narguments test.zip  set_file_compression 0 deflate 0\nfile test.zip testdeflated.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_deflate_to_store.test",
    "content": "# change method from deflated to stored\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip testdeflated.zip teststored.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_lzma_no_eos_to_store.test",
    "content": "# change method from lzma-compressed (id 14) without EOS/EOPM marker to stored\nfeatures HAVE_LIBLZMA\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip lzma-no-eos.zip stored-no-eos.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_lzma_to_store.test",
    "content": "# change method from lzma-compressed (id 14) to stored\nfeatures HAVE_LIBLZMA\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip testfile-lzma.zip testfile-stored-dos.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_bzip2.test",
    "content": "# change method from stored to bzip2\nfeatures HAVE_LIBBZ2\nreturn 0\narguments test.zip  set_file_compression 0 bzip2 0\nfile test.zip teststored.zip testbzip2.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_deflate.test",
    "content": "# change method from stored to deflated\nreturn 0\narguments test.zip  set_file_compression 0 deflate 0\nfile test.zip teststored.zip testdeflated.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_lzma.test",
    "content": "# change method from stored to lzma-compressed (Id 14)\nfeatures HAVE_LIBLZMA\nreturn 0\narguments test.zip  set_file_compression 0 lzma 0\nfile test.zip testfile-stored-dos.zip testfile-lzma.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_store.test",
    "content": "# change method from stored to stored (no change)\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip teststored.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_xz.test",
    "content": "# change method from stored to xz-compressed\nfeatures HAVE_LIBLZMA\nreturn 0\narguments test.zip  set_file_compression 0 xz 0\nfile test.zip testfile-stored-dos.zip testfile-xz.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_store_to_zstd.test",
    "content": "# change method from stored to zstd-compressed\nfeatures HAVE_LIBZSTD\nreturn 0\narguments test.zip  set_file_compression 0 zstd 0\nfile test.zip testfile-stored-dos.zip testfile-zstd.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_unknown.test",
    "content": "# change method to unknown\nreturn 1\narguments test.zip  set_file_compression 0 unknown 0\nfile test.zip teststored.zip\nstderr\ncan't set file compression method at index '0' to 'unknown', flags '0': Compression method not supported\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/set_compression_xz_to_store.test",
    "content": "# change method from xz-compressed to stored\nfeatures HAVE_LIBLZMA\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip testfile-xz.zip testfile-stored-dos.zip\n"
  },
  {
    "path": "external/libzip/regress/set_compression_zstd_to_store.test",
    "content": "# change method from zstd-compressed to stored\nfeatures HAVE_LIBZSTD\nreturn 0\narguments test.zip  set_file_compression 0 store 0\nfile test.zip testfile-zstd.zip testfile-stored-dos.zip\n"
  },
  {
    "path": "external/libzip/regress/set_file_dostime.test",
    "content": "# change dostime in a zip archive (use torrentzip default time)\nreturn 0\narguments testfile set_file_dostime 0 48128 8600\nfile testfile testfile.zip testfile0.zip\n"
  },
  {
    "path": "external/libzip/regress/set_file_mtime.test",
    "content": "# change mtime in a zip archive\nreturn 0\narguments testfile set_file_mtime 0 1407272201\nfile testfile testfile.zip testfile2014.zip\n"
  },
  {
    "path": "external/libzip/regress/set_file_mtime_pkware.test",
    "content": "# change mtime in a zip archive, fails because file is PKWare-encrypted\nreturn 1\narguments testfile set_file_mtime 0 1407272201\nfile testfile encrypt.zip\nstderr\ncan't set file mtime at index '0' to '1407272201': Operation not supported\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/short",
    "content": "short"
  },
  {
    "path": "external/libzip/regress/source_hole.c",
    "content": "/*\n source_hole.c -- source for handling huge files that are mostly NULs\n Copyright (C) 2014-2022 Dieter Baron and Thomas Klausner\n\n This file is part of libzip, a library to manipulate ZIP archives.\n The authors can be contacted at <info@libzip.org>\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n 3. The names of the authors may not be used to endorse or promote\n products derived from this software without specific prior\n written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"zip.h\"\n\n/* public API */\n\nzip_source_t *source_hole_create(const char *, int flags, zip_error_t *);\n\n\n#ifndef EFTYPE\n#define EFTYPE EINVAL\n#endif\n\n\n#define MY_MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define FRAGMENT_SIZE (8 * 1024)\n\n#define MARK_BEGIN \"NiH0\"\n#define MARK_DATA \"NiH1\"\n#define MARK_NUL \"NiH2\"\n\n\ntypedef struct buffer {\n    zip_uint64_t fragment_size;\n    zip_uint8_t **fragment;\n    zip_uint64_t nfragments;\n    zip_uint64_t size;\n    zip_uint64_t offset;\n} buffer_t;\n\nstatic void buffer_free(buffer_t *buffer);\nstatic buffer_t *buffer_from_file(const char *fname, int flags, zip_error_t *error);\nstatic buffer_t *buffer_new(void);\nstatic zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);\nstatic int buffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error);\nstatic zip_int64_t buffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error);\nstatic int buffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error);\nstatic zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);\nstatic zip_uint64_t get_u64(const zip_uint8_t *b);\nstatic int only_nul(const zip_uint8_t *data, zip_uint64_t length);\nstatic int write_nuls(zip_uint64_t n, FILE *f);\nstatic int write_u64(zip_uint64_t u64, FILE *f);\n\n\ntypedef struct hole {\n    zip_error_t error;\n    char *fname;\n    buffer_t *in;\n    buffer_t *out;\n} hole_t;\n\nstatic hole_t *hole_new(const char *fname, int flags, zip_error_t *error);\nstatic zip_int64_t source_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command);\n\n\nzip_source_t *\nsource_hole_create(const char *fname, int flags, zip_error_t *error) {\n    hole_t *ud = hole_new(fname, flags, error);\n\n    if (ud == NULL) {\n        return NULL;\n    }\n    return zip_source_function_create(source_hole_cb, ud, error);\n}\n\n\nstatic void\nbuffer_free(buffer_t *buffer) {\n    zip_uint64_t i;\n\n    if (buffer == NULL) {\n        return;\n    }\n\n    if (buffer->fragment) {\n        for (i = 0; i < buffer->nfragments; i++) {\n            free(buffer->fragment[i]);\n        }\n        free(buffer->fragment);\n    }\n    free(buffer);\n}\n\n\nstatic buffer_t *\nbuffer_from_file(const char *fname, int flags, zip_error_t *error) {\n    buffer_t *buffer;\n    FILE *f;\n\n    if ((buffer = buffer_new()) == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((flags & ZIP_TRUNCATE) == 0) {\n        if ((f = fopen(fname, \"rb\")) == NULL) {\n            if (!(errno == ENOENT && (flags & ZIP_CREATE))) {\n                buffer_free(buffer);\n                return NULL;\n            }\n        }\n        else {\n            if (buffer_read_file(buffer, f, error) < 0) {\n                buffer_free(buffer);\n                fclose(f);\n                return NULL;\n            }\n            fclose(f);\n        }\n    }\n\n    return buffer;\n}\n\n\nstatic buffer_t *\nbuffer_new(void) {\n    buffer_t *buffer;\n\n    if ((buffer = (buffer_t *)malloc(sizeof(*buffer))) == NULL) {\n        return NULL;\n    }\n\n    buffer->fragment = NULL;\n    buffer->nfragments = 0;\n    buffer->fragment_size = FRAGMENT_SIZE;\n    buffer->size = 0;\n    buffer->offset = 0;\n\n    return buffer;\n}\n\n\nstatic zip_int64_t\nbuffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) {\n    zip_uint64_t n, i, fragment_offset;\n\n    length = MY_MIN(length, buffer->size - buffer->offset);\n\n    if (length == 0) {\n        return 0;\n    }\n    if (length > ZIP_INT64_MAX) {\n        return -1;\n    }\n\n    i = buffer->offset / buffer->fragment_size;\n    fragment_offset = buffer->offset % buffer->fragment_size;\n    n = 0;\n    while (n < length) {\n        zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset);\n\n        if (buffer->fragment[i]) {\n            memcpy(data + n, buffer->fragment[i] + fragment_offset, left);\n        }\n        else {\n            memset(data + n, 0, left);\n        }\n\n        n += left;\n        i++;\n        fragment_offset = 0;\n    }\n\n    buffer->offset += n;\n    return (zip_int64_t)n;\n}\n\n\nstatic int\nbuffer_read_file(buffer_t *buffer, FILE *f, zip_error_t *error) {\n    zip_uint8_t b[20];\n    zip_uint64_t i;\n\n    if (fread(b, 20, 1, f) != 1) {\n        zip_error_set(error, ZIP_ER_READ, errno);\n        return -1;\n    }\n\n    if (memcmp(b, MARK_BEGIN, 4) != 0) {\n        zip_error_set(error, ZIP_ER_READ, EFTYPE);\n        return -1;\n    }\n\n    buffer->fragment_size = get_u64(b + 4);\n    buffer->size = get_u64(b + 12);\n    \n    if (buffer->fragment_size == 0) {\n        zip_error_set(error, ZIP_ER_INCONS, 0);\n        return -1;\n    }\n\n    buffer->nfragments = buffer->size / buffer->fragment_size;\n    if (buffer->size % buffer->fragment_size != 0) {\n        buffer->nfragments += 1;\n    }\n    \n    if ((buffer->nfragments > SIZE_MAX / sizeof(buffer->fragment[0])) || ((buffer->fragment = (zip_uint8_t **)malloc(sizeof(buffer->fragment[0]) * buffer->nfragments)) == NULL)) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return -1;\n    }\n\n    for (i = 0; i < buffer->nfragments; i++) {\n        buffer->fragment[i] = NULL;\n    }\n\n    i = 0;\n    while (i < buffer->nfragments) {\n        if (fread(b, 4, 1, f) != 1) {\n            zip_error_set(error, ZIP_ER_READ, errno);\n            return -1;\n        }\n\n        if (memcmp(b, MARK_DATA, 4) == 0) {\n            if (buffer->fragment_size > SIZE_MAX) {\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n            if ((buffer->fragment[i] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) {\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return -1;\n            }\n            if (fread(buffer->fragment[i], buffer->fragment_size, 1, f) != 1) {\n                zip_error_set(error, ZIP_ER_READ, errno);\n                return -1;\n            }\n            i++;\n        }\n        else if (memcmp(b, MARK_NUL, 4) == 0) {\n            if (fread(b, 8, 1, f) != 1) {\n                zip_error_set(error, ZIP_ER_READ, errno);\n                return -1;\n            }\n            i += get_u64(b);\n        }\n        else {\n            zip_error_set(error, ZIP_ER_READ, EFTYPE);\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\nstatic zip_int64_t\nbuffer_seek(buffer_t *buffer, void *data, zip_uint64_t length, zip_error_t *error) {\n    zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, length, error);\n\n    if (new_offset < 0) {\n        return -1;\n    }\n\n    buffer->offset = (zip_uint64_t)new_offset;\n    return 0;\n}\n\n\nstatic int\nbuffer_to_file(buffer_t *buffer, const char *fname, zip_error_t *error) {\n    FILE *f = fopen(fname, \"wb\");\n    zip_uint64_t i;\n    zip_uint64_t nul_run;\n\n    if (f == NULL) {\n        zip_error_set(error, ZIP_ER_OPEN, errno);\n        return -1;\n    }\n\n    fwrite(MARK_BEGIN, 4, 1, f);\n    write_u64(buffer->fragment_size, f);\n    write_u64(buffer->size, f);\n\n    nul_run = 0;\n    for (i = 0; i * buffer->fragment_size < buffer->size; i++) {\n        if (buffer->fragment[i] == NULL || only_nul(buffer->fragment[i], buffer->fragment_size)) {\n            nul_run++;\n        }\n        else {\n            if (nul_run > 0) {\n                write_nuls(nul_run, f);\n                nul_run = 0;\n            }\n            fwrite(MARK_DATA, 4, 1, f);\n\n            fwrite(buffer->fragment[i], 1, buffer->fragment_size, f);\n        }\n    }\n\n    if (nul_run > 0) {\n        write_nuls(nul_run, f);\n    }\n\n    if (fclose(f) != 0) {\n        zip_error_set(error, ZIP_ER_WRITE, errno);\n        return -1;\n    }\n\n    return 0;\n}\n\n\nstatic zip_int64_t\nbuffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) {\n    zip_uint8_t **fragment;\n    if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) {\n        zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size;\n        zip_uint64_t new_capacity = buffer->nfragments;\n        zip_uint64_t i;\n\n        if (new_capacity == 0) {\n            new_capacity = 4;\n        }\n        while (new_capacity < needed_fragments) {\n            new_capacity *= 2;\n        }\n\n        fragment = realloc(buffer->fragment, new_capacity * sizeof(*fragment));\n\n        if (fragment == NULL) {\n            zip_error_set(error, ZIP_ER_MEMORY, 0);\n            return -1;\n        }\n\n        for (i = buffer->nfragments; i < new_capacity; i++) {\n            fragment[i] = NULL;\n        }\n\n        buffer->fragment = fragment;\n        buffer->nfragments = new_capacity;\n    }\n\n    if (!only_nul(data, length)) {\n        zip_uint64_t idx, n, fragment_offset;\n\n        idx = buffer->offset / buffer->fragment_size;\n        fragment_offset = buffer->offset % buffer->fragment_size;\n        n = 0;\n\n        while (n < length) {\n            zip_uint64_t left = MY_MIN(length - n, buffer->fragment_size - fragment_offset);\n\n            if (buffer->fragment[idx] == NULL) {\n                if ((buffer->fragment[idx] = (zip_uint8_t *)malloc(buffer->fragment_size)) == NULL) {\n                    zip_error_set(error, ZIP_ER_MEMORY, 0);\n                    return -1;\n                }\n                memset(buffer->fragment[idx], 0, buffer->fragment_size);\n            }\n            memcpy(buffer->fragment[idx] + fragment_offset, data + n, left);\n\n            n += left;\n            idx++;\n            fragment_offset = 0;\n        }\n    }\n\n    buffer->offset += length;\n    if (buffer->offset > buffer->size) {\n        buffer->size = buffer->offset;\n    }\n\n    return (zip_int64_t)length;\n}\n\n\nstatic zip_uint64_t\nget_u64(const zip_uint8_t *b) {\n    zip_uint64_t i;\n\n    i = (zip_uint64_t)b[0] << 56 | (zip_uint64_t)b[1] << 48 | (zip_uint64_t)b[2] << 40 | (zip_uint64_t)b[3] << 32 | (zip_uint64_t)b[4] << 24 | (zip_uint64_t)b[5] << 16 | (zip_uint64_t)b[6] << 8 | (zip_uint64_t)b[7];\n\n    return i;\n}\n\n\nstatic int\nonly_nul(const zip_uint8_t *data, zip_uint64_t length) {\n    zip_uint64_t i;\n\n    for (i = 0; i < length; i++) {\n        if (data[i] != '\\0') {\n            return 0;\n        }\n    }\n\n    return 1;\n}\n\n\nstatic int\nwrite_nuls(zip_uint64_t n, FILE *f) {\n    if (fwrite(MARK_NUL, 4, 1, f) != 1) {\n        return -1;\n    }\n    return write_u64(n, f);\n}\n\n\nstatic int\nwrite_u64(zip_uint64_t u64, FILE *f) {\n    zip_uint8_t b[8];\n\n    b[0] = (zip_uint8_t)((u64 >> 56) & 0xff);\n    b[1] = (zip_uint8_t)((u64 >> 48) & 0xff);\n    b[2] = (zip_uint8_t)((u64 >> 40) & 0xff);\n    b[3] = (zip_uint8_t)((u64 >> 32) & 0xff);\n    b[4] = (zip_uint8_t)((u64 >> 24) & 0xff);\n    b[5] = (zip_uint8_t)((u64 >> 16) & 0xff);\n    b[6] = (zip_uint8_t)((u64 >> 8) & 0xff);\n    b[7] = (zip_uint8_t)(u64 & 0xff);\n\n    return fwrite(b, 8, 1, f) == 1 ? 0 : -1;\n}\n\n\nstatic void\nhole_free(hole_t *hole) {\n    if (hole == NULL) {\n        return;\n    }\n    zip_error_fini(&hole->error);\n    buffer_free(hole->in);\n    buffer_free(hole->out);\n    free(hole->fname);\n    free(hole);\n}\n\n\nstatic hole_t *\nhole_new(const char *fname, int flags, zip_error_t *error) {\n    hole_t *ctx = (hole_t *)malloc(sizeof(*ctx));\n\n    if (ctx == NULL) {\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->fname = strdup(fname)) == NULL) {\n        free(ctx);\n        zip_error_set(error, ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    if ((ctx->in = buffer_from_file(fname, flags, error)) == NULL) {\n        free(ctx);\n        return NULL;\n    }\n\n    zip_error_init(&ctx->error);\n    ctx->out = NULL;\n\n    return ctx;\n}\n\n\nstatic zip_int64_t\nsource_hole_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) {\n    hole_t *ctx = (hole_t *)ud;\n\n    switch (command) {\n    case ZIP_SOURCE_BEGIN_WRITE:\n        ctx->out = buffer_new();\n        return 0;\n\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_COMMIT_WRITE:\n        if (buffer_to_file(ctx->out, ctx->fname, &ctx->error) < 0) {\n            return -1;\n        }\n        buffer_free(ctx->in);\n        ctx->in = ctx->out;\n        ctx->out = NULL;\n        return 0;\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, length);\n\n    case ZIP_SOURCE_FREE:\n        hole_free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_OPEN:\n        ctx->in->offset = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        return buffer_read(ctx->in, data, length, &ctx->error);\n\n    case ZIP_SOURCE_REMOVE:\n        buffer_free(ctx->in);\n        ctx->in = buffer_new();\n        buffer_free(ctx->out);\n        ctx->out = NULL;\n        (void)remove(ctx->fname);\n        return 0;\n\n    case ZIP_SOURCE_ROLLBACK_WRITE:\n        buffer_free(ctx->out);\n        ctx->out = NULL;\n        return 0;\n\n    case ZIP_SOURCE_SEEK:\n        return buffer_seek(ctx->in, data, length, &ctx->error);\n\n    case ZIP_SOURCE_SEEK_WRITE:\n        return buffer_seek(ctx->out, data, length, &ctx->error);\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);\n\n        if (st == NULL) {\n            return -1;\n        }\n\n        /* TODO: return ENOENT if fname doesn't exist */\n\n        st->valid |= ZIP_STAT_SIZE;\n        st->size = ctx->in->size;\n        return 0;\n    }\n\n    case ZIP_SOURCE_TELL:\n        return (zip_int64_t)ctx->in->offset;\n\n    case ZIP_SOURCE_TELL_WRITE:\n        return (zip_int64_t)ctx->out->offset;\n\n    case ZIP_SOURCE_WRITE:\n        return buffer_write(ctx->out, data, length, &ctx->error);\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_STAT, ZIP_SOURCE_TELL, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);\n\n    default:\n        zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n}\n"
  },
  {
    "path": "external/libzip/regress/stat_index_cp437_guess.test",
    "content": "# guess CP437 file names and autoconvert them\narguments test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15\nreturn 0\nfile test-cp437.zip test-cp437.zip\nstdout\nname: '☺☻♥♦♣♠•◘○◙♂♀♪♫☼►'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '◄↕‼¶§▬↨↑↓→←∟↔▲▼ '\nindex: '1'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '!\"#$%&'()*+,-./0'\nindex: '2'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:58'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '123456789:;<=>?@'\nindex: '3'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:04'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'ABCDEFGHIJKLMNOP'\nindex: '4'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'QRSTUVWXYZ[\\]^_`'\nindex: '5'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:12'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'abcdefghijklmnop'\nindex: '6'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:18'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'qrstuvwxyz{|}~⌂Ç'\nindex: '7'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:22'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'üéâäàåçêëèïîìÄÅÉ'\nindex: '8'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:26'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'æÆôöòûùÿÖÜ¢£¥₧ƒá'\nindex: '9'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:30'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'íóúñÑªº¿⌐¬½¼¡«»░'\nindex: '10'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:36'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '▒▓│┤╡╢╖╕╣║╗╝╜╛┐└'\nindex: '11'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:40'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '┴┬├─┼╞╟╚╔╩╦╠═╬╧╨'\nindex: '12'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:44'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α'\nindex: '13'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'ßΓπΣσµτΦΘΩδ∞φε∩≡'\nindex: '14'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '±≥≤⌠⌡÷≈°∙·√ⁿ²■  '\nindex: '15'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:53:02'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_cp437_raw.test",
    "content": "# get raw file names them from archive\narguments -x -r test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15\nreturn 0\nfile test-cp437.zip test-cp437.zip\nstdout\nname: '0102030405060708090a0b0c0d0e0f10'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '1112131415161718191a1b1c1d1e1f20'\nindex: '1'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '2122232425262728292a2b2c2d2e2f30'\nindex: '2'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:58'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '3132333435363738393a3b3c3d3e3f40'\nindex: '3'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:04'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '4142434445464748494a4b4c4d4e4f50'\nindex: '4'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '5152535455565758595a5b5c5d5e5f60'\nindex: '5'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:12'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '6162636465666768696a6b6c6d6e6f70'\nindex: '6'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:18'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '7172737475767778797a7b7c7d7e7f80'\nindex: '7'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:22'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '8182838485868788898a8b8c8d8e8f90'\nindex: '8'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:26'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '9192939495969798999a9b9c9d9e9fa0'\nindex: '9'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:30'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'a1a2a3a4a5a6a7a8a9aaabacadaeafb0'\nindex: '10'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:36'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'b1b2b3b4b5b6b7b8b9babbbcbdbebfc0'\nindex: '11'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:40'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'c1c2c3c4c5c6c7c8c9cacbcccdcecfd0'\nindex: '12'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:44'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'd1d2d3d4d5d6d7d8d9dadbdcdddedfe0'\nindex: '13'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'e1e2e3e4e5e6e7e8e9eaebecedeeeff0'\nindex: '14'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'f1f2f3f4f5f6f7f8f9fafbfcfdfeffff'\nindex: '15'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:53:02'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_cp437_strict.test",
    "content": "# strictly follow ZIP spec and expect CP437 file names, and autoconvert them\narguments -s test-cp437.zip stat 0 stat 1 stat 2 stat 3 stat 4 stat 5 stat 6 stat 7 stat 8 stat 9 stat 10 stat 11 stat 12 stat 13 stat 14 stat 15\nreturn 0\nfile test-cp437.zip test-cp437.zip\nstdout\nname: '☺☻♥♦♣♠•◘○◙♂♀♪♫☼►'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '◄↕‼¶§▬↨↑↓→←∟↔▲▼ '\nindex: '1'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '!\"#$%&'()*+,-./0'\nindex: '2'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:51:58'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '123456789:;<=>?@'\nindex: '3'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:04'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'ABCDEFGHIJKLMNOP'\nindex: '4'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'QRSTUVWXYZ[\\]^_`'\nindex: '5'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:12'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'abcdefghijklmnop'\nindex: '6'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:18'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'qrstuvwxyz{|}~⌂Ç'\nindex: '7'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:22'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'üéâäàåçêëèïîìÄÅÉ'\nindex: '8'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:26'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'æÆôöòûùÿÖÜ¢£¥₧ƒá'\nindex: '9'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:30'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'íóúñÑªº¿⌐¬½¼¡«»░'\nindex: '10'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:36'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '▒▓│┤╡╢╖╕╣║╗╝╜╛┐└'\nindex: '11'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:40'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '┴┬├─┼╞╟╚╔╩╦╠═╬╧╨'\nindex: '12'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:44'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '╤╥╙╘╒╓╫╪┘┌█▄▌▐▀α'\nindex: '13'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:50'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'ßΓπΣσµτΦΘΩδ∞φε∩≡'\nindex: '14'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:52:54'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: '±≥≤⌠⌡÷≈°∙·√ⁿ²■  '\nindex: '15'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Feb 17 2012 20:53:02'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_fileorder.test",
    "content": "# zip_open: entries ordered by central directory order\narguments fileorder.zzip stat 0 stat 1\nreturn 0\nfile fileorder.zzip fileorder.zip\nstdout\nname: 'file1'\nindex: '0'\nsize: '5'\ncompressed size: '5'\nmtime: 'Fri Apr 27 2012 23:21:42'\ncrc: '9ee760e5'\ncompression method: '0'\nencryption method: '0'\n\nname: 'file2'\nindex: '1'\nsize: '5'\ncompressed size: '5'\nmtime: 'Fri Apr 27 2012 23:21:44'\ncrc: '7ee315f'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_streamed.test",
    "content": "# stat file in streamed zip file\narguments streamed stat 0\nfile streamed streamed.zip\nreturn 0\nstdout\nname: '-'\nindex: '0'\nsize: '2'\ncompressed size: '4'\nmtime: 'Wed Apr 25 2012 10:20:38'\ncrc: 'ddeaa107'\ncompression method: '8'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_streamed_zip64.test",
    "content": "# stat file in streamed zip file\narguments streamed stat 0\nfile streamed streamed-zip64.zip\nreturn 0\nstdout\nname: '-'\nindex: '0'\nsize: '2'\ncompressed size: '4'\nmtime: 'Wed Apr 25 2012 10:20:38'\ncrc: 'ddeaa107'\ncompression method: '8'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_utf8_guess.test",
    "content": "# guess UTF-8 file names\narguments test-utf8.zip stat 0\nreturn 0\nfile test-utf8.zip test-utf8.zip\nstdout\nname: 'ÄÖÜäöüßćçĉéèêëē'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Sat Feb 18 2012 00:15:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_utf8_raw.test",
    "content": "# print UTF-8 file names\narguments -r test-utf8.zip stat 0\nreturn 0\nfile test-utf8.zip test-utf8.zip\nstdout\nname: 'ÄÖÜäöüßćçĉéèêëē'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Sat Feb 18 2012 00:15:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_utf8_strict.test",
    "content": "# follow strict rules and convert UTF-8 as if it was CP437, but not\n# if the files are marked as having UTF-8 names\narguments -s test-utf8.zip stat 0\nreturn 0\nfile test-utf8.zip test-utf8.zip\nstdout\nname: 'ÄÖÜäöüßćçĉéèêëē'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Sat Feb 18 2012 00:15:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_utf8_unmarked_strict.test",
    "content": "# follow strict rules and convert UTF-8 as if it was CP437,\n# if not marked otherwise (in this case: not marked)\narguments -s test-utf8-unmarked.zip stat 0\nreturn 0\nfile test-utf8-unmarked.zip test-utf8-unmarked.zip\nstdout\nname: '├ä├û├£├ñ├╢├╝├ƒ─ç├º─ë├⌐├¿├¬├½─ô'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Sat Feb 18 2012 00:15:08'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/stat_index_zip64.test",
    "content": "# stat file in zip64 zip file\narguments bigzero stat 0\nfile bigzero bigzero.zip\nreturn 0\nstdout\nname: 'bigzero'\nindex: '0'\nsize: '4294967296'\ncompressed size: '4168157'\nmtime: 'Thu Mar 15 2012 14:54:06'\ncrc: 'd202ef8d'\ncompression method: '8'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/testfile.txt",
    "content": ""
  },
  {
    "path": "external/libzip/regress/truncate_empty_keep.test",
    "content": "# delete last entry in zip archive\nreturn 0\narguments -t testfile.zzip  set_archive_flag create-or-keep-file-for-empty-archive 1\nfile testfile.zzip testfile.zip testempty.zip\n"
  },
  {
    "path": "external/libzip/regress/tryopen.c",
    "content": "/*\n  tryopen.c -- tool for tests that try opening zip archives\n  Copyright (C) 1999-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <stdio.h>\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\n\n#include \"zip.h\"\n#define TRYOPEN_USAGE                  \\\n    \"usage: %s [-cent] file\\n\\n\"       \\\n    \"\\t-c\\tcheck consistency\\n\"        \\\n    \"\\t-e\\texclusively open archive\\n\" \\\n    \"\\t-n\\tcreate new file\\n\"          \\\n    \"\\t-s\\tprint error string\\n\"       \\\n    \"\\t-t\\ttruncate file to size 0\\n\"\n\n\nint\nmain(int argc, char *argv[]) {\n    const char *fname;\n    zip_t *z;\n    int c, flags, ze;\n    zip_int64_t count;\n    int error_count;\n    zip_error_t error;\n    int error_strings = 0;\n\n    flags = 0;\n\n    while ((c = getopt(argc, argv, \"censt\")) != -1) {\n        switch (c) {\n        case 'c':\n            flags |= ZIP_CHECKCONS;\n            break;\n        case 'e':\n            flags |= ZIP_EXCL;\n            break;\n        case 'n':\n            flags |= ZIP_CREATE;\n            break;\n        case 's':\n            error_strings = 1;\n            break;\n        case 't':\n            flags |= ZIP_TRUNCATE;\n            break;\n\n        default:\n            fprintf(stderr, TRYOPEN_USAGE, argv[0]);\n            return 1;\n        }\n    }\n\n    error_count = 0;\n    for (; optind < argc; optind++) {\n        fname = argv[optind];\n        errno = 0;\n\n        if ((z = zip_open(fname, flags, &ze)) != NULL) {\n            count = zip_get_num_entries(z, 0);\n            printf(\"opening '%s' succeeded, %\" PRIu64 \" entries\\n\", fname, count);\n            zip_close(z);\n            continue;\n        }\n\n        zip_error_init_with_code(&error, ze);\n        printf(\"opening '%s' returned error \", fname);\n        if (error_strings) {\n            printf(\"%s\", zip_error_strerror(&error));\n        }\n        else {\n            printf(\"%d\", ze);\n            switch (zip_error_system_type(&error)) {\n            case ZIP_ET_SYS:\n            case ZIP_ET_LIBZIP:\n                printf(\"/%d\", zip_error_code_system(&error));\n                break;\n\n            default:\n                break;\n            }\n        }\n        printf(\"\\n\");\n        error_count++;\n    }\n\n    if (error_count > 0)\n        fprintf(stderr, \"%d errors\\n\", error_count);\n\n    return error_count ? 1 : 0;\n}\n"
  },
  {
    "path": "external/libzip/regress/unchange-delete-namelocate.test",
    "content": "# namelocate after a file has been deleted and unchanged should succeed.\narguments test2.zip delete  0  unchange 0  name_locate testfile.txt 0\nreturn 0\nfile test2.zip test2.zip\nstdout\nname 'testfile.txt' using flags '0' found at index 0\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/utf-8-standardization.test",
    "content": "# replace file contents and make UTF-8 name\nreturn 0\narguments testfile.zzip replace_file_contents 0 \"Some new content for the file.\" set_file_mtime 0 1406885162\nfile testfile.zzip utf-8-standardization-input.zip utf-8-standardization-output.zip\n"
  },
  {
    "path": "external/libzip/regress/want_torrentzip_stat.test",
    "content": "# check that wanting to convert a file to torrentzip changes stat information\nreturn 0\narguments testfile.zzip stat 0 set_archive_flag want-torrentzip 1 stat 0 unchange_all stat 0\nfile testfile.zzip testfile.zip\nstdout\nname: 'testfile.txt'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Jul 15 2005 16:37:14'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nname: 'testfile.txt'\nindex: '0'\nsize: '0'\nmtime: 'Tue Dec 24 1996 23:32:00'\ncrc: '0'\ncompression method: '8'\nencryption method: '0'\n\nname: 'testfile.txt'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Jul 15 2005 16:37:14'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/zip-in-archive-comment.test",
    "content": "# stat file in zip that contains archive comment to find out if it detected the right one of the two\narguments zip-in-archive-comment.zip stat 0\nfile zip-in-archive-comment.zip zip-in-archive-comment.zip\nreturn 0\nstdout\nname: 'test'\nindex: '0'\nsize: '5'\ncompressed size: '5'\nmtime: 'Mon Oct 06 2003 15:46:42'\ncrc: '3bb935c6'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/zip64-in-archive-comment.test",
    "content": "# stat file in zip that contains archive comment to find out if it detected the right one of the two\narguments zip64-in-archive-comment.zip stat 0\nfile zip64-in-archive-comment.zip zip64-in-archive-comment.zip\nreturn 0\nstdout\nname: 'testfile.txt'\nindex: '0'\nsize: '0'\ncompressed size: '0'\nmtime: 'Fri Jul 15 2005 16:37:14'\ncrc: '0'\ncompression method: '0'\nencryption method: '0'\n\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/zip64_creation.test",
    "content": "# create big zip64 zip file from scratch\narguments bigzero.zip  add_nul bigzero 4294967296\nfile bigzero.zip {} bigzero.zip\nreturn 0\n"
  },
  {
    "path": "external/libzip/regress/zip64_stored_creation.test",
    "content": "# create big zip64 zip file from scratch\narguments -H bigstored.zh  add_nul bigzero 4294967296  set_file_compression 0 0 0  set_file_mtime 0 0  add_nul smallzero 16384  set_file_compression 1 0 0  set_file_mtime 1 0\nfile bigstored.zh {} bigstored.zh\nreturn 0\n"
  },
  {
    "path": "external/libzip/regress/zipcmp_zip_dir.test",
    "content": "# compare zip with directory\nfeatures HAVE_FTS_H\nprogram zipcmp\nmkdir a\nmkdir a/dir-with-file\nmkdir a/empty-dir-in-dir\narguments zipcmp_zip_dir.zip  a\nfile zipcmp_zip_dir.zip zipcmp_zip_dir.zip\nreturn 1\nstdout\n--- zipcmp_zip_dir.zip\n+++ a\n- directory '00-empty-dir/'\n- file 'dir-with-file/a', size 1, crc e8b7be43, mtime 1610623116\n+ directory 'empty-dir-in-dir/'\n- directory 'empty-dir/'\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/zipcmp_zip_dir_slash.test",
    "content": "# compare zip with directory with trailing slash\nfeatures HAVE_FTS_H\nprogram zipcmp\nmkdir a\nmkdir a/dir-with-file\nmkdir a/empty-dir-in-dir\narguments zipcmp_zip_dir.zip  a/\nfile zipcmp_zip_dir.zip zipcmp_zip_dir.zip\nreturn 1\nstdout\n--- zipcmp_zip_dir.zip\n+++ a/\n- directory '00-empty-dir/'\n- file 'dir-with-file/a', size 1, crc e8b7be43, mtime 1610623116\n+ directory 'empty-dir-in-dir/'\n- directory 'empty-dir/'\nend-of-inline-data\n"
  },
  {
    "path": "external/libzip/regress/ziptool_regress.c",
    "content": "#include \"zip.h\"\n\n#include <sys/stat.h>\n\n#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define FOR_REGRESS\n\ntypedef enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IN_MEMORY, SOURCE_TYPE_HOLE } source_type_t;\n\nsource_type_t source_type = SOURCE_TYPE_NONE;\nzip_uint64_t fragment_size = 0;\nzip_file_t *z_files[16];\nunsigned int z_files_count;\nint commands_from_stdin = 0;\n\nstatic int add_nul(char *argv[]);\nstatic int cancel(char *argv[]);\nstatic int extract_as(char *argv[]);\nstatic int regress_fopen(char *argv[]);\nstatic int regress_fread(char *argv[]);\nstatic int regress_fseek(char *argv[]);\nstatic int is_seekable(char *argv[]);\nstatic int unchange_one(char *argv[]);\nstatic int unchange_all(char *argv[]);\nstatic int zin_close(char *argv[]);\n\n#define OPTIONS_REGRESS \"F:Himx\"\n\n#define USAGE_REGRESS \" [-Himx] [-F fragment-size]\"\n\n#define GETOPT_REGRESS                              \\\n    case 'H':                                       \\\n        source_type = SOURCE_TYPE_HOLE;             \\\n        break;                                      \\\n    case 'i':                                       \\\n        commands_from_stdin = 1;                    \\\n        break;                                      \\\n    case 'm':                                       \\\n        source_type = SOURCE_TYPE_IN_MEMORY;        \\\n        break;                                      \\\n    case 'F':                                       \\\n        fragment_size = strtoull(optarg, NULL, 10); \\\n        break;                                      \\\n    case 'x':                                       \\\n        hex_encoded_filenames = 1;                  \\\n        break;\n\n/* clang-format off */\n\n#define DISPATCH_REGRESS \\\n    {\"add_nul\", 2, \"name length\", \"add NUL bytes\", add_nul}, \\\n    {\"cancel\", 1, \"limit\", \"cancel writing archive when limit% have been written (calls print_progress)\", cancel}, \\\n    {\"extract_as\", 2, \"index name\", \"extract file data to given file name\", extract_as}, \\\n    {\"fopen\", 1, \"name\", \"open archive entry\", regress_fopen}, \\\n    {\"fread\", 2, \"file_index length\", \"read from fopened file and print\", regress_fread}, \\\n    {\"fseek\", 3, \"file_index offset whence\", \"seek in fopened file\", regress_fseek}, \\\n    {\"is_seekable\", 1, \"index\", \"report if entry is seekable\", is_seekable}, \\\n    {\"unchange\", 1, \"index\", \"revert changes for entry\", unchange_one}, \\\n    {\"unchange_all\", 0, \"\", \"revert all changes\", unchange_all}, \\\n    {\"zin_close\", 1, \"index\", \"close input zip_source (for internal tests)\", zin_close}\n\n#define PRECLOSE_REGRESS                                         \\\n  do {                                                           \\\n      unsigned int file_idx = 0;                                 \\\n      for (file_idx = 0; file_idx < z_files_count; ++file_idx) { \\\n          if (zip_fclose (z_files[file_idx]) != 0) {             \\\n              err = 1;                                           \\\n          }                                                      \\\n      }                                                          \\\n  }                                                              \\\n  while (0)\n\n/* clang-format on */\n\n#define MAX_STDIN_ARGC  128\n#define MAX_STDIN_LENGTH    8192\n\nchar* stdin_argv[MAX_STDIN_ARGC];\nstatic char stdin_line[MAX_STDIN_LENGTH];\n\nint get_stdin_commands(void);\n\n#define REGRESS_PREPARE_ARGS                \\\n    if (commands_from_stdin) {              \\\n        argc = get_stdin_commands();        \\\n        arg = 0;                            \\\n        argv = stdin_argv;                  \\\n    }\n\nzip_t *ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len);\n\n\n#include \"ziptool.c\"\n\nint get_stdin_commands(void) {\n    int argc = 0;\n    char *p, *word;\n    fgets(stdin_line, sizeof(stdin_line), stdin);\n    word = p = stdin_line;\n    while (1) {\n        if (*p == ' ' || *p == '\\n') {\n            *p = '\\0';\n            if (word[0] != '\\0') {\n                stdin_argv[argc] = word;\n                argc += 1;\n                if (argc >= MAX_STDIN_ARGC) {\n                    break;\n                }\n            }\n            word = p + 1;\n        }\n        else if (*p == '\\0') {\n            if (word[0] != '\\0') {\n                stdin_argv[argc] = word;\n                argc += 1;\n            }\n            break;\n        }\n        p += 1;\n    }\n    return argc;\n}\n\nzip_source_t *memory_src = NULL;\n\nstatic int get_whence(const char *str);\nzip_source_t *source_hole_create(const char *, int flags, zip_error_t *);\nstatic zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp);\nstatic zip_source_t *source_nul(zip_t *za, zip_uint64_t length);\n\n\nstatic int\nadd_nul(char *argv[]) {\n    zip_source_t *zs;\n    zip_uint64_t length = strtoull(argv[1], NULL, 10);\n\n    if ((zs = source_nul(za, length)) == NULL) {\n        fprintf(stderr, \"can't create zip_source for length: %s\\n\", zip_strerror(za));\n        return -1;\n    }\n\n    if (zip_file_add(za, argv[0], zs, 0) == -1) {\n        zip_source_free(zs);\n        fprintf(stderr, \"can't add file '%s': %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\ncancel_callback(zip_t *archive, void *ud) {\n    if (progress_userdata.percentage >= progress_userdata.limit) {\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\ncancel(char *argv[]) {\n    zip_int64_t percent;\n    percent = strtoll(argv[0], NULL, 10);\n    if (percent > 100 || percent < 0) {\n        fprintf(stderr, \"invalid percentage '%\" PRId64 \"' for cancel (valid: 0 <= x <= 100)\\n\", percent);\n        return -1;\n    }\n    progress_userdata.limit = ((double)percent) / 100;\n\n    zip_register_cancel_callback_with_state(za, cancel_callback, NULL, NULL);\n\n    /* needs the percentage updates from print_progress */\n    print_progress(argv);\n    return 0;\n}\n\nstatic int\nextract_as(char *argv[]) {\n    zip_uint64_t idx;\n    FILE *fp;\n    int ret;\n\n    idx = strtoull(argv[0], NULL, 10);\n    if ((fp=fopen(argv[1], \"wb\")) == NULL) {\n        fprintf(stderr, \"can't open output file '%s': %s\", argv[1], strerror(errno));\n        return -1;\n    }\n    ret = cat_impl_backend(idx, 0, -1, fp);\n    if (fclose(fp) != 0) {\n        fprintf(stderr, \"can't close output file '%s': %s\", argv[1], strerror(errno));\n        ret = -1;\n    }\n    return ret;\n}\n\n\nstatic int\nis_seekable(char *argv[]) {\n    zip_uint64_t idx;\n    zip_file_t *zf;\n\n    idx = strtoull(argv[0], NULL, 10);\n    if ((zf = zip_fopen_index(za, idx, 0)) == NULL) {\n        fprintf(stderr, \"can't open file at index '%\" PRIu64 \"': %s\\n\", idx, zip_strerror(za));\n        return -1;\n    }\n    switch (zip_file_is_seekable(zf)) {\n    case -1:\n\tfprintf(stderr, \"can't check if file %\" PRIu64 \" is seekable: %s\\n\", idx, zip_strerror(za));\n\treturn -1;\n    case 0:\n\tprintf(\"%\" PRIu64 \": NOT seekable\\n\", idx);\n\tbreak;\n    case 1:\n\tprintf(\"%\" PRIu64 \": seekable\\n\", idx);\n\tbreak;\n    }\n    return 0;\n}\n\nstatic int\nregress_fseek(char *argv[]) {\n    zip_uint64_t file_idx;\n    zip_file_t *zf;\n    zip_int64_t offset;\n    int whence;\n\n    file_idx = strtoull(argv[0], NULL, 10);\n    offset = strtoll(argv[1], NULL, 10);\n    whence = get_whence(argv[2]);\n    if (file_idx >= z_files_count || z_files[file_idx] == NULL) {\n        fprintf(stderr, \"trying to seek in invalid opened file\\n\");\n        return -1;\n    }\n    zf = z_files[file_idx];\n\n    if (zip_fseek(zf, offset, whence) == -1) {\n\tfprintf(stderr, \"can't seek in file %\" PRIu64 \": %s\\n\", file_idx, zip_strerror(za));\n\treturn -1;\n    }\n    return 0;\n}\n\nstatic int\nunchange_all(char *argv[]) {\n    if (zip_unchange_all(za) < 0) {\n        fprintf(stderr, \"can't revert changes to archive: %s\\n\", zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\n\nstatic int\nunchange_one(char *argv[]) {\n    zip_uint64_t idx;\n\n    idx = strtoull(argv[0], NULL, 10);\n\n    if (zip_unchange(za, idx) < 0) {\n\tfprintf(stderr, \"can't revert changes for entry %\" PRIu64 \": %s\", idx, zip_strerror(za));\n\treturn -1;\n    }\n\n    return 0;\n}\n\nstatic int\nzin_close(char *argv[]) {\n    zip_uint64_t idx;\n\n    idx = strtoull(argv[0], NULL, 10);\n    if (idx >= z_in_count) {\n        fprintf(stderr, \"invalid argument '%\" PRIu64 \"', only %u zip sources open\\n\", idx, z_in_count);\n        return -1;\n    }\n    if (zip_close(z_in[idx]) < 0) {\n        fprintf(stderr, \"can't close source archive: %s\\n\", zip_strerror(z_in[idx]));\n        return -1;\n    }\n    z_in[idx] = z_in[z_in_count];\n    z_in_count--;\n\n    return 0;\n}\n\nstatic int\nregress_fopen(char *argv[]) {\n    if (z_files_count >= (sizeof(z_files) / sizeof(*z_files))) {\n        fprintf(stderr, \"too many open files\\n\");\n        return -1;\n    }\n    if ((z_files[z_files_count] = zip_fopen(za, argv[0], 0)) == NULL) {\n        fprintf(stderr, \"can't open entry '%s' from input archive: %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    printf(\"opened '%s' as file %u\\n\", argv[0], z_files_count);\n    z_files_count += 1;\n    return 0;\n}\n\n\nstatic int\nregress_fread(char *argv[]) {\n    zip_uint64_t file_idx;\n    zip_uint64_t length;\n    char buf[8192];\n    zip_int64_t n;\n    zip_file_t *f;\n\n    file_idx = strtoull(argv[0], NULL, 10);\n    length = strtoull(argv[1], NULL, 10);\n\n    if (file_idx >= z_files_count || z_files[file_idx] == NULL) {\n        fprintf(stderr, \"trying to read from invalid opened file\\n\");\n        return -1;\n    }\n    f = z_files[file_idx];\n    while (length > 0) {\n        zip_uint64_t to_read;\n\n        if (length > sizeof (buf)) {\n            to_read = sizeof (buf);\n        } else {\n            to_read = length;\n        }\n        n = zip_fread(f, buf, to_read);\n        if (n < 0) {\n            fprintf(stderr, \"can't read opened file %\" PRIu64 \": %s\\n\", file_idx, zip_file_strerror(f));\n            return -1;\n        }\n        if (n == 0) {\n#if 0\n            fprintf(stderr, \"premature end of opened file %\" PRIu64 \"\\n\", file_idx);\n            return -1;\n#else\n            break;\n#endif\n        }\n        if (fwrite(buf, (size_t)n, 1, stdout) != 1) {\n            fprintf(stderr, \"can't write file contents to stdout: %s\\n\", strerror(errno));\n            return -1;\n        }\n        length -= n;\n    }\n    return 0;\n}\n\n\nstatic zip_t *\nread_hole(const char *archive, int flags, zip_error_t *error) {\n    zip_source_t *src = NULL;\n    zip_t *zs = NULL;\n\n    if (strcmp(archive, \"/dev/stdin\") == 0) {\n        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((src = source_hole_create(archive, flags, error)) == NULL || (zs = zip_open_from_source(src, flags, error)) == NULL) {\n        zip_source_free(src);\n    }\n\n    return zs;\n}\n\n\nstatic int get_whence(const char *str) {\n    if (strcasecmp(str, \"set\") == 0) {\n        return SEEK_SET;\n    }\n    else if (strcasecmp(str, \"cur\") == 0) {\n        return SEEK_CUR;\n    }\n    else if (strcasecmp(str, \"end\") == 0) {\n        return SEEK_END;\n    }\n    else {\n        return 100; /* invalid */\n    }\n}\n\n\nstatic zip_t *\nread_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp) {\n    zip_source_t *src;\n    zip_t *zb;\n    FILE *fp;\n\n    if (strcmp(archive, \"/dev/stdin\") == 0) {\n        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);\n        return NULL;\n    }\n\n    if ((fp = fopen(archive, \"rb\")) == NULL) {\n        if (errno == ENOENT) {\n            src = zip_source_buffer_create(NULL, 0, 0, error);\n        }\n        else {\n            zip_error_set(error, ZIP_ER_OPEN, errno);\n            return NULL;\n        }\n    }\n    else {\n        struct stat st;\n\n        if (fstat(fileno(fp), &st) < 0) {\n            fclose(fp);\n            zip_error_set(error, ZIP_ER_OPEN, errno);\n            return NULL;\n        }\n        if (fragment_size == 0) {\n            char *buf;\n            if ((buf = malloc((size_t)st.st_size)) == NULL) {\n                fclose(fp);\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return NULL;\n            }\n            if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {\n                free(buf);\n                fclose(fp);\n                zip_error_set(error, ZIP_ER_READ, errno);\n                return NULL;\n            }\n            src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error);\n            if (src == NULL) {\n                free(buf);\n            }\n        }\n        else {\n            zip_uint64_t nfragments, i, left;\n            zip_buffer_fragment_t *fragments;\n\n            nfragments = ((size_t)st.st_size + fragment_size - 1) / fragment_size;\n            if ((fragments = malloc(sizeof(fragments[0]) * nfragments)) == NULL) {\n                fclose(fp);\n                zip_error_set(error, ZIP_ER_MEMORY, 0);\n                return NULL;\n            }\n            for (i = 0; i < nfragments; i++) {\n                left = ZIP_MIN(fragment_size, (size_t)st.st_size - i * fragment_size);\n                if ((fragments[i].data = malloc(left)) == NULL) {\n#ifndef __clang_analyzer__\n                    /* fragments is initialized up to i - 1*/\n                    while (--i > 0) {\n                        free(fragments[i].data);\n                    }\n#endif\n                    free(fragments);\n                    fclose(fp);\n                    zip_error_set(error, ZIP_ER_MEMORY, 0);\n                    return NULL;\n                }\n                fragments[i].length = left;\n                if (fread(fragments[i].data, left, 1, fp) < 1) {\n#ifndef __clang_analyzer__\n                    /* fragments is initialized up to i - 1*/\n                    while (--i > 0) {\n                        free(fragments[i].data);\n                    }\n#endif\n                    free(fragments);\n                    fclose(fp);\n                    zip_error_set(error, ZIP_ER_READ, errno);\n                    return NULL;\n                }\n            }\n            src = zip_source_buffer_fragment_create(fragments, nfragments, 1, error);\n            if (src == NULL) {\n                for (i = 0; i < nfragments; i++) {\n                    free(fragments[i].data);\n                }\n                free(fragments);\n                fclose(fp);\n                return NULL;\n            }\n            free(fragments);\n        }\n        fclose(fp);\n    }\n    if (src == NULL) {\n        return NULL;\n    }\n    zb = zip_open_from_source(src, flags, error);\n    if (zb == NULL) {\n        zip_source_free(src);\n        return NULL;\n    }\n    zip_source_keep(src);\n    *srcp = src;\n    return zb;\n}\n\n\ntypedef struct source_nul {\n    zip_error_t error;\n    zip_uint64_t length;\n    zip_uint64_t offset;\n} source_nul_t;\n\nstatic zip_int64_t\nsource_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) {\n    source_nul_t *ctx = (source_nul_t *)ud;\n\n    switch (command) {\n    case ZIP_SOURCE_CLOSE:\n        return 0;\n\n    case ZIP_SOURCE_ERROR:\n        return zip_error_to_data(&ctx->error, data, length);\n\n    case ZIP_SOURCE_FREE:\n        free(ctx);\n        return 0;\n\n    case ZIP_SOURCE_OPEN:\n        ctx->offset = 0;\n        return 0;\n\n    case ZIP_SOURCE_READ:\n        if (length > ZIP_INT64_MAX) {\n            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);\n            return -1;\n        }\n\n        if (length > ctx->length - ctx->offset) {\n            length = ctx->length - ctx->offset;\n        }\n\n        memset(data, 0, length);\n        ctx->offset += length;\n        return (zip_int64_t)length;\n\n    case ZIP_SOURCE_STAT: {\n        zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);\n\n        if (st == NULL) {\n            return -1;\n        }\n\n        st->valid |= ZIP_STAT_SIZE;\n        st->size = ctx->length;\n\n        return 0;\n    }\n\n    case ZIP_SOURCE_SUPPORTS:\n        return zip_source_make_command_bitmap(ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_STAT, -1);\n\n    default:\n        zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);\n        return -1;\n    }\n}\n\nstatic zip_source_t *\nsource_nul(zip_t *zs, zip_uint64_t length) {\n    source_nul_t *ctx;\n    zip_source_t *src;\n\n    if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {\n        zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);\n        return NULL;\n    }\n\n    zip_error_init(&ctx->error);\n    ctx->length = length;\n    ctx->offset = 0;\n\n    if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {\n        free(ctx);\n        return NULL;\n    }\n\n    return src;\n}\n\n\nstatic int\nwrite_memory_src_to_file(const char *archive, zip_source_t *src) {\n    zip_stat_t zst;\n    char *buf;\n    FILE *fp;\n\n    if (zip_source_stat(src, &zst) < 0) {\n        fprintf(stderr, \"zip_source_stat on buffer failed: %s\\n\", zip_error_strerror(zip_source_error(src)));\n        return -1;\n    }\n    if (zip_source_open(src) < 0) {\n        if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {\n            if (unlink(archive) < 0 && errno != ENOENT) {\n                fprintf(stderr, \"unlink failed: %s\\n\", strerror(errno));\n                return -1;\n            }\n            return 0;\n        }\n        fprintf(stderr, \"zip_source_open on buffer failed: %s\\n\", zip_error_strerror(zip_source_error(src)));\n        return -1;\n    }\n    if ((buf = malloc(zst.size)) == NULL) {\n        fprintf(stderr, \"malloc failed: %s\\n\", strerror(errno));\n        zip_source_close(src);\n        return -1;\n    }\n    if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {\n        fprintf(stderr, \"zip_source_read on buffer failed: %s\\n\", zip_error_strerror(zip_source_error(src)));\n        zip_source_close(src);\n        free(buf);\n        return -1;\n    }\n    zip_source_close(src);\n    if ((fp = fopen(archive, \"wb\")) == NULL) {\n        fprintf(stderr, \"fopen failed: %s\\n\", strerror(errno));\n        free(buf);\n        return -1;\n    }\n    if (fwrite(buf, zst.size, 1, fp) < 1) {\n        fprintf(stderr, \"fwrite failed: %s\\n\", strerror(errno));\n        free(buf);\n        fclose(fp);\n        return -1;\n    }\n    free(buf);\n    if (fclose(fp) != 0) {\n        fprintf(stderr, \"fclose failed: %s\\n\", strerror(errno));\n        return -1;\n    }\n    return 0;\n}\n\n\nzip_t *\nziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len) {\n    switch (source_type) {\n    case SOURCE_TYPE_NONE:\n        za = read_from_file(archive, flags, error, offset, len);\n        break;\n\n    case SOURCE_TYPE_IN_MEMORY:\n        za = read_to_memory(archive, flags, error, &memory_src);\n        break;\n\n    case SOURCE_TYPE_HOLE:\n        za = read_hole(archive, flags, error);\n        break;\n    }\n\n    return za;\n}\n\n\nint\nziptool_post_close(const char *archive) {\n    if (source_type == SOURCE_TYPE_IN_MEMORY) {\n        if (write_memory_src_to_file(archive, memory_src) < 0) {\n            return -1;\n        }\n        zip_source_free(memory_src);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "external/libzip/src/CMakeLists.txt",
    "content": "check_function_exists(getopt HAVE_GETOPT)\nforeach(PROGRAM zipcmp zipmerge ziptool)\n  add_executable(${PROGRAM} ${PROGRAM}.c)\n  target_link_libraries(${PROGRAM} zip)\n  target_include_directories(${PROGRAM} PRIVATE BEFORE ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})\n  if(LIBZIP_DO_INSTALL)\n    install(TARGETS ${PROGRAM} EXPORT ${PROJECT_NAME}-bin-targets DESTINATION bin)\n  endif()\n  if(NOT HAVE_GETOPT)\n    target_sources(${PROGRAM} PRIVATE getopt.c)\n  endif(NOT HAVE_GETOPT)\nendforeach()\ntarget_sources(zipcmp PRIVATE diff_output.c)\ntarget_link_libraries(zipcmp ${FTS_LIB} ZLIB::ZLIB)\n"
  },
  {
    "path": "external/libzip/src/diff_output.c",
    "content": "#include \"diff_output.h\"\n\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"compat.h\"\n\nstatic void\nensure_header(diff_output_t *output) {\n    if (output->archive_names[0] != NULL) {\n        printf(\"--- %s\\n\", output->archive_names[0]);\n        printf(\"+++ %s\\n\", output->archive_names[1]);\n        output->archive_names[0] = NULL;\n        output->archive_names[1] = NULL;\n    }\n}\n\nvoid\ndiff_output_init(diff_output_t *output, int verbose, char *const archive_names[]) {\n    output->archive_names[0] = archive_names[0];\n    output->archive_names[1] = archive_names[1];\n    output->verbose = verbose;\n    output->file_name = NULL;\n    output->file_size = 0;\n    output->file_crc = 0;\n    output->file_mtime = 0;\n}\n\nvoid\ndiff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime) {\n    output->file_name = name;\n    output->file_size = size;\n    output->file_crc = crc;\n    output->file_mtime = mtime;\n}\n\nvoid\ndiff_output_end_file(diff_output_t *output) {\n    output->file_name = NULL;\n}\n\nvoid\ndiff_output(diff_output_t *output, int side, const char *fmt, ...) {\n    va_list ap;\n\n    if (!output->verbose) {\n        return;\n    }\n\n    ensure_header(output);\n\n    if (output->file_name != NULL) {\n        diff_output_file(output, ' ', output->file_name, output->file_size, output->file_crc, output->file_mtime);\n        output->file_name = NULL;\n    }\n\n    printf(\"%c \", side);\n    va_start(ap, fmt);\n    vprintf(fmt, ap);\n    va_end(ap);\n    printf(\"\\n\");\n}\n\nvoid\ndiff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime) {\n    if (!output->verbose) {\n        return;\n    }\n\n    ensure_header(output);\n\n    if (size == 0 && crc == 0 && name[0] != '\\0' && name[strlen(name) - 1] == '/') {\n        printf(\"%c directory '%s'\\n\", side, name);\n    }\n    else {\n        printf(\"%c file '%s', size %\" PRIu64 \", crc %08x, mtime %\" PRIu64 \"\\n\", side, name, size, crc, mtime);\n    }\n}\n\n#define MAX_BYTES 64\nvoid\ndiff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) {\n    char prefix[1024];\n    char hexdata[MAX_BYTES * 3 + 6];\n    size_t i, offset;\n    va_list ap;\n\n    if (!output->verbose) {\n        return;\n    }\n\n    offset = 0;\n    for (i = 0; i < data_length; i++) {\n        hexdata[offset++] = (i == 0 ? '<' : ' ');\n\n        if (i >= MAX_BYTES) {\n            snprintf(hexdata + offset, sizeof(hexdata) - offset, \"...\");\n            break;\n        }\n        snprintf(hexdata + offset, sizeof(hexdata) - offset, \"%02x\", data[i]);\n        offset += 2;\n    }\n\n    hexdata[offset++] = '>';\n    hexdata[offset] = '\\0';\n\n    va_start(ap, fmt);\n    vsnprintf(prefix, sizeof(prefix), fmt, ap);\n    va_end(ap);\n    prefix[sizeof(prefix) - 1] = '\\0';\n\n    diff_output(output, side, \"%s, length %\" PRIu64 \", data %s\", prefix, data_length, hexdata);\n}\n"
  },
  {
    "path": "external/libzip/src/diff_output.h",
    "content": "#ifndef HAD_DIFF_OUTPUT_H\n#define HAD_DIFF_OUTPUT_H\n\n#include <zip.h>\n\ntypedef struct {\n    const char *archive_names[2];\n    const char *file_name;\n    zip_uint64_t file_size;\n    zip_uint32_t file_crc;\n    zip_uint64_t file_mtime;\n    int verbose;\n} diff_output_t;\n\n#if defined(__GNUC__) && __GNUC__ >= 4\n#define PRINTF_LIKE(n, m) __attribute__((__format__(__printf__, n, m)))\n#else\n#define PRINTF_LIKE(n, m)\n#endif\n\nvoid diff_output_init(diff_output_t *output, int verbose, char *const archive_names[]);\nvoid diff_output_start_file(diff_output_t *output, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime);\nvoid diff_output_end_file(diff_output_t *output);\n\nvoid diff_output(diff_output_t *output, int side, const char *fmt, ...) PRINTF_LIKE(3, 4);\nvoid diff_output_data(diff_output_t *output, int side, const zip_uint8_t *data, zip_uint64_t data_length, const char *fmt, ...) PRINTF_LIKE(5, 6);\nvoid diff_output_file(diff_output_t *output, char side, const char *name, zip_uint64_t size, zip_uint32_t crc, zip_uint64_t mtime);\n\n#endif /* HAD_DIFF_OUTPUT_H */\n"
  },
  {
    "path": "external/libzip/src/getopt.c",
    "content": "/*\n * getopt.c --\n *\n *      Standard UNIX getopt function.  Code is from BSD.\n *\n * Copyright (c) 1987-2002 The Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * A. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * B. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * C. Neither the names of the copyright holders nor the names of its\n *    contributors may be used to endorse or promote products derived from this\n *    software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS\n * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n/* #if !defined(lint)\n * static char sccsid[] = \"@(#)getopt.c 8.2 (Berkeley) 4/2/94\";\n * #endif\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"getopt.h\"\n\nint opterr = 1, /* if error message should be printed */\n    optind = 1, /* index into parent argv vector */\n    optopt,     /* character checked for validity */\n    optreset;   /* reset getopt */\nchar *optarg;   /* argument associated with option */\n\n#define BADCH (int)'?'\n#define BADARG (int)':'\n#define EMSG \"\"\n\n/*\n * getopt --\n *      Parse argc/argv argument vector.\n */\nint\ngetopt(int nargc, char *const *nargv, const char *ostr) {\n    static char *place = EMSG; /* option letter processing */\n    char *oli;                 /* option letter list index */\n\n    if (optreset || !*place) { /* update scanning pointer */\n        optreset = 0;\n        if (optind >= nargc || *(place = nargv[optind]) != '-') {\n            place = EMSG;\n            return (EOF);\n        }\n        if (place[1] && *++place == '-') { /* found \"--\" */\n            ++optind;\n            place = EMSG;\n            return (EOF);\n        }\n    } /* option letter okay? */\n    if ((optopt = (int)*place++) == (int)':' || !(oli = (char *)strchr(ostr, optopt))) {\n        /*\n         * if the user didn't specify '-' as an option,\n         * assume it means EOF.\n         */\n        if (optopt == (int)'-')\n            return (EOF);\n        if (!*place)\n            ++optind;\n        if (opterr && *ostr != ':')\n            (void)fprintf(stderr, \"illegal option -- %c\\n\", optopt);\n        return (BADCH);\n    }\n    if (*++oli != ':') { /* don't need argument */\n        optarg = NULL;\n        if (!*place)\n            ++optind;\n    }\n    else {          /* need an argument */\n        if (*place) /* no white space */\n            optarg = place;\n        else if (nargc <= ++optind) { /* no arg */\n            place = EMSG;\n            if (*ostr == ':')\n                return (BADARG);\n            if (opterr)\n                (void)fprintf(stderr, \"option requires an argument -- %c\\n\", optopt);\n            return (BADCH);\n        }\n        else /* white space */\n            optarg = nargv[optind];\n        place = EMSG;\n        ++optind;\n    }\n    return (optopt); /* dump back option letter */\n}\n"
  },
  {
    "path": "external/libzip/src/getopt.h",
    "content": "#ifndef _HAD_GETOPT_H\n#define _HAD_GETOPT_H\n\n/*\n  getopt.h -- header for getopt() replacement function\n  Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern char *optarg;\nextern int optind;\nextern int opterr;\n\nextern int getopt(int, char *const *, const char *);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _HAD_GETOPT_H */\n"
  },
  {
    "path": "external/libzip/src/zipcmp.c",
    "content": "/*\n  zipcmp.c -- compare zip files\n  Copyright (C) 2003-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif\n#ifdef HAVE_FTS_H\n#include <fts.h>\n#endif\n#include <zlib.h>\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\n\n#include \"zip.h\"\n\n#include \"compat.h\"\n\n#include \"diff_output.h\"\n\nstruct archive {\n    const char *name;\n    zip_t *za;\n    zip_uint64_t nentry;\n    struct entry *entry;\n    const char *comment;\n    size_t comment_length;\n};\n\nstruct ef {\n    const char *name;\n    zip_uint16_t flags;\n    zip_uint16_t id;\n    zip_uint16_t size;\n    const zip_uint8_t *data;\n};\n\nstruct entry {\n    char *name;\n    zip_uint64_t size;\n    zip_uint32_t crc;\n    zip_uint32_t comp_method;\n    time_t last_modification_time;\n    struct ef *extra_fields;\n    zip_uint16_t n_extra_fields;\n    const char *comment;\n    zip_uint32_t comment_length;\n};\n\n\ntypedef struct {\n    uint32_t value;\n    const char *const name;\n} enum_map_t;\n\nconst enum_map_t comp_methods[] = {{0, \"Stored (no compression)\"}, {1, \"Shrunk\"}, {2, \"Reduced with compression factor 1\"}, {3, \"Reduced with compression factor 2\"}, {4, \"Reduced with compression factor 3\"}, {5, \"Reduced with compression factor 4\"}, {6, \"Imploded\"}, {7, \"Reserved for Tokenizing compression algorithm\"}, {8, \"Deflated\"}, {9, \"Enhanced Deflating using Deflate64(tm)\"}, {10, \"PKWARE Data Compression Library Imploding (old IBM TERSE)\"}, {11, \"11 (Reserved by PKWARE)\"}, {12, \"BZIP2\"}, {13, \"13 (Reserved by PKWARE)\"}, {14, \"LZMA (EFS)\"}, {15, \"15 (Reserved by PKWARE)\"}, {16, \"16 (Reserved by PKWARE)\"}, {17, \"17 (Reserved by PKWARE)\"}, {18, \"IBM TERSE (new)\"}, {19, \"IBM LZ77 z Architecture (PFS)\"}, {20, \"Zstandard compressed data (obsolete)\"}, {93, \"Zstandard compressed data\"}, {95, \"XZ compressed data\"}, {97, \"WavPack compressed data\"}, {98, \"PPMd version I, Rev 1\"}, {99, \"WinZIP AES Encryption\"}, {UINT32_MAX, NULL}};\n\nconst enum_map_t extra_fields[] = {\n    /* PKWARE defined */\n    {0x0001, \"Zip64 extended information\"},\n    {0x0007, \"AV Info\"},\n    {0x0008, \"Reserved for extended language encoding data (PFS)\"},\n    {0x0009, \"OS/2\"},\n    {0x000a, \"NTFS\"},\n    {0x000c, \"OpenVMS\"},\n    {0x000d, \"UNIX\"},\n    {0x000e, \"Reserved for file stream and fork descriptors\"},\n    {0x000f, \"Patch Descriptor\"},\n    {0x0014, \"PKCS#7 Store for X.509 Certificates\"},\n    {0x0015, \"X.509 Certificate ID and Signature for individual file\"},\n    {0x0016, \"X.509 Certificate ID for Central Directory\"},\n    {0x0017, \"Strong Encryption Header\"},\n    {0x0018, \"Record Management Controls\"},\n    {0x0019, \"PKCS#7 Encryption Recipient Certificate List\"},\n    {0x0065, \"IBM S/390 (Z390), AS/400 (I400) attributes - uncompressed\"},\n    {0x0066, \"Reserved for IBM S/390 (Z390), AS/400 (I400) attributes - compressed\"},\n    {0x4690, \"POSZIP 4690 (reserved)\"},\n\n    /* Third-Party defined; see InfoZIP unzip sources proginfo/extrafld.txt */\n    {0x07c8, \"Info-ZIP Macintosh (old)\"},\n    {0x2605, \"ZipIt Macintosh (first version)\"},\n    {0x2705, \"ZipIt Macintosh 1.3.5+ (w/o full filename)\"},\n    {0x2805, \"ZipIt Macintosh 1.3.5+\"},\n    {0x334d, \"Info-ZIP Macintosh (new)\"},\n    {0x4154, \"Tandem NSK\"},\n    {0x4341, \"Acorn/SparkFS\"},\n    {0x4453, \"Windows NT security descriptor\"},\n    {0x4704, \"VM/CMS\"},\n    {0x470f, \"MVS\"},\n    {0x4854, \"Theos, old unofficial port\"},\n    {0x4b46, \"FWKCS MD5\"},\n    {0x4c41, \"OS/2 access control list (text ACL)\"},\n    {0x4d49, \"Info-ZIP OpenVMS (obsolete)\"},\n    {0x4d63, \"Macintosh SmartZIP\"},\n    {0x4f4c, \"Xceed original location extra field\"},\n    {0x5356, \"AOS/VS (ACL)\"},\n    {0x5455, \"extended timestamp\"},\n    {0x554e, \"Xceed unicode extra field\"},\n    {0x5855, \"Info-ZIP UNIX (original)\"},\n    {0x6375, \"Info-ZIP UTF-8 comment field\"},\n    {0x6542, \"BeOS (BeBox, PowerMac, etc.)\"},\n    {0x6854, \"Theos\"},\n    {0x7075, \"Info-ZIP UTF-8 name field\"},\n    {0x7441, \"AtheOS (AtheOS/Syllable attributes)\"},\n    {0x756e, \"ASi UNIX\"},\n    {0x7855, \"Info-ZIP UNIX\"},\n    {0x7875, \"Info-ZIP UNIX 3rd generation\"},\n    {0x9901, \"WinZIP AES encryption\"},\n    {0xa220, \"Microsoft Open Packaging Growth Hint\"},\n    {0xcafe, \"executable Java JAR file\"},\n    {0xfb4a, \"SMS/QDOS\"}, /* per InfoZIP extrafld.txt */\n    {0xfd4a, \"SMS/QDOS\"}, /* per appnote.txt */\n    {UINT32_MAX, NULL}};\n\n\nconst char *progname;\n\n#define PROGRAM \"zipcmp\"\n\n#define USAGE \"usage: %s [-\" OPTIONS \"] archive1 archive2\\n\"\n\nchar help_head[] = PROGRAM \" (\" PACKAGE \") by Dieter Baron and Thomas Klausner\\n\\n\";\n\nchar help[] = \"\\n\\\n  -C       check archive consistencies\\n\\\n  -h       display this help message\\n\\\n  -i       compare names ignoring case distinctions\\n\\\n  -p       compare as many details as possible\\n\\\n  -q       be quiet\\n\\\n  -s       print a summary\\n\\\n  -T       compare time stamps\\n\\\n  -t       test zip files (compare file contents to checksum)\\n\\\n  -V       display version number\\n\\\n  -v       be verbose (print differences, default)\\n\\\n\\n\\\nReport bugs to <info@libzip.org>.\\n\";\n\nchar version_string[] = PROGRAM \" (\" PACKAGE \" \" VERSION \")\\n\\\nCopyright (C) 2003-2024 Dieter Baron and Thomas Klausner\\n\\\n\" PACKAGE \" comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\\n\";\n\n#define OPTIONS \"ChipqsTtVv\"\n\n\n#define BOTH_ARE_ZIPS(a) (a[0].za && a[1].za)\n\nstatic int comment_compare(const char *c1, size_t l1, const char *c2, size_t l2);\nstatic int compare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element));\nstatic int compare_zip(char *const zn[]);\nstatic int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2);\nstatic int ef_order(const void *a, const void *b);\nstatic void ef_print(char side, const void *p);\nstatic int ef_read(zip_t *za, zip_uint64_t idx, struct entry *e);\nstatic int entry_cmp(const void *p1, const void *p2);\nstatic int entry_ignore(const void *p1, int last, const void *o);\nstatic int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2);\nstatic void entry_print(char side, const void *p);\nstatic void entry_start_file(const void *p);\nstatic const char *map_enum(const enum_map_t *map, uint32_t value);\n\nstatic int is_directory(const char *name);\n#ifdef HAVE_FTS_H\nstatic int list_directory(const char *name, struct archive *a);\n#endif\nstatic int list_zip(const char *name, struct archive *a);\nstatic int test_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc);\n\nint ignore_case, test_files, paranoid, verbose, have_directory, check_consistency, compare_time_stamps, summary;\nint plus_count = 0, minus_count = 0;\n\ndiff_output_t output;\n\n\nint\nmain(int argc, char *const argv[]) {\n    int c;\n\n    progname = argv[0];\n\n    ignore_case = 0;\n    test_files = 0;\n    check_consistency = 0;\n    compare_time_stamps = 0;\n    paranoid = 0;\n    have_directory = 0;\n    verbose = 1;\n    summary = 0;\n\n    while ((c = getopt(argc, argv, OPTIONS)) != -1) {\n        switch (c) {\n        case 'C':\n            check_consistency = 1;\n            break;\n        case 'h':\n            fputs(help_head, stdout);\n            printf(USAGE, progname);\n            fputs(help, stdout);\n            exit(0);\n        case 'i':\n            ignore_case = 1;\n            break;\n        case 'p':\n            paranoid = 1;\n            break;\n        case 'q':\n            verbose = 0;\n            break;\n        case 's':\n            summary = 1;\n            break;\n        case 'T':\n            compare_time_stamps = 1;\n            break;\n        case 't':\n            test_files = 1;\n            break;\n        case 'V':\n            fputs(version_string, stdout);\n            exit(0);\n        case 'v':\n            verbose = 1;\n            break;\n\n        default:\n            fprintf(stderr, USAGE, progname);\n            exit(2);\n        }\n    }\n\n    if (argc != optind + 2) {\n        fprintf(stderr, USAGE, progname);\n        exit(2);\n    }\n\n    exit((compare_zip(argv + optind) == 0) ? 0 : 1);\n}\n\n\nstatic int\ncompare_zip(char *const zn[]) {\n    struct archive a[2];\n    struct entry *e[2];\n    zip_uint64_t n[2];\n    int i;\n    int res;\n\n    for (i = 0; i < 2; i++) {\n        a[i].name = zn[i];\n        a[i].entry = NULL;\n        a[i].nentry = 0;\n        a[i].za = NULL;\n        a[i].comment = NULL;\n        a[i].comment_length = 0;\n\n        if (is_directory(zn[i])) {\n#ifndef HAVE_FTS_H\n            fprintf(stderr, \"%s: reading directories not supported\\n\", progname);\n            exit(2);\n#else\n            if (list_directory(zn[i], a + i) < 0)\n                exit(2);\n            have_directory = 1;\n            paranoid = 0; /* paranoid checks make no sense for directories, since they compare zip metadata */\n#endif\n        }\n        else {\n            if (list_zip(zn[i], a + i) < 0)\n                exit(2);\n        }\n        if (a[i].nentry > 0)\n            qsort(a[i].entry, a[i].nentry, sizeof(a[i].entry[0]), entry_cmp);\n    }\n\n    diff_output_init(&output, verbose, zn);\n\n    e[0] = a[0].entry;\n    e[1] = a[1].entry;\n    n[0] = a[0].nentry;\n    n[1] = a[1].nentry;\n    res = compare_list(zn, (const void **)e, n, sizeof(e[i][0]), entry_cmp, have_directory ? entry_ignore : NULL, paranoid ? entry_paranoia_checks : NULL, entry_print, entry_start_file);\n\n    if (paranoid) {\n        if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {\n            if (a[0].comment_length > 0) {\n                diff_output_data(&output, '-', (const zip_uint8_t *)a[0].comment, a[0].comment_length, \"archive comment\");\n                minus_count++;\n            }\n            if (a[1].comment_length > 0) {\n                diff_output_data(&output, '+', (const zip_uint8_t *)a[1].comment, a[1].comment_length, \"archive comment\");\n                plus_count++;\n            }\n            res = 1;\n        }\n    }\n\n    for (i = 0; i < 2; i++) {\n        zip_uint64_t j;\n\n        if (a[i].za) {\n            zip_close(a[i].za);\n        }\n        for (j = 0; j < a[i].nentry; j++) {\n            free(a[i].entry[j].name);\n        }\n        free(a[i].entry);\n    }\n\n    if (summary) {\n        printf(\"%d files removed, %d files added\\n\", minus_count, plus_count);\n    }\n\n    switch (res) {\n    case 0:\n        exit(0);\n\n    case 1:\n        exit(1);\n\n    default:\n        exit(2);\n    }\n}\n\n#ifdef HAVE_FTS_H\nstatic zip_int64_t\ncompute_crc(const char *fname) {\n    FILE *f;\n    uLong crc = crc32(0L, Z_NULL, 0);\n    size_t n;\n    Bytef buffer[8192];\n\n\n    if ((f = fopen(fname, \"rb\")) == NULL) {\n        fprintf(stderr, \"%s: can't open %s: %s\\n\", progname, fname, strerror(errno));\n        return -1;\n    }\n\n    while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) {\n        crc = crc32(crc, buffer, (unsigned int)n);\n    }\n\n    if (ferror(f)) {\n        fprintf(stderr, \"%s: read error on %s: %s\\n\", progname, fname, strerror(errno));\n        fclose(f);\n        return -1;\n    }\n\n    fclose(f);\n\n    return (zip_int64_t)crc;\n}\n#endif\n\n\nstatic int\nis_directory(const char *name) {\n    struct stat st;\n\n    if (stat(name, &st) < 0)\n        return 0;\n\n    return S_ISDIR(st.st_mode);\n}\n\n\n#ifdef HAVE_FTS_H\nstatic int\nlist_directory(const char *name, struct archive *a) {\n    FTS *fts;\n    FTSENT *ent;\n    zip_uint64_t nalloc;\n    size_t prefix_length;\n    size_t name_length;\n    char* normalized_name;\n\n    name_length = strlen(name);\n    if (name_length == 0) {\n        fprintf(stderr, \"%s: can't open directory '': invalid name\\n\", progname);\n        return -1;\n    }\n\n    normalized_name = strdup(name);\n\n    while (name_length > 0 && normalized_name[name_length-1] == '/') {\n        name_length -= 1;\n    }\n    normalized_name[name_length] = '\\0';\n\n    if (name_length == 0) {\n        normalized_name[0] = '/';\n        normalized_name[1] = '\\0';\n        name_length = 1;\n    }\n\n    prefix_length = name_length + 1;\n\n    char *const names[2] = {normalized_name, NULL};\n\n    if ((fts = fts_open(names, FTS_NOCHDIR | FTS_LOGICAL, NULL)) == NULL) {\n        fprintf(stderr, \"%s: can't open directory '%s': %s\\n\", progname, name, strerror(errno));\n        free(normalized_name);\n        return -1;\n    }\n\n    nalloc = 0;\n\n    while ((ent = fts_read(fts))) {\n        zip_int64_t crc;\n\n        switch (ent->fts_info) {\n        case FTS_DOT:\n        case FTS_DP:\n        case FTS_DEFAULT:\n        case FTS_SL:\n        case FTS_NSOK:\n            break;\n\n        case FTS_DC:\n        case FTS_DNR:\n        case FTS_ERR:\n        case FTS_NS:\n        case FTS_SLNONE:\n            /* TODO: error */\n            fts_close(fts);\n            return -1;\n\n        case FTS_D:\n        case FTS_F:\n            if (a->nentry >= nalloc) {\n                nalloc += 16;\n                if (nalloc > SIZE_MAX / sizeof(a->entry[0])) {\n                    fprintf(stderr, \"%s: malloc failure\\n\", progname);\n                    exit(1);\n                }\n                a->entry = realloc(a->entry, sizeof(a->entry[0]) * nalloc);\n                if (a->entry == NULL) {\n                    fprintf(stderr, \"%s: malloc failure\\n\", progname);\n                    exit(1);\n                }\n            }\n\n            if (ent->fts_info == FTS_D) {\n                char *dir_name;\n\n                if (ent->fts_path[prefix_length - 1] == '\\0') {\n                    break;\n                }\n\n                size_t dir_name_size = strlen(ent->fts_path + prefix_length) + 2;\n                dir_name = malloc(dir_name_size);\n                if (dir_name == NULL) {\n                    fprintf(stderr, \"%s: malloc failure\\n\", progname);\n                    exit(1);\n                }\n                snprintf(dir_name, dir_name_size, \"%s/\", ent->fts_path + prefix_length);\n                a->entry[a->nentry].name = dir_name;\n                a->entry[a->nentry].size = 0;\n                a->entry[a->nentry].crc = 0;\n                a->entry[a->nentry].last_modification_time = 0;\n            }\n            else {\n                a->entry[a->nentry].name = strdup(ent->fts_path + prefix_length);\n                a->entry[a->nentry].size = (zip_uint64_t)ent->fts_statp->st_size;\n                if ((crc = compute_crc(ent->fts_accpath)) < 0) {\n                    fts_close(fts);\n                    free(normalized_name);\n                    return -1;\n                }\n\n                a->entry[a->nentry].crc = (zip_uint32_t)crc;\n                a->entry[a->nentry].last_modification_time = ent->fts_statp->st_mtime;\n            }\n            a->nentry++;\n            break;\n        }\n    }\n\n    if (fts_close(fts)) {\n        fprintf(stderr, \"%s: error closing directory '%s': %s\\n\", progname, a->name, strerror(errno));\n        free(normalized_name);\n        return -1;\n    }\n\n    free(normalized_name);\n    return 0;\n}\n#endif\n\n\nstatic int\nlist_zip(const char *name, struct archive *a) {\n    zip_t *za;\n    int err;\n    struct zip_stat st;\n    unsigned int i;\n\n    if ((za = zip_open(name, check_consistency ? ZIP_CHECKCONS : 0, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: cannot open zip archive '%s': %s\\n\", progname, name, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return -1;\n    }\n\n    a->za = za;\n    a->nentry = (zip_uint64_t)zip_get_num_entries(za, 0);\n\n    if (a->nentry == 0)\n        a->entry = NULL;\n    else {\n        if ((a->nentry > SIZE_MAX / sizeof(a->entry[0])) || (a->entry = (struct entry *)malloc(sizeof(a->entry[0]) * a->nentry)) == NULL) {\n            fprintf(stderr, \"%s: malloc failure\\n\", progname);\n            exit(1);\n        }\n\n        for (i = 0; i < a->nentry; i++) {\n            zip_stat_index(za, i, 0, &st);\n            a->entry[i].name = strdup(st.name);\n            a->entry[i].size = st.size;\n            a->entry[i].crc = st.crc;\n            if (test_files)\n                test_file(za, i, name, st.name, st.size, st.crc);\n            if (paranoid) {\n                a->entry[i].comp_method = st.comp_method;\n                ef_read(za, i, a->entry + i);\n                a->entry[i].comment = zip_file_get_comment(za, i, &a->entry[i].comment_length, 0);\n            }\n            else {\n                a->entry[i].comp_method = 0;\n                a->entry[i].n_extra_fields = 0;\n            }\n            a->entry[i].last_modification_time = st.mtime;\n        }\n\n        if (paranoid) {\n            int length;\n            a->comment = zip_get_archive_comment(za, &length, 0);\n            a->comment_length = (size_t)length;\n        }\n        else {\n            a->comment = NULL;\n            a->comment_length = 0;\n        }\n    }\n\n    return 0;\n}\n\n\nstatic int\ncomment_compare(const char *c1, size_t l1, const char *c2, size_t l2) {\n    if (l1 != l2)\n        return 1;\n\n    if (l1 == 0)\n        return 0;\n\n    if (c1 == NULL || c2 == NULL)\n        return c1 == c2;\n\n    return memcmp(c1, c2, (size_t)l2);\n}\n\n\nstatic int\ncompare_list(char *const name[2], const void *list[2], const zip_uint64_t list_length[2], int element_size, int (*cmp)(const void *a, const void *b), int (*ignore)(const void *list, int last, const void *other), int (*check)(char *const name[2], const void *a, const void *b), void (*print)(char side, const void *element), void (*start_file)(const void *element)) {\n    unsigned int i[2];\n    int j;\n    int diff;\n\n#define INC(k) (i[k]++, list[k] = ((const char *)list[k]) + element_size)\n#define PRINT(k)                                                                                                         \\\n    do {                                                                                                                 \\\n        if (ignore && ignore(list[k], i[k] >= list_length[k] - 1, i[1 - k] < list_length[1 - k] ? list[1 - k] : NULL)) { \\\n            break;                                                                                                       \\\n        }                                                                                                                \\\n        print((k) ? '+' : '-', list[k]);                                                                                 \\\n        (k) ? plus_count++ : minus_count++;                                                                              \\\n        diff = 1;                                                                                                        \\\n    } while (0)\n\n    i[0] = i[1] = 0;\n    diff = 0;\n    while (i[0] < list_length[0] && i[1] < list_length[1]) {\n        int c = cmp(list[0], list[1]);\n\n        if (c == 0) {\n            if (check) {\n                if (start_file) {\n                    start_file(list[0]);\n                }\n                diff |= check(name, list[0], list[1]);\n                if (start_file) {\n                    diff_output_end_file(&output);\n                }\n            }\n            INC(0);\n            INC(1);\n        }\n        else if (c < 0) {\n            PRINT(0);\n            INC(0);\n        }\n        else {\n            PRINT(1);\n            INC(1);\n        }\n    }\n\n    for (j = 0; j < 2; j++) {\n        while (i[j] < list_length[j]) {\n            PRINT(j);\n            INC(j);\n        }\n    }\n\n    return diff;\n}\n\n\nstatic int\nef_read(zip_t *za, zip_uint64_t idx, struct entry *e) {\n    zip_int16_t n_local, n_central;\n    zip_uint16_t i;\n\n    if ((n_local = zip_file_extra_fields_count(za, idx, ZIP_FL_LOCAL)) < 0 || (n_central = zip_file_extra_fields_count(za, idx, ZIP_FL_CENTRAL)) < 0) {\n        return -1;\n    }\n\n    e->n_extra_fields = (zip_uint16_t)(n_local + n_central);\n\n    if ((e->extra_fields = (struct ef *)malloc(sizeof(e->extra_fields[0]) * e->n_extra_fields)) == NULL)\n        return -1;\n\n    for (i = 0; i < n_local; i++) {\n        e->extra_fields[i].name = e->name;\n        e->extra_fields[i].data = zip_file_extra_field_get(za, idx, i, &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_LOCAL);\n        if (e->extra_fields[i].data == NULL)\n            return -1;\n        e->extra_fields[i].flags = ZIP_FL_LOCAL;\n    }\n    for (; i < e->n_extra_fields; i++) {\n        e->extra_fields[i].name = e->name;\n        e->extra_fields[i].data = zip_file_extra_field_get(za, idx, (zip_uint16_t)(i - n_local), &e->extra_fields[i].id, &e->extra_fields[i].size, ZIP_FL_CENTRAL);\n        if (e->extra_fields[i].data == NULL)\n            return -1;\n        e->extra_fields[i].flags = ZIP_FL_CENTRAL;\n    }\n\n    qsort(e->extra_fields, e->n_extra_fields, sizeof(e->extra_fields[0]), ef_order);\n\n    return 0;\n}\n\n\nstatic int\nef_compare(char *const name[2], const struct entry *e1, const struct entry *e2) {\n    struct ef *ef[2];\n    zip_uint64_t n[2];\n\n    ef[0] = e1->extra_fields;\n    ef[1] = e2->extra_fields;\n    n[0] = e1->n_extra_fields;\n    n[1] = e2->n_extra_fields;\n\n    return compare_list(name, (const void **)ef, n, sizeof(struct ef), ef_order, NULL, NULL, ef_print, NULL);\n}\n\n\nstatic int\nef_order(const void *ap, const void *bp) {\n    const struct ef *a, *b;\n\n    a = (struct ef *)ap;\n    b = (struct ef *)bp;\n\n    if (a->flags != b->flags)\n        return a->flags - b->flags;\n    if (a->id != b->id)\n        return a->id - b->id;\n    if (a->size != b->size)\n        return a->size - b->size;\n    return memcmp(a->data, b->data, a->size);\n}\n\n\nstatic void\nef_print(char side, const void *p) {\n    const struct ef *ef = (struct ef *)p;\n\n    diff_output_data(&output, side, ef->data, ef->size, \"  %s extra field %s\", ef->flags == ZIP_FL_LOCAL ? \"local\" : \"central\", map_enum(extra_fields, ef->id));\n}\n\n\nstatic int\nentry_cmp(const void *p1, const void *p2) {\n    const struct entry *e1, *e2;\n    int c;\n\n    e1 = (struct entry *)p1;\n    e2 = (struct entry *)p2;\n\n    if ((c = (ignore_case ? strcasecmp : strcmp)(e1->name, e2->name)) != 0)\n        return c;\n    if (e1->size != e2->size) {\n        if (e1->size > e2->size)\n            return 1;\n        else\n            return -1;\n    }\n    if (e1->crc != e2->crc) {\n        return (int)e1->crc - (int)e2->crc;\n    }\n    if (compare_time_stamps && e1->last_modification_time != e2->last_modification_time) {\n        return (int)(e1->last_modification_time - e2->last_modification_time);\n    }\n\n    return 0;\n}\n\n\nstatic int\nentry_ignore(const void *p, int last, const void *o) {\n    const struct entry *e = (const struct entry *)p;\n    const struct entry *other = (const struct entry *)o;\n\n    size_t length = strlen(e[0].name);\n\n    if (length == 0 || e[0].name[length - 1] != '/') {\n        /* not a directory */\n        return 0;\n    }\n\n    if (other != NULL && strlen(other->name) > length && strncmp(other->name, e[0].name, length) == 0) {\n        /* not empty in other archive */\n        return 1;\n    }\n\n    if (last || (strlen(e[1].name) < length || strncmp(e[0].name, e[1].name, length) != 0)) {\n        /* empty in this archive */\n        return 0;\n    }\n\n    /* not empty in this archive */\n    return 1;\n}\n\n\nstatic int\nentry_paranoia_checks(char *const name[2], const void *p1, const void *p2) {\n    const struct entry *e1, *e2;\n    int ret;\n\n    e1 = (struct entry *)p1;\n    e2 = (struct entry *)p2;\n\n    ret = 0;\n\n    if (e1->comp_method != e2->comp_method) {\n        diff_output(&output, '-', \"  compression method %s\", map_enum(comp_methods, e1->comp_method));\n        diff_output(&output, '+', \"  compression method %s\", map_enum(comp_methods, e2->comp_method));\n        ret = 1;\n    }\n\n    if (ef_compare(name, e1, e2) != 0) {\n        ret = 1;\n    }\n\n    if (comment_compare(e1->comment, e1->comment_length, e2->comment, e2->comment_length) != 0) {\n        diff_output_data(&output, '-', (const zip_uint8_t *)e1->comment, e1->comment_length, \"  comment\");\n        diff_output_data(&output, '+', (const zip_uint8_t *)e2->comment, e2->comment_length, \"  comment\");\n        ret = 1;\n    }\n\n    return ret;\n}\n\n\nstatic void\nentry_print(char side, const void *p) {\n    const struct entry *e = (struct entry *)p;\n\n    diff_output_file(&output, side, e->name, e->size, e->crc, e->last_modification_time);\n}\n\n\nstatic void\nentry_start_file(const void *p) {\n    const struct entry *e = (struct entry *)p;\n\n    diff_output_start_file(&output, e->name, e->size, e->crc, e->last_modification_time);\n}\n\n\nstatic int\ntest_file(zip_t *za, zip_uint64_t idx, const char *zipname, const char *filename, zip_uint64_t size, zip_uint32_t crc) {\n    zip_file_t *zf;\n    char buf[8192];\n    zip_uint64_t nsize;\n    zip_int64_t n;\n    zip_uint32_t ncrc;\n\n    if ((zf = zip_fopen_index(za, idx, 0)) == NULL) {\n        fprintf(stderr, \"%s: %s: cannot open file %s (index %\" PRIu64 \"): %s\\n\", progname, zipname, filename, idx, zip_strerror(za));\n        return -1;\n    }\n\n    ncrc = (zip_uint32_t)crc32(0, NULL, 0);\n    nsize = 0;\n\n    while ((n = zip_fread(zf, buf, sizeof(buf))) > 0) {\n        nsize += (zip_uint64_t)n;\n        ncrc = (zip_uint32_t)crc32(ncrc, (const Bytef *)buf, (unsigned int)n);\n    }\n\n    if (n < 0) {\n        fprintf(stderr, \"%s: %s: error reading file %s (index %\" PRIu64 \"): %s\\n\", progname, zipname, filename, idx, zip_file_strerror(zf));\n        zip_fclose(zf);\n        return -1;\n    }\n\n    zip_fclose(zf);\n\n    if (nsize != size) {\n        fprintf(stderr, \"%s: %s: file %s (index %\" PRIu64 \"): unexpected length %\" PRId64 \" (should be %\" PRId64 \")\\n\", progname, zipname, filename, idx, nsize, size);\n        return -2;\n    }\n    if (ncrc != crc) {\n        fprintf(stderr, \"%s: %s: file %s (index %\" PRIu64 \"): unexpected length %x (should be %x)\\n\", progname, zipname, filename, idx, ncrc, crc);\n        return -2;\n    }\n\n    return 0;\n}\n\n\nstatic const char *\nmap_enum(const enum_map_t *map, uint32_t value) {\n    static char unknown[16];\n    size_t i = 0;\n\n    while (map[i].value < UINT32_MAX) {\n        if (map[i].value == value) {\n            return map[i].name;\n        }\n        i++;\n    }\n\n    snprintf(unknown, sizeof(unknown), \"unknown (%u)\", value);\n    unknown[sizeof(unknown) - 1] = '\\0';\n\n    return unknown;\n}\n"
  },
  {
    "path": "external/libzip/src/zipmerge.c",
    "content": "/*\n  zipmerge.c -- merge zip archives\n  Copyright (C) 2004-2023 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#include <ctype.h>\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"config.h\"\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\n\n#include \"zip.h\"\n\nchar *progname;\n\n#define PROGRAM \"zipmerge\"\n\n#define USAGE \"usage: %s [-DhIikSsV] target-zip zip...\\n\"\n\nchar help_head[] = PROGRAM \" (\" PACKAGE \") by Dieter Baron and Thomas Klausner\\n\\n\";\n\nchar help[] = \"\\n\\\n  -h       display this help message\\n\\\n  -V       display version number\\n\\\n  -D       ignore directory component in file names\\n\\\n  -I       ignore case in file names\\n\\\n  -i       ask before overwriting files\\n\\\n  -k       don't compress when adding uncompressed files\\n\\\n  -S       don't overwrite identical files\\n\\\n  -s       overwrite identical files without asking\\n\\\n\\n\\\nReport bugs to <info@libzip.org>.\\n\";\n\nchar version_string[] = PROGRAM \" (\" PACKAGE \" \" VERSION \")\\n\\\nCopyright (C) 2004-2023 Dieter Baron and Thomas Klausner\\n\\\n\" PACKAGE \" comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\\n\";\n\n#define OPTIONS \"hVDiIksS\"\n\n#define CONFIRM_ALL_YES 0x001\n#define CONFIRM_ALL_NO 0x002\n#define CONFIRM_SAME_YES 0x010\n#define CONFIRM_SAME_NO 0x020\n\nint confirm;\nzip_flags_t name_flags;\nint keep_stored;\n\nstatic int confirm_replace(zip_t *, const char *, zip_uint64_t, zip_t *, const char *, zip_uint64_t);\nstatic void copy_extra_fields(zip_t *destination_archive, zip_uint64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, zip_flags_t flags);\nstatic int copy_file(zip_t *destination_archive, zip_int64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, const char* name);\nstatic zip_t *merge_zip(zip_t *, const char *, const char *);\n\n\nint\nmain(int argc, char *argv[]) {\n    zip_t *za;\n    zip_t **zs;\n    int c, err;\n    unsigned int i, n;\n    char *tname;\n\n    progname = argv[0];\n\n    confirm = CONFIRM_ALL_YES;\n    name_flags = 0;\n    keep_stored = 0;\n\n    while ((c = getopt(argc, argv, OPTIONS)) != -1) {\n        switch (c) {\n        case 'D':\n            name_flags |= ZIP_FL_NODIR;\n            break;\n        case 'I':\n            name_flags |= ZIP_FL_NOCASE;\n            break;\n        case 'i':\n            confirm &= ~CONFIRM_ALL_YES;\n            break;\n        case 'k':\n            keep_stored = 1;\n            break;\n        case 'S':\n            confirm &= ~CONFIRM_SAME_YES;\n            confirm |= CONFIRM_SAME_NO;\n            break;\n        case 's':\n            confirm &= ~CONFIRM_SAME_NO;\n            confirm |= CONFIRM_SAME_YES;\n            break;\n\n        case 'h':\n            fputs(help_head, stdout);\n            printf(USAGE, progname);\n            fputs(help, stdout);\n            exit(0);\n        case 'V':\n            fputs(version_string, stdout);\n            exit(0);\n\n        default:\n            fprintf(stderr, USAGE, progname);\n            exit(2);\n        }\n    }\n\n    if (argc < optind + 2) {\n        fprintf(stderr, USAGE, progname);\n        exit(2);\n    }\n\n    tname = argv[optind++];\n    argv += optind;\n\n    n = (unsigned int)(argc - optind);\n    if ((zs = (zip_t **)malloc(sizeof(zs[0]) * n)) == NULL) {\n        fprintf(stderr, \"%s: out of memory\\n\", progname);\n        exit(1);\n    }\n\n    if ((za = zip_open(tname, ZIP_CREATE, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: can't open zip archive '%s': %s\\n\", progname, tname, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        exit(1);\n    }\n\n    for (i = 0; i < n; i++) {\n        if ((zs[i] = merge_zip(za, tname, argv[i])) == NULL)\n            exit(1);\n    }\n\n    if (zip_close(za) < 0) {\n        fprintf(stderr, \"%s: cannot write zip archive '%s': %s\\n\", progname, tname, zip_strerror(za));\n        exit(1);\n    }\n\n    for (i = 0; i < n; i++)\n        zip_close(zs[i]);\n\n    exit(0);\n}\n\n\nstatic int\nconfirm_replace(zip_t *za, const char *tname, zip_uint64_t it, zip_t *zs, const char *sname, zip_uint64_t is) {\n    char line[1024];\n    struct zip_stat st, ss;\n\n    if (confirm & CONFIRM_ALL_YES)\n        return 1;\n    else if (confirm & CONFIRM_ALL_NO)\n        return 0;\n\n    if (zip_stat_index(za, it, ZIP_FL_UNCHANGED, &st) < 0) {\n        fprintf(stderr, \"%s: cannot stat file %\" PRIu64 \" in '%s': %s\\n\", progname, it, tname, zip_strerror(za));\n        return -1;\n    }\n    if (zip_stat_index(zs, is, 0, &ss) < 0) {\n        fprintf(stderr, \"%s: cannot stat file %\" PRIu64 \" in '%s': %s\\n\", progname, is, sname, zip_strerror(zs));\n        return -1;\n    }\n\n    if (st.size == ss.size && st.crc == ss.crc) {\n        if (confirm & CONFIRM_SAME_YES)\n            return 1;\n        else if (confirm & CONFIRM_SAME_NO)\n            return 0;\n    }\n\n    printf(\"replace '%s' (%\" PRIu64 \" / %08x) in `%s'\\n\"\n           \"   with '%s' (%\" PRIu64 \" / %08x) from `%s'? \",\n           st.name, st.size, st.crc, tname, ss.name, ss.size, ss.crc, sname);\n    fflush(stdout);\n\n    if (fgets(line, sizeof(line), stdin) == NULL) {\n        fprintf(stderr, \"%s: read error from stdin: %s\\n\", progname, strerror(errno));\n        return -1;\n    }\n\n    if (tolower((unsigned char)line[0]) == 'y')\n        return 1;\n\n    return 0;\n}\n\n\nstatic zip_t *\nmerge_zip(zip_t *za, const char *tname, const char *sname) {\n    zip_t *zs;\n    zip_int64_t ret, idx;\n    zip_uint64_t i;\n    int err;\n    const char *fname;\n\n    if ((zs = zip_open(sname, 0, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"%s: can't open zip archive '%s': %s\\n\", progname, sname, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return NULL;\n    }\n\n    ret = zip_get_num_entries(zs, 0);\n    if (ret < 0) {\n        fprintf(stderr, \"%s: cannot get number of entries for '%s': %s\\n\", progname, sname, zip_strerror(za));\n        return NULL;\n    }\n    for (i = 0; i < (zip_uint64_t)ret; i++) {\n        fname = zip_get_name(zs, i, 0);\n\n        if ((idx = zip_name_locate(za, fname, name_flags)) >= 0) {\n            switch (confirm_replace(za, tname, (zip_uint64_t)idx, zs, sname, i)) {\n            case 0:\n                break;\n\n            case 1:\n                if (copy_file(za, idx, zs, i, NULL) < 0) {\n                    fprintf(stderr, \"%s: cannot replace '%s' in `%s': %s\\n\", progname, fname, tname, zip_strerror(za));\n                    zip_close(zs);\n                    return NULL;\n                }\n                break;\n\n            case -1:\n                zip_close(zs);\n                return NULL;\n\n            default:\n                fprintf(stderr,\n                        \"%s: internal error: \"\n                        \"unexpected return code from confirm (%d)\\n\",\n                        progname, err);\n                zip_close(zs);\n                return NULL;\n            }\n        }\n        else {\n            if (copy_file(za, -1, zs, i, fname) < 0) {\n                fprintf(stderr, \"%s: cannot add '%s' to `%s': %s\\n\", progname, fname, tname, zip_strerror(za));\n                zip_close(zs);\n                return NULL;\n            }\n        }\n    }\n\n    return zs;\n}\n\n\nstatic int copy_file(zip_t *destination_archive, zip_int64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, const char* name) {\n    zip_source_t *source = zip_source_zip_file(destination_archive, source_archive, source_index, ZIP_FL_COMPRESSED, 0, -1, NULL);\n\n    if (source == NULL) {\n        return -1;\n    }\n\n    if (destination_index >= 0) {\n        if (zip_file_replace(destination_archive, (zip_uint64_t)destination_index, source, 0) < 0) {\n            zip_source_free(source);\n            return -1;\n        }\n    }\n    else {\n        destination_index = zip_file_add(destination_archive, name, source, 0);\n        if (destination_index < 0) {\n            zip_source_free(source);\n            return -1;\n        }\n    }\n\n    copy_extra_fields(destination_archive, (zip_uint64_t)destination_index, source_archive, source_index, ZIP_FL_CENTRAL);\n    copy_extra_fields(destination_archive, (zip_uint64_t)destination_index, source_archive, source_index, ZIP_FL_LOCAL);\n    if (keep_stored) {\n        zip_stat_t st;\n        if (zip_stat_index(source_archive, source_index, 0, &st) == 0 && (st.valid & ZIP_STAT_COMP_METHOD) && st.comp_method == ZIP_CM_STORE) {\n            zip_set_file_compression(destination_archive, destination_index, ZIP_CM_STORE, 0);\n        }\n    }\n\n    return 0;\n}\n\n\nstatic void copy_extra_fields(zip_t *destination_archive, zip_uint64_t destination_index, zip_t *source_archive, zip_uint64_t source_index, zip_flags_t flags) {\n    zip_int16_t n;\n    zip_uint16_t i, id, length;\n    const zip_uint8_t *data;\n\n    if ((n = zip_file_extra_fields_count(source_archive, source_index, flags)) < 0) {\n        return;\n    }\n\n    for (i = 0; i < n; i++) {\n        if ((data = zip_file_extra_field_get(source_archive, source_index, i, &id, &length, flags)) == NULL) {\n            continue;\n        }\n        zip_file_extra_field_set(destination_archive, destination_index, id, ZIP_EXTRA_FIELD_NEW, data, length, flags);\n    }\n}\n"
  },
  {
    "path": "external/libzip/src/ziptool.c",
    "content": "/*\n  ziptool.c -- tool for modifying zip archive in multiple ways\n  Copyright (C) 2012-2024 Dieter Baron and Thomas Klausner\n\n  This file is part of libzip, a library to manipulate ZIP archives.\n  The authors can be contacted at <info@libzip.org>\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions\n  are met:\n  1. Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n  2. Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n  3. The names of the authors may not be used to endorse or promote\n     products derived from this software without specific prior\n     written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS\n  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"config.h\"\n\n#include \"compat.h\"\n\n#include <errno.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef _WIN32\n/* WIN32 needs <fcntl.h> for _O_BINARY */\n#include <fcntl.h>\n#ifndef STDIN_FILENO\n#define STDIN_FILENO _fileno(stdin)\n#endif\n#endif\n\n#ifndef HAVE_GETOPT\n#include \"getopt.h\"\n#endif\nextern int optopt;\n\n#include \"zip.h\"\n\ntypedef struct dispatch_table_s {\n    const char *cmdline_name;\n    int argument_count;\n    const char *arg_names;\n    const char *description;\n    int (*function)(char *argv[]);\n} dispatch_table_t;\n\nstatic zip_flags_t get_flags(const char *arg);\nstatic zip_int32_t get_compression_method(const char *arg);\nstatic zip_uint16_t get_encryption_method(const char *arg);\nstatic void hexdump(const zip_uint8_t *data, zip_uint16_t len);\nstatic int parse_archive_flag(const char* arg);\nint ziptool_post_close(const char *archive);\nstatic const char* decode_filename(const char* name);\nstatic const char* encode_filename(const char* name);\n\n#ifndef FOR_REGRESS\n#define OPTIONS_REGRESS \"\"\n#define USAGE_REGRESS \"\"\n#endif\n\nzip_t *za, *z_in[16];\nunsigned int z_in_count;\nzip_flags_t stat_flags;\nint hex_encoded_filenames = 0; // Can only be set in ziptool_regress.\n\nstatic int\ncat_impl_backend(zip_uint64_t idx, zip_uint64_t start, zip_uint64_t len, FILE *out) {\n    zip_error_t error;\n    zip_source_t *src;\n    zip_int64_t n;\n    char buf[8192];\n\n    zip_error_init(&error);\n    /* we can't pass 0 as a len to zip_source_zip_create because it\n       will try to give us compressed data */\n    if (len == 0) {\n        struct zip_stat sb;\n\n        if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {\n            fprintf(stderr, \"zip_stat_index failed on '%\" PRIu64 \"' failed: %s\\n\", idx, zip_strerror(za));\n            return -1;\n        }\n\n        if (!(sb.valid & ZIP_STAT_SIZE)) {\n            fprintf(stderr, \"can't cat file at index '%\" PRIu64 \"' with unknown size\\n\", idx);\n            return -1;\n        }\n        len = sb.size;\n    }\n    if ((src = zip_source_zip_file_create(za, idx, 0, start, len, NULL, &error)) == NULL) {\n        fprintf(stderr, \"can't open file at index '%\" PRIu64 \"': %s\\n\", idx, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return -1;\n    }\n    zip_error_fini(&error);\n\n    if (zip_source_open(src) < 0) {\n        fprintf(stderr, \"can't open file at index '%\" PRIu64 \"': %s\\n\", idx, zip_error_strerror(zip_source_error(src)));\n        zip_source_free(src);\n        return -1;\n    }\n    while ((n = zip_source_read(src, buf, sizeof(buf))) > 0) {\n        if (fwrite(buf, (size_t)n, 1, out) != 1) {\n            fprintf(stderr, \"can't write file contents: %s\\n\", strerror(errno));\n            zip_source_free(src);\n            return -1;\n        }\n    }\n    if (n == -1) {\n        fprintf(stderr, \"can't read file at index '%\" PRIu64 \"': %s\\n\", idx, zip_error_strerror(zip_source_error(src)));\n        zip_source_free(src);\n        return -1;\n    }\n    if (zip_source_close(src) < 0) {\n        fprintf(stderr, \"can't close file at index '%\" PRIu64 \"': %s\\n\", idx, zip_error_strerror(zip_source_error(src)));\n        zip_source_free(src);\n        return -1;\n    }\n    zip_source_free(src);\n\n    return 0;\n}\n\nstatic int\ncat_impl(zip_uint64_t idx, zip_uint64_t start, zip_uint64_t len) {\n#ifdef _WIN32\n    /* Need to set stdout to binary mode for Windows */\n    setmode(fileno(stdout), _O_BINARY);\n#endif\n    return cat_impl_backend(idx, start, len, stdout);\n}\n\nstatic int\nadd(char *argv[]) {\n    zip_source_t *zs;\n\n    if ((zs = zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {\n        fprintf(stderr, \"can't create zip_source from buffer: %s\\n\", zip_strerror(za));\n        return -1;\n    }\n\n    if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) {\n        zip_source_free(zs);\n        fprintf(stderr, \"can't add file '%s': %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nadd_dir(char *argv[]) {\n    /* add directory */\n    if (zip_dir_add(za, decode_filename(argv[0]), 0) < 0) {\n        fprintf(stderr, \"can't add directory '%s': %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nadd_file(char *argv[]) {\n    zip_source_t *zs;\n    zip_uint64_t start = strtoull(argv[2], NULL, 10);\n    zip_int64_t len = strtoll(argv[3], NULL, 10);\n\n    if (strcmp(argv[1], \"/dev/stdin\") == 0) {\n        if ((zs = zip_source_filep(za, stdin, start, len)) == NULL) {\n            fprintf(stderr, \"can't create zip_source from stdin: %s\\n\", zip_strerror(za));\n            return -1;\n        }\n    }\n    else {\n        if ((zs = zip_source_file(za, argv[1], start, len)) == NULL) {\n            fprintf(stderr, \"can't create zip_source from file: %s\\n\", zip_strerror(za));\n            return -1;\n        }\n    }\n\n    if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) {\n        zip_source_free(zs);\n        fprintf(stderr, \"can't add file '%s': %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nadd_from_zip(char *argv[]) {\n    zip_uint64_t idx, start;\n    zip_int64_t len;\n    int err;\n    zip_source_t *zs;\n    zip_flags_t flags = 0;\n    /* add from another zip file */\n    idx = strtoull(argv[2], NULL, 10);\n    start = strtoull(argv[3], NULL, 10);\n    len = strtoll(argv[4], NULL, 10);\n    if ((z_in[z_in_count] = zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {\n        zip_error_t error;\n        zip_error_init_with_code(&error, err);\n        fprintf(stderr, \"can't open zip archive '%s': %s\\n\", argv[1], zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return -1;\n    }\n    if (start == 0 && len == -1) {\n        flags = ZIP_FL_COMPRESSED;\n    }\n    if ((zs = zip_source_zip_file(za, z_in[z_in_count], idx, flags, start, len, NULL)) == NULL) {\n        fprintf(stderr, \"error creating file source from '%s' index '%\" PRIu64 \"': %s\\n\", argv[1], idx, zip_strerror(za));\n        zip_close(z_in[z_in_count]);\n        return -1;\n    }\n    if (zip_file_add(za, decode_filename(argv[0]), zs, 0) == -1) {\n        fprintf(stderr, \"can't add file '%s': %s\\n\", argv[0], zip_strerror(za));\n        zip_source_free(zs);\n        zip_close(z_in[z_in_count]);\n        return -1;\n    }\n    z_in_count++;\n    return 0;\n}\n\nstatic int\ncat(char *argv[]) {\n    /* output file contents to stdout */\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n\n    return cat_impl(idx, 0, 0);\n}\n\nstatic int\ncat_partial(char *argv[]) {\n    /* output partial file contents to stdout */\n    zip_uint64_t idx;\n    zip_uint64_t start;\n    zip_uint64_t len;\n\n    idx = strtoull(argv[0], NULL, 10);\n    start = strtoull(argv[1], NULL, 10);\n    len = strtoull(argv[2], NULL, 10);\n\n    return cat_impl(idx, start, len);\n}\n\nstatic int\ncount_extra(char *argv[]) {\n    zip_int16_t count;\n    zip_uint64_t idx;\n    zip_flags_t ceflags = 0;\n    idx = strtoull(argv[0], NULL, 10);\n    ceflags = get_flags(argv[1]);\n    if ((count = zip_file_extra_fields_count(za, idx, ceflags)) < 0) {\n        fprintf(stderr, \"can't get extra field count for file at index '%\" PRIu64 \"': %s\\n\", idx, zip_strerror(za));\n        return -1;\n    }\n    else {\n        printf(\"Extra field count: %d\\n\", count);\n    }\n    return 0;\n}\n\nstatic int\ncount_extra_by_id(char *argv[]) {\n    zip_int16_t count;\n    zip_uint16_t eid;\n    zip_flags_t ceflags = 0;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    ceflags = get_flags(argv[2]);\n    if ((count = zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {\n        fprintf(stderr, \"can't get extra field count for file at index '%\" PRIu64 \"' and for id '%d': %s\\n\", idx, eid, zip_strerror(za));\n        return -1;\n    }\n    else {\n        printf(\"Extra field count: %d\\n\", count);\n    }\n    return 0;\n}\n\nstatic int delete (char *argv[]) {\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    if (zip_delete(za, idx) < 0) {\n        fprintf(stderr, \"can't delete file at index '%\" PRIu64 \"': %s\\n\", idx, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\ndelete_extra(char *argv[]) {\n    zip_flags_t geflags;\n    zip_uint16_t eid;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    geflags = get_flags(argv[2]);\n    if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {\n        fprintf(stderr, \"can't delete extra field data for file at index '%\" PRIu64 \"', extra field id '%d': %s\\n\", idx, eid, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\ndelete_extra_by_id(char *argv[]) {\n    zip_flags_t geflags;\n    zip_uint16_t eid, eidx;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);\n    geflags = get_flags(argv[3]);\n    if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {\n        fprintf(stderr, \"can't delete extra field data for file at index '%\" PRIu64 \"', extra field id '%d', extra field idx '%d': %s\\n\", idx, eid, eidx, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nget_archive_comment(char *argv[]) {\n    const char *comment;\n    int len;\n    /* get archive comment */\n    if ((comment = zip_get_archive_comment(za, &len, 0)) == NULL || len == 0)\n        printf(\"No archive comment\\n\");\n    else\n        printf(\"Archive comment: %.*s\\n\", len, encode_filename(comment));\n    return 0;\n}\n\nstatic int\nget_archive_flag(char *argv[]) {\n    int flag = parse_archive_flag(argv[0]);\n    if (flag < 0) {\n        fprintf(stderr, \"invalid archive flag '%s'\\n\", argv[0]);\n        return -1;\n    }\n\n    printf(\"%d\\n\", zip_get_archive_flag(za, flag, 0));\n    return 0;\n}\n\nstatic int\nget_extra(char *argv[]) {\n    zip_flags_t geflags;\n    zip_uint16_t id, eidx, eflen;\n    const zip_uint8_t *efdata;\n    zip_uint64_t idx;\n    /* get extra field data */\n    idx = strtoull(argv[0], NULL, 10);\n    eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    geflags = get_flags(argv[2]);\n    if ((efdata = zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {\n        fprintf(stderr, \"can't get extra field data for file at index %\" PRIu64 \", extra field %d, flags %u: %s\\n\", idx, eidx, geflags, zip_strerror(za));\n        return -1;\n    }\n    printf(\"Extra field 0x%04x: len %d\", id, eflen);\n    if (eflen > 0) {\n        printf(\", data \");\n        hexdump(efdata, eflen);\n    }\n    printf(\"\\n\");\n    return 0;\n}\n\nstatic int\nget_extra_by_id(char *argv[]) {\n    zip_flags_t geflags;\n    zip_uint16_t eid, eidx, eflen;\n    const zip_uint8_t *efdata;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);\n    geflags = get_flags(argv[3]);\n    if ((efdata = zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {\n        fprintf(stderr, \"can't get extra field data for file at index %\" PRIu64 \", extra field id %d, ef index %d, flags %u: %s\\n\", idx, eid, eidx, geflags, zip_strerror(za));\n        return -1;\n    }\n    printf(\"Extra field 0x%04x: len %d\", eid, eflen);\n    if (eflen > 0) {\n        printf(\", data \");\n        hexdump(efdata, eflen);\n    }\n    printf(\"\\n\");\n    return 0;\n}\n\nstatic int\nget_file_comment(char *argv[]) {\n    const char *comment;\n    zip_uint32_t len;\n    zip_uint64_t idx;\n    /* get file comment */\n    idx = strtoull(argv[0], NULL, 10);\n    if ((comment = zip_file_get_comment(za, idx, &len, 0)) == NULL) {\n        fprintf(stderr, \"can't get comment for '%s': %s\\n\", zip_get_name(za, idx, 0), zip_strerror(za));\n        return -1;\n    }\n    else if (len == 0)\n        printf(\"No comment for '%s'\\n\", zip_get_name(za, idx, 0));\n    else\n        printf(\"File comment for '%s': %.*s\\n\", zip_get_name(za, idx, 0), (int)len, comment);\n    return 0;\n}\n\nstatic int\nget_num_entries(char *argv[]) {\n    zip_int64_t count;\n    zip_flags_t flags;\n    /* get number of entries in archive */\n    flags = get_flags(argv[0]);\n    count = zip_get_num_entries(za, flags);\n    printf(\"%\" PRId64 \" entr%s in archive\\n\", count, count == 1 ? \"y\" : \"ies\");\n    return 0;\n}\n\nstatic int\nname_locate(char *argv[]) {\n    zip_flags_t flags;\n    zip_int64_t idx;\n    flags = get_flags(argv[1]);\n\n    if ((idx = zip_name_locate(za, decode_filename(argv[0]), flags)) < 0) {\n        fprintf(stderr, \"can't find entry with name '%s' using flags '%s'\\n\", argv[0], argv[1]);\n    }\n    else {\n        printf(\"name '%s' using flags '%s' found at index %\" PRId64 \"\\n\", argv[0], argv[1], idx);\n    }\n\n    return 0;\n}\n\nstruct progress_userdata_s {\n    double percentage;\n    double limit;\n};\n\nstruct progress_userdata_s progress_userdata;\n\nstatic void\nprogress_callback(zip_t *archive, double percentage, void *ud) {\n    printf(\"%.1f%% done\\n\", percentage * 100);\n    progress_userdata.percentage = percentage;\n}\n\nstatic int\nprint_progress(char *argv[]) {\n    zip_register_progress_callback_with_state(za, 0.001, progress_callback, NULL, NULL);\n    return 0;\n}\n\nstatic int\nzrename(char *argv[]) {\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    if (zip_file_rename(za, idx, decode_filename(argv[1]), 0) < 0) {\n        fprintf(stderr, \"can't rename file at index '%\" PRIu64 \"' to '%s': %s\\n\", idx, argv[1], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nreplace_file_contents(char *argv[]) {\n    /* replace file contents with data from command line */\n    const char *content;\n    zip_source_t *s;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    content = argv[1];\n    if ((s = zip_source_buffer(za, content, strlen(content), 0)) == NULL || zip_file_replace(za, idx, s, 0) < 0) {\n        zip_source_free(s);\n        fprintf(stderr, \"error replacing file data: %s\\n\", zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_extra(char *argv[]) {\n    zip_flags_t geflags;\n    zip_uint16_t eid, eidx;\n    const zip_uint8_t *efdata;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);\n    geflags = get_flags(argv[3]);\n    efdata = (zip_uint8_t *)argv[4];\n    if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {\n        fprintf(stderr, \"can't set extra field data for file at index '%\" PRIu64 \"', extra field id '%d', index '%d': %s\\n\", idx, eid, eidx, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_archive_comment(char *argv[]) {\n    if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {\n        fprintf(stderr, \"can't set archive comment to '%s': %s\\n\", argv[0], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_archive_flag(char *argv[]) {\n    int flag = parse_archive_flag(argv[0]);\n    if (flag < 0) {\n        fprintf(stderr, \"invalid archive flag '%s'\\n\", argv[0]);\n        return -1;\n    }\n\n    int value = strcasecmp(argv[1], \"1\") == 0 || strcasecmp(argv[1], \"true\") == 0 || strcasecmp(argv[1], \"yes\") == 0;\n\n    if (zip_set_archive_flag(za, flag, value) < 0) {\n        fprintf(stderr, \"can't set archive flag '%s' to %d: %s\\n\", argv[0], value, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\n\nstatic int\nset_file_comment(char *argv[]) {\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {\n        fprintf(stderr, \"can't set file comment at index '%\" PRIu64 \"' to '%s': %s\\n\", idx, argv[1], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_file_compression(char *argv[]) {\n    zip_int32_t method;\n    zip_uint32_t flags;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    method = get_compression_method(argv[1]);\n    flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);\n    if (zip_set_file_compression(za, idx, method, flags) < 0) {\n        fprintf(stderr, \"can't set file compression method at index '%\" PRIu64 \"' to '%s', flags '%\" PRIu32 \"': %s\\n\", idx, argv[1], flags, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_file_encryption(char *argv[]) {\n    zip_uint16_t method;\n    zip_uint64_t idx;\n    char *password;\n    idx = strtoull(argv[0], NULL, 10);\n    method = get_encryption_method(argv[1]);\n    password = argv[2];\n    if (strlen(password) == 0) {\n        password = NULL;\n    }\n    if (zip_file_set_encryption(za, idx, method, password) < 0) {\n        fprintf(stderr, \"can't set file encryption method at index '%\" PRIu64 \"' to '%s': %s\\n\", idx, argv[1], zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_file_dostime(char *argv[]) {\n    /* set file last modification time (mtime) directly */\n    zip_uint16_t dostime, dosdate;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    dostime = (zip_uint16_t)strtoull(argv[1], NULL, 10);\n    dosdate = (zip_uint16_t)strtoull(argv[2], NULL, 10);\n    if (zip_file_set_dostime(za, idx, dostime, dosdate, 0) < 0) {\n        fprintf(stderr, \"can't set file dostime at index '%\" PRIu64 \"' to '%d'/'%d': %s\\n\", idx, (int)dostime, (int)dosdate, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_file_mtime(char *argv[]) {\n    /* set file last modification time (mtime) */\n    time_t mtime;\n    zip_uint64_t idx;\n    idx = strtoull(argv[0], NULL, 10);\n    mtime = (time_t)strtoull(argv[1], NULL, 10);\n    if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {\n        fprintf(stderr, \"can't set file mtime at index '%\" PRIu64 \"' to '%lld': %s\\n\", idx, (long long)mtime, zip_strerror(za));\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nset_file_mtime_all(char *argv[]) {\n    /* set last modification time (mtime) for all files */\n    time_t mtime;\n    zip_int64_t num_entries;\n    zip_uint64_t idx;\n    mtime = (time_t)strtoull(argv[0], NULL, 10);\n\n    if ((num_entries = zip_get_num_entries(za, 0)) < 0) {\n        fprintf(stderr, \"can't get number of entries: %s\\n\", zip_strerror(za));\n        return -1;\n    }\n    for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {\n        if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {\n            fprintf(stderr, \"can't set file mtime at index '%\" PRIu64 \"' to '%lld': %s\\n\", idx, (long long)mtime, zip_strerror(za));\n            return -1;\n        }\n    }\n    return 0;\n}\n\nstatic int\nset_password(char *argv[]) {\n    /* set default password */\n    if (zip_set_default_password(za, argv[0]) < 0) {\n        fprintf(stderr, \"can't set default password to '%s'\\n\", argv[0]);\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nzstat(char *argv[]) {\n    zip_uint64_t idx;\n    char buf[100];\n    struct zip_stat sb;\n    idx = strtoull(argv[0], NULL, 10);\n\n    if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {\n        fprintf(stderr, \"zip_stat_index failed on '%\" PRIu64 \"' failed: %s\\n\", idx, zip_strerror(za));\n        return -1;\n    }\n\n    if (sb.valid & ZIP_STAT_NAME)\n        printf(\"name: '%s'\\n\", encode_filename(sb.name));\n    if (sb.valid & ZIP_STAT_INDEX)\n        printf(\"index: '%\" PRIu64 \"'\\n\", sb.index);\n    if (sb.valid & ZIP_STAT_SIZE)\n        printf(\"size: '%\" PRIu64 \"'\\n\", sb.size);\n    if (sb.valid & ZIP_STAT_COMP_SIZE)\n        printf(\"compressed size: '%\" PRIu64 \"'\\n\", sb.comp_size);\n    if (sb.valid & ZIP_STAT_MTIME) {\n        struct tm *tpm;\n        struct tm tm;\n        tpm = zip_localtime(&sb.mtime, &tm);\n        if (tpm == NULL) {\n            printf(\"mtime: <not valid>\\n\");\n        }\n        else {\n            strftime(buf, sizeof(buf), \"%a %b %d %Y %H:%M:%S\", tpm);\n            printf(\"mtime: '%s'\\n\", buf);\n        }\n    }\n    if (sb.valid & ZIP_STAT_CRC)\n        printf(\"crc: '%0x'\\n\", sb.crc);\n    if (sb.valid & ZIP_STAT_COMP_METHOD)\n        printf(\"compression method: '%d'\\n\", sb.comp_method);\n    if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)\n        printf(\"encryption method: '%d'\\n\", sb.encryption_method);\n    if (sb.valid & ZIP_STAT_FLAGS)\n        printf(\"flags: '%ld'\\n\", (long)sb.flags);\n    printf(\"\\n\");\n\n    return 0;\n}\n\nstatic int parse_archive_flag(const char* arg) {\n    if (strcasecmp(arg, \"rdonly\") == 0) {\n        return ZIP_AFL_RDONLY;\n    }\n    else if (strcasecmp(arg, \"is-torrentzip\") == 0) {\n        return ZIP_AFL_IS_TORRENTZIP;\n    }\n    else if (strcasecmp(arg, \"want-torrentzip\") == 0) {\n        return ZIP_AFL_WANT_TORRENTZIP;\n    }\n    else if (strcasecmp(arg, \"create-or-keep-file-for-empty-archive\") == 0) {\n        return ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE;\n    }\n    return -1;\n}\n\nstatic zip_flags_t\nget_flags(const char *arg) {\n    zip_flags_t flags = 0;\n    if (strchr(arg, 'C') != NULL)\n        flags |= ZIP_FL_NOCASE;\n    if (strchr(arg, 'c') != NULL)\n        flags |= ZIP_FL_CENTRAL;\n    if (strchr(arg, 'd') != NULL)\n        flags |= ZIP_FL_NODIR;\n    if (strchr(arg, 'l') != NULL)\n        flags |= ZIP_FL_LOCAL;\n    if (strchr(arg, 'u') != NULL)\n        flags |= ZIP_FL_UNCHANGED;\n    if (strchr(arg, '8') != NULL)\n        flags |= ZIP_FL_ENC_UTF_8;\n    if (strchr(arg, '4') != NULL)\n        flags |= ZIP_FL_ENC_CP437;\n    if (strchr(arg, 'r') != NULL)\n        flags |= ZIP_FL_ENC_RAW;\n    if (strchr(arg, 's') != NULL)\n        flags |= ZIP_FL_ENC_STRICT;\n    return flags;\n}\n\nstatic zip_int32_t\nget_compression_method(const char *arg) {\n    if (strcasecmp(arg, \"default\") == 0)\n        return ZIP_CM_DEFAULT;\n    else if (strcasecmp(arg, \"store\") == 0)\n        return ZIP_CM_STORE;\n    else if (strcasecmp(arg, \"deflate\") == 0)\n        return ZIP_CM_DEFLATE;\n#if defined(HAVE_LIBBZ2)\n    else if (strcasecmp(arg, \"bzip2\") == 0)\n        return ZIP_CM_BZIP2;\n#endif\n#if defined(HAVE_LIBLZMA)\n    /*  Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2\n        archives made this way - and vice versa.\n\n        else if (strcasecmp(arg, \"lzma2\") == 0)\n          return ZIP_CM_LZMA2;\n    */\n    else if (strcasecmp(arg, \"lzma\") == 0)\n\treturn ZIP_CM_LZMA;\n    else if (strcasecmp(arg, \"xz\") == 0)\n        return ZIP_CM_XZ;\n#endif\n#if defined(HAVE_LIBZSTD)\n    else if (strcasecmp(arg, \"zstd\") == 0)\n        return ZIP_CM_ZSTD;\n\n#endif\n    else if (strcasecmp(arg, \"unknown\") == 0)\n        return 100;\n    return 0; /* TODO: error handling */\n}\n\nstatic zip_uint16_t\nget_encryption_method(const char *arg) {\n    if (strcasecmp(arg, \"none\") == 0)\n        return ZIP_EM_NONE;\n    else if (strcasecmp(arg, \"PKWARE\") == 0)\n        return ZIP_EM_TRAD_PKWARE;\n    else if (strcasecmp(arg, \"AES-128\") == 0)\n        return ZIP_EM_AES_128;\n    else if (strcasecmp(arg, \"AES-192\") == 0)\n        return ZIP_EM_AES_192;\n    else if (strcasecmp(arg, \"AES-256\") == 0)\n        return ZIP_EM_AES_256;\n    else if (strcasecmp(arg, \"unknown\") == 0)\n        return 100;\n    return (zip_uint16_t)-1; /* TODO: error handling */\n}\n\nstatic void\nhexdump(const zip_uint8_t *data, zip_uint16_t len) {\n    zip_uint16_t i;\n\n    if (len <= 0)\n        return;\n\n    printf(\"0x\");\n\n    for (i = 0; i < len; i++)\n        printf(\"%02x\", data[i]);\n}\n\n\nstatic zip_t *\nread_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length) {\n    zip_t *zaa;\n    zip_source_t *source;\n    int err;\n\n    if (offset == 0 && length == 0) {\n        if (strcmp(archive, \"/dev/stdin\") == 0) {\n            zaa = zip_fdopen(STDIN_FILENO, flags & ~ZIP_CREATE, &err);\n        }\n        else {\n            zaa = zip_open(archive, flags, &err);\n        }\n        if (zaa == NULL) {\n            zip_error_set(error, err, errno);\n            return NULL;\n        }\n    }\n    else {\n        if (length > ZIP_INT64_MAX) {\n            zip_error_set(error, ZIP_ER_INVAL, 0);\n            return NULL;\n        }\n        if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL || (zaa = zip_open_from_source(source, flags, error)) == NULL) {\n            zip_source_free(source);\n            return NULL;\n        }\n    }\n\n    return zaa;\n}\n\ndispatch_table_t dispatch_table[] = {{\"add\", 2, \"name content\", \"add file called name using content\", add},\n                                     {\"add_dir\", 1, \"name\", \"add directory\", add_dir},\n                                     {\"add_file\", 4, \"name file_to_add offset len\", \"add file to archive, len bytes starting from offset\", add_file},\n                                     {\"add_from_zip\", 5, \"name archivename index offset len\", \"add file from another archive, len bytes starting from offset\", add_from_zip},\n                                     {\"cat\", 1, \"index\", \"output file contents to stdout\", cat},\n                                     {\"cat_partial\", 3, \"index start length\", \"output partial file contents to stdout\", cat_partial},\n                                     {\"count_extra\", 2, \"index flags\", \"show number of extra fields for archive entry\", count_extra},\n                                     {\"count_extra_by_id\", 3, \"index extra_id flags\", \"show number of extra fields of type extra_id for archive entry\", count_extra_by_id},\n                                     {\"delete\", 1, \"index\", \"remove entry\", delete},\n                                     {\"delete_extra\", 3, \"index extra_idx flags\", \"remove extra field\", delete_extra},\n                                     {\"delete_extra_by_id\", 4, \"index extra_id extra_index flags\", \"remove extra field of type extra_id\", delete_extra_by_id},\n                                     {\"get_archive_comment\", 0, \"\", \"show archive comment\", get_archive_comment},\n                                     {\"get_archive_flag\", 1, \"flag\", \"show archive flag\", get_archive_flag},\n                                     {\"get_extra\", 3, \"index extra_index flags\", \"show extra field\", get_extra},\n                                     {\"get_extra_by_id\", 4, \"index extra_id extra_index flags\", \"show extra field of type extra_id\", get_extra_by_id},\n                                     {\"get_file_comment\", 1, \"index\", \"get file comment\", get_file_comment},\n                                     {\"get_num_entries\", 1, \"flags\", \"get number of entries in archive\", get_num_entries},\n                                     {\"name_locate\", 2, \"name flags\", \"find entry in archive\", name_locate},\n                                     {\"print_progress\", 0, \"\", \"print progress during zip_close()\", print_progress},\n                                     {\"rename\", 2, \"index name\", \"rename entry\", zrename},\n                                     {\"replace_file_contents\", 2, \"index data\", \"replace entry with data\", replace_file_contents},\n                                     {\"set_archive_comment\", 1, \"comment\", \"set archive comment\", set_archive_comment},\n                                     {\"set_archive_flag\", 2, \"flag\", \"set archive flag\", set_archive_flag},\n                                     {\"set_extra\", 5, \"index extra_id extra_index flags value\", \"set extra field\", set_extra},\n                                     {\"set_file_comment\", 2, \"index comment\", \"set file comment\", set_file_comment},\n                                     {\"set_file_compression\", 3, \"index method compression_flags\", \"set file compression method\", set_file_compression},\n                                     {\"set_file_dostime\", 3, \"index time date\", \"set file modification time and date (DOS format)\", set_file_dostime},\n                                     {\"set_file_encryption\", 3, \"index method password\", \"set file encryption method\", set_file_encryption},\n                                     {\"set_file_mtime\", 2, \"index timestamp\", \"set file modification time\", set_file_mtime},\n                                     {\"set_file_mtime_all\", 1, \"timestamp\", \"set file modification time for all files\", set_file_mtime_all},\n                                     {\"set_password\", 1, \"password\", \"set default password for encryption\", set_password},\n                                     {\"stat\", 1, \"index\", \"print information about entry\", zstat}\n#ifdef DISPATCH_REGRESS\n                                     ,\n                                     DISPATCH_REGRESS\n#endif\n};\n\nstatic int\ndispatch(int argc, char *argv[]) {\n    unsigned int i;\n    for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) {\n        if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {\n            argc--;\n            argv++;\n            /* 1 for the command, argument_count for the arguments */\n            if (argc < dispatch_table[i].argument_count) {\n                fprintf(stderr, \"not enough arguments for command '%s': %d available, %d needed\\n\", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);\n                return -1;\n            }\n            if (dispatch_table[i].function(argv) == 0)\n                return 1 + dispatch_table[i].argument_count;\n            return -1;\n        }\n    }\n\n    fprintf(stderr, \"unknown command '%s'\\n\", argv[0]);\n    return -1;\n}\n\n\nstatic void\nusage(const char *progname, const char *reason) {\n    unsigned int i;\n    FILE *out;\n    if (reason == NULL)\n        out = stdout;\n    else\n        out = stderr;\n    fprintf(out, \"usage: %s [-ceghnrst]\" USAGE_REGRESS \" [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\\n\", progname);\n    if (reason != NULL) {\n        fprintf(out, \"%s\\n\", reason);\n        exit(1);\n    }\n\n    fprintf(out, \"\\nSupported options are:\\n\"\n                 \"\\t-c\\t\\tcheck consistency\\n\"\n                 \"\\t-e\\t\\terror if archive already exists (only useful with -n)\\n\"\n#ifdef FOR_REGRESS\n                 \"\\t-F size\\t\\tfragment size for in memory archive\\n\"\n#endif\n                 \"\\t-g\\t\\tguess file name encoding (for stat)\\n\"\n#ifdef FOR_REGRESS\n                 \"\\t-H\\t\\twrite files with holes compactly\\n\"\n#endif\n                 \"\\t-h\\t\\tdisplay this usage\\n\"\n                 \"\\t-l len\\t\\tonly use len bytes of file\\n\"\n#ifdef FOR_REGRESS\n                 \"\\t-m\\t\\tread archive into memory, and modify there; write out at end\\n\"\n#endif\n                 \"\\t-n\\t\\tcreate archive if it doesn't exist\\n\"\n                 \"\\t-o offset\\tstart reading file at offset\\n\"\n                 \"\\t-r\\t\\tprint raw file name encoding without translation (for stat)\\n\"\n                 \"\\t-s\\t\\tfollow file name convention strictly (for stat)\\n\"\n                 \"\\t-t\\t\\tdisregard current archive contents, if any\\n\");\n    fprintf(out, \"\\nSupported commands and arguments are:\\n\");\n    for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) {\n        fprintf(out, \"\\t%s %s\\n\\t    %s\\n\\n\", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);\n    }\n    fprintf(out, \"\\nSupported flags are:\\n\"\n                 \"\\t0\\t(no flags)\\n\"\n                 \"\\t4\\tZIP_FL_ENC_CP437\\n\"\n                 \"\\t8\\tZIP_FL_ENC_UTF_8\\n\"\n                 \"\\tC\\tZIP_FL_NOCASE\\n\"\n                 \"\\tc\\tZIP_FL_CENTRAL\\n\"\n                 \"\\td\\tZIP_FL_NODIR\\n\"\n                 \"\\tl\\tZIP_FL_LOCAL\\n\"\n                 \"\\tr\\tZIP_FL_ENC_RAW\\n\"\n                 \"\\ts\\tZIP_FL_ENC_STRICT\\n\"\n                 \"\\tu\\tZIP_FL_UNCHANGED\\n\");\n    fprintf(out, \"\\nSupported archive flags are:\\n\"\n\t         \"\\tcreate-or-keep-empty-file-for-archive\\n\"\n\t         \"\\tis-torrentzip\\n\"\n\t         \"\\trdonly\\n\"\n\t         \"\\twant-torrentzip\\n\");\n    fprintf(out, \"\\nSupported compression methods are:\\n\"\n                 \"\\tdefault\\n\");\n    if (zip_compression_method_supported(ZIP_CM_BZIP2, 1)) {\n        fprintf(out, \"\\tbzip2\\n\");\n    }\n    fprintf(out, \"\\tdeflate\\n\"\n                 \"\\tstore\\n\");\n    if (zip_compression_method_supported(ZIP_CM_XZ, 1)) {\n        fprintf(out, \"\\txz\\n\");\n    }\n    if (zip_compression_method_supported(ZIP_CM_ZSTD, 1)) {\n        fprintf(out, \"\\tzstd\\n\");\n    }\n    fprintf(out, \"\\nSupported encryption methods are:\\n\"\n                 \"\\tnone\\n\");\n    if (zip_encryption_method_supported(ZIP_EM_AES_128, 1)) {\n        fprintf(out, \"\\tAES-128\\n\");\n    }\n    if (zip_encryption_method_supported(ZIP_EM_AES_192, 1)) {\n        fprintf(out, \"\\tAES-192\\n\");\n    }\n    if (zip_encryption_method_supported(ZIP_EM_AES_256, 1)) {\n        fprintf(out, \"\\tAES-256\\n\");\n    }\n    fprintf(out, \"\\tPKWARE\\n\");\n    fprintf(out, \"\\nThe index is zero-based.\\n\");\n    exit(0);\n}\n\n#ifndef FOR_REGRESS\n#define ziptool_open read_from_file\nint\nziptool_post_close(const char *archive) {\n    return 0;\n}\n#endif\n\nint\nmain(int argc, char *argv[]) {\n    const char *archive;\n    unsigned int i;\n    int c, arg, err, flags;\n    const char *prg;\n    zip_uint64_t len = 0, offset = 0;\n    zip_error_t error;\n\n    flags = 0;\n    prg = argv[0];\n\n    while ((c = getopt(argc, argv, \"ceghl:no:rst\" OPTIONS_REGRESS)) != -1) {\n        switch (c) {\n        case 'c':\n            flags |= ZIP_CHECKCONS;\n            break;\n        case 'e':\n            flags |= ZIP_EXCL;\n            break;\n        case 'g':\n            stat_flags = ZIP_FL_ENC_GUESS;\n            break;\n        case 'h':\n            usage(prg, NULL);\n            break;\n        case 'l':\n            len = strtoull(optarg, NULL, 10);\n            break;\n        case 'n':\n            flags |= ZIP_CREATE;\n            break;\n        case 'o':\n            offset = strtoull(optarg, NULL, 10);\n            break;\n        case 'r':\n            stat_flags = ZIP_FL_ENC_RAW;\n            break;\n        case 's':\n            stat_flags = ZIP_FL_ENC_STRICT;\n            break;\n        case 't':\n            flags |= ZIP_TRUNCATE;\n            break;\n#ifdef GETOPT_REGRESS\n            GETOPT_REGRESS\n#endif\n\n        default: {\n            char reason[128];\n            snprintf(reason, sizeof(reason), \"invalid option -%c\", optopt);\n            usage(prg, reason);\n        }\n        }\n    }\n\n    if (optind >= argc - 1)\n        usage(prg, \"too few arguments\");\n\n    arg = optind;\n\n    archive = argv[arg++];\n\n    if (flags == 0)\n        flags = ZIP_CREATE;\n\n    zip_error_init(&error);\n    za = ziptool_open(archive, flags, &error, offset, len);\n    if (za == NULL) {\n        fprintf(stderr, \"can't open zip archive '%s': %s\\n\", archive, zip_error_strerror(&error));\n        zip_error_fini(&error);\n        return 1;\n    }\n    zip_error_fini(&error);\n\n#ifdef REGRESS_PREPARE_ARGS\n    REGRESS_PREPARE_ARGS\n#endif\n\n    err = 0;\n    while (arg < argc) {\n        int ret;\n        ret = dispatch(argc - arg, argv + arg);\n        if (ret > 0) {\n            arg += ret;\n        }\n        else {\n            err = 1;\n            break;\n        }\n    }\n\n#ifdef PRECLOSE_REGRESS\n    PRECLOSE_REGRESS;\n#endif\n\n    if (zip_close(za) == -1) {\n        fprintf(stderr, \"can't close zip archive '%s': %s\\n\", archive, zip_strerror(za));\n        return 1;\n    }\n    if (ziptool_post_close(archive) < 0) {\n        err = 1;\n    }\n\n    for (i = 0; i < z_in_count; i++) {\n        if (zip_close(z_in[i]) < 0) {\n            err = 1;\n        }\n    }\n\n    return err;\n}\n\n#define BIN2HEX(n) ((n) >= 10 ? (n) + 'a' - 10 : (n) + '0')\n#define HEX2BIN(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' : ((c) >= 'A' && (c) <= 'F') ? (c) - 'A' + 10 : (c) - 'a' + 10)\n\n#define FILENAME_BUFFER_LENGTH (2 * 64 * 1024)\nstatic char filename_buffer[FILENAME_BUFFER_LENGTH + 1];\n\nstatic const char* encode_filename(const char* name) {\n    char *t = filename_buffer;\n\n    if (!hex_encoded_filenames) {\n        const char* s = name;\n        if (strlen(name) > FILENAME_BUFFER_LENGTH) {\n            fprintf(stderr, \"internal buffer limit reached, increase buffer size\\n\");\n            exit(1);\n        }\n        while (*s != '\\0') {\n            if (s[0] == '\\r' && s[1] == '\\n') {\n                s++;\n                continue;\n            }\n            *(t++) = *(s++);\n        }\n    }\n    else {\n        const unsigned char *s = (const unsigned char *)name;\n        if (strlen(name) > FILENAME_BUFFER_LENGTH / 2) {\n            fprintf(stderr, \"internal buffer limit reached, increase buffer size\\n\");\n            exit(1);\n        }\n        while (*s != '\\0') {\n            *(t++) = BIN2HEX(*s >> 4);\n            *(t++) = BIN2HEX(*s & 0xf);\n            s += 1;\n        }\n    }\n    *t = '\\0';\n    return filename_buffer;\n}\n\nstatic const char* decode_filename(const char* name) {\n    if (!hex_encoded_filenames) {\n        return name;\n    }\n\n    if (strlen(name) > FILENAME_BUFFER_LENGTH * 2) {\n        fprintf(stderr, \"internal buffer limit reached, increase buffer size\\n\");\n        exit(1);\n    }\n    // TODO: check that strlen(name) % 2 == 0\n    // TODO: check with strspn that s is all hex digits\n\n    unsigned char *t = (unsigned char*)filename_buffer;\n    const char *s = name;\n    while (*s != '\\0') {\n        *(t++) = (HEX2BIN(s[0]) << 4) | HEX2BIN(s[1]);\n        s += 2;\n    }\n    *t = '\\0';\n\n    return filename_buffer;\n}\n"
  },
  {
    "path": "external/libzip/vcpkg.json",
    "content": "{\n  \"dependencies\": [\n    \"bzip2\",\n    \"liblzma\",\n    \"zlib\",\n    \"zstd\"\n  ]\n}\n"
  },
  {
    "path": "external/libzip/zipconf.h.in",
    "content": "#ifndef _HAD_ZIPCONF_H\n#define _HAD_ZIPCONF_H\n\n/*\n   zipconf.h -- platform specific include file\n\n   This file was generated automatically by CMake\n   based on ../cmake-zipconf.h.in.\n */\n\n#define LIBZIP_VERSION \"${libzip_VERSION}\"\n#define LIBZIP_VERSION_MAJOR ${libzip_VERSION_MAJOR}\n#define LIBZIP_VERSION_MINOR ${libzip_VERSION_MINOR}\n#define LIBZIP_VERSION_MICRO ${libzip_VERSION_PATCH}\n\n#cmakedefine ZIP_STATIC\n\n${LIBZIP_TYPES_INCLUDE}\n\ntypedef ${ZIP_INT8_T} zip_int8_t;\ntypedef ${ZIP_UINT8_T} zip_uint8_t;\ntypedef ${ZIP_INT16_T} zip_int16_t;\ntypedef ${ZIP_UINT16_T} zip_uint16_t;\ntypedef ${ZIP_INT32_T} zip_int32_t;\ntypedef ${ZIP_UINT32_T} zip_uint32_t;\ntypedef ${ZIP_INT64_T} zip_int64_t;\ntypedef ${ZIP_UINT64_T} zip_uint64_t;\n\n#define ZIP_INT8_MIN\t (-ZIP_INT8_MAX-1)\n#define ZIP_INT8_MAX\t 0x7f\n#define ZIP_UINT8_MAX\t 0xff\n\n#define ZIP_INT16_MIN\t (-ZIP_INT16_MAX-1)\n#define ZIP_INT16_MAX\t 0x7fff\n#define ZIP_UINT16_MAX\t 0xffff\n\n#define ZIP_INT32_MIN\t (-ZIP_INT32_MAX-1L)\n#define ZIP_INT32_MAX\t 0x7fffffffL\n#define ZIP_UINT32_MAX\t 0xffffffffLU\n\n#define ZIP_INT64_MIN\t (-ZIP_INT64_MAX-1LL)\n#define ZIP_INT64_MAX\t 0x7fffffffffffffffLL\n#define ZIP_UINT64_MAX\t 0xffffffffffffffffULL\n\n#endif /* zipconf.h */\n"
  },
  {
    "path": "external/pdfium/README.md",
    "content": "# PDFium prebuilts\n\nThis folder is populated by `app/scripts/vendor_doc_deps.sh` or `app/scripts/vendor_doc_deps.ps1`.\nExpected layout:\n\n- linux-x64/\n- windows-x64/\n- macos-arm64/\n- macos-x64/\n\nEach folder should contain `include/` and the platform PDFium library under `lib/`:\n\n- Linux: `lib/libpdfium.so`\n- Windows: `bin/pdfium.dll` + `lib/pdfium.dll.lib`\n- macOS: `lib/libpdfium.dylib` (arm64 or x64)\n"
  },
  {
    "path": "external/pdfium/linux-x64/LICENSE",
    "content": "Copyright 2014-2025 Benoit Blanchon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nThis package also includes third-party software. See the licenses/ directory for their respective licenses.\n"
  },
  {
    "path": "external/pdfium/linux-x64/PDFiumConfig.cmake",
    "content": "# PDFium Package Configuration for CMake\n#\n# To use PDFium in your CMake project:\n#\n#   1. set the environment variable PDFium_DIR to the folder containing this file.\n#   2. in your CMakeLists.txt, add\n#       find_package(PDFium)\n#   3. then link your executable with PDFium\n#       target_link_libraries(my_exe pdfium)\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_path(PDFium_INCLUDE_DIR\n    NAMES \"fpdfview.h\"\n    PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n    PATH_SUFFIXES \"include\"\n)\n\nset(PDFium_VERSION \"147.0.7713.0\")\n\nif(WIN32)\n  find_file(PDFium_LIBRARY\n        NAMES \"pdfium.dll\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"bin\")\n\n  find_file(PDFium_IMPLIB\n        NAMES \"pdfium.dll.lib\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    IMPORTED_IMPLIB               \"${PDFium_IMPLIB}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nelse()\n  find_library(PDFium_LIBRARY\n        NAMES \"pdfium\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nendif()\n"
  },
  {
    "path": "external/pdfium/linux-x64/VERSION",
    "content": "MAJOR=147\nMINOR=0\nBUILD=7713\nPATCH=0\n"
  },
  {
    "path": "external/pdfium/linux-x64/args.gn",
    "content": "clang_use_chrome_plugins = false\nis_component_build = false\nis_debug = false\npdf_enable_v8 = false\npdf_enable_xfa = false\npdf_is_standalone = true\npdf_use_partition_alloc = false\ntarget_cpu = \"x64\"\ntarget_os = \"linux\"\ntreat_warnings_as_errors = false\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/cpp/fpdf_deleters.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_DELETERS_H_\n#define PUBLIC_CPP_FPDF_DELETERS_H_\n\n#include \"../fpdf_annot.h\"\n#include \"../fpdf_dataavail.h\"\n#include \"../fpdf_edit.h\"\n#include \"../fpdf_formfill.h\"\n#include \"../fpdf_javascript.h\"\n#include \"../fpdf_structtree.h\"\n#include \"../fpdf_text.h\"\n#include \"../fpdf_transformpage.h\"\n#include \"../fpdfview.h\"\n\n// Custom deleters for using FPDF_* types with std::unique_ptr<>.\n\nstruct FPDFAnnotationDeleter {\n  inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); }\n};\n\nstruct FPDFAvailDeleter {\n  inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); }\n};\n\nstruct FPDFBitmapDeleter {\n  inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); }\n};\n\nstruct FPDFClipPathDeleter {\n  inline void operator()(FPDF_CLIPPATH clip_path) {\n    FPDF_DestroyClipPath(clip_path);\n  }\n};\n\nstruct FPDFDocumentDeleter {\n  inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); }\n};\n\nstruct FPDFFontDeleter {\n  inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); }\n};\n\nstruct FPDFFormHandleDeleter {\n  inline void operator()(FPDF_FORMHANDLE form) {\n    FPDFDOC_ExitFormFillEnvironment(form);\n  }\n};\n\nstruct FPDFJavaScriptActionDeleter {\n  inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) {\n    FPDFDoc_CloseJavaScriptAction(javascript);\n  }\n};\n\nstruct FPDFPageDeleter {\n  inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); }\n};\n\nstruct FPDFPageLinkDeleter {\n  inline void operator()(FPDF_PAGELINK pagelink) {\n    FPDFLink_CloseWebLinks(pagelink);\n  }\n};\n\nstruct FPDFPageObjectDeleter {\n  inline void operator()(FPDF_PAGEOBJECT object) {\n    FPDFPageObj_Destroy(object);\n  }\n};\n\nstruct FPDFStructTreeDeleter {\n  inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); }\n};\n\nstruct FPDFTextFindDeleter {\n  inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); }\n};\n\nstruct FPDFTextPageDeleter {\n  inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); }\n};\n\n#endif  // PUBLIC_CPP_FPDF_DELETERS_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/cpp/fpdf_scopers.h",
    "content": "// Copyright 2018 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_SCOPERS_H_\n#define PUBLIC_CPP_FPDF_SCOPERS_H_\n\n#include <memory>\n#include <type_traits>\n\n#include \"fpdf_deleters.h\"\n\n// Versions of FPDF types that clean up the object at scope exit.\n\nusing ScopedFPDFAnnotation =\n    std::unique_ptr<std::remove_pointer<FPDF_ANNOTATION>::type,\n                    FPDFAnnotationDeleter>;\n\nusing ScopedFPDFAvail =\n    std::unique_ptr<std::remove_pointer<FPDF_AVAIL>::type, FPDFAvailDeleter>;\n\nusing ScopedFPDFBitmap =\n    std::unique_ptr<std::remove_pointer<FPDF_BITMAP>::type, FPDFBitmapDeleter>;\n\nusing ScopedFPDFClipPath =\n    std::unique_ptr<std::remove_pointer<FPDF_CLIPPATH>::type,\n                    FPDFClipPathDeleter>;\n\nusing ScopedFPDFDocument =\n    std::unique_ptr<std::remove_pointer<FPDF_DOCUMENT>::type,\n                    FPDFDocumentDeleter>;\n\nusing ScopedFPDFFont =\n    std::unique_ptr<std::remove_pointer<FPDF_FONT>::type, FPDFFontDeleter>;\n\nusing ScopedFPDFFormHandle =\n    std::unique_ptr<std::remove_pointer<FPDF_FORMHANDLE>::type,\n                    FPDFFormHandleDeleter>;\n\nusing ScopedFPDFJavaScriptAction =\n    std::unique_ptr<std::remove_pointer<FPDF_JAVASCRIPT_ACTION>::type,\n                    FPDFJavaScriptActionDeleter>;\n\nusing ScopedFPDFPage =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGE>::type, FPDFPageDeleter>;\n\nusing ScopedFPDFPageLink =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGELINK>::type,\n                    FPDFPageLinkDeleter>;\n\nusing ScopedFPDFPageObject =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGEOBJECT>::type,\n                    FPDFPageObjectDeleter>;\n\nusing ScopedFPDFStructTree =\n    std::unique_ptr<std::remove_pointer<FPDF_STRUCTTREE>::type,\n                    FPDFStructTreeDeleter>;\n\nusing ScopedFPDFTextFind =\n    std::unique_ptr<std::remove_pointer<FPDF_SCHHANDLE>::type,\n                    FPDFTextFindDeleter>;\n\nusing ScopedFPDFTextPage =\n    std::unique_ptr<std::remove_pointer<FPDF_TEXTPAGE>::type,\n                    FPDFTextPageDeleter>;\n\n#endif  // PUBLIC_CPP_FPDF_SCOPERS_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_annot.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ANNOT_H_\n#define PUBLIC_FPDF_ANNOT_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdf_formfill.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n#define FPDF_ANNOT_UNKNOWN 0\n#define FPDF_ANNOT_TEXT 1\n#define FPDF_ANNOT_LINK 2\n#define FPDF_ANNOT_FREETEXT 3\n#define FPDF_ANNOT_LINE 4\n#define FPDF_ANNOT_SQUARE 5\n#define FPDF_ANNOT_CIRCLE 6\n#define FPDF_ANNOT_POLYGON 7\n#define FPDF_ANNOT_POLYLINE 8\n#define FPDF_ANNOT_HIGHLIGHT 9\n#define FPDF_ANNOT_UNDERLINE 10\n#define FPDF_ANNOT_SQUIGGLY 11\n#define FPDF_ANNOT_STRIKEOUT 12\n#define FPDF_ANNOT_STAMP 13\n#define FPDF_ANNOT_CARET 14\n#define FPDF_ANNOT_INK 15\n#define FPDF_ANNOT_POPUP 16\n#define FPDF_ANNOT_FILEATTACHMENT 17\n#define FPDF_ANNOT_SOUND 18\n#define FPDF_ANNOT_MOVIE 19\n#define FPDF_ANNOT_WIDGET 20\n#define FPDF_ANNOT_SCREEN 21\n#define FPDF_ANNOT_PRINTERMARK 22\n#define FPDF_ANNOT_TRAPNET 23\n#define FPDF_ANNOT_WATERMARK 24\n#define FPDF_ANNOT_THREED 25\n#define FPDF_ANNOT_RICHMEDIA 26\n#define FPDF_ANNOT_XFAWIDGET 27\n#define FPDF_ANNOT_REDACT 28\n\n// Refer to PDF Reference (6th edition) table 8.16 for all annotation flags.\n#define FPDF_ANNOT_FLAG_NONE 0\n#define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0)\n#define FPDF_ANNOT_FLAG_HIDDEN (1 << 1)\n#define FPDF_ANNOT_FLAG_PRINT (1 << 2)\n#define FPDF_ANNOT_FLAG_NOZOOM (1 << 3)\n#define FPDF_ANNOT_FLAG_NOROTATE (1 << 4)\n#define FPDF_ANNOT_FLAG_NOVIEW (1 << 5)\n#define FPDF_ANNOT_FLAG_READONLY (1 << 6)\n#define FPDF_ANNOT_FLAG_LOCKED (1 << 7)\n#define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8)\n\n#define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0\n#define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1\n#define FPDF_ANNOT_APPEARANCEMODE_DOWN 2\n#define FPDF_ANNOT_APPEARANCEMODE_COUNT 3\n\n// Refer to PDF Reference version 1.7 table 8.70 for field flags common to all\n// interactive form field types.\n#define FPDF_FORMFLAG_NONE 0\n#define FPDF_FORMFLAG_READONLY (1 << 0)\n#define FPDF_FORMFLAG_REQUIRED (1 << 1)\n#define FPDF_FORMFLAG_NOEXPORT (1 << 2)\n\n// Refer to PDF Reference version 1.7 table 8.77 for field flags specific to\n// interactive form text fields.\n#define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12)\n#define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13)\n\n// Refer to PDF Reference version 1.7 table 8.79 for field flags specific to\n// interactive form choice fields.\n#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17)\n#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18)\n#define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21)\n\n// Additional actions type of form field:\n//   K, on key stroke, JavaScript action.\n//   F, on format, JavaScript action.\n//   V, on validate, JavaScript action.\n//   C, on calculate, JavaScript action.\n#define FPDF_ANNOT_AACTION_KEY_STROKE 12\n#define FPDF_ANNOT_AACTION_FORMAT 13\n#define FPDF_ANNOT_AACTION_VALIDATE 14\n#define FPDF_ANNOT_AACTION_CALCULATE 15\n\ntypedef enum FPDFANNOT_COLORTYPE {\n  FPDFANNOT_COLORTYPE_Color = 0,\n  FPDFANNOT_COLORTYPE_InteriorColor\n} FPDFANNOT_COLORTYPE;\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for creation.\n// Currently supported subtypes:\n//    - circle\n//    - fileattachment\n//    - freetext\n//    - highlight\n//    - ink\n//    - link\n//    - popup\n//    - square,\n//    - squiggly\n//    - stamp\n//    - strikeout\n//    - text\n//    - underline\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Create an annotation in |page| of the subtype |subtype|. If the specified\n// subtype is illegal or unsupported, then a new annotation will not be created.\n// Must call FPDFPage_CloseAnnot() when the annotation returned by this\n// function is no longer needed.\n//\n//   page      - handle to a page.\n//   subtype   - the subtype of the new annotation.\n//\n// Returns a handle to the new annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Get the number of annotations in |page|.\n//\n//   page   - handle to a page.\n//\n// Returns the number of annotations in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page);\n\n// Experimental API.\n// Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the\n// annotation returned by this function is no longer needed.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns a handle to the annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,\n                                                            int index);\n\n// Experimental API.\n// Get the index of |annot| in |page|. This is the opposite of\n// FPDFPage_GetAnnot().\n//\n//   page  - handle to the page that the annotation is on.\n//   annot - handle to an annotation.\n//\n// Returns the index of |annot|, or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,\n                                                     FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Close an annotation. Must be called when the annotation returned by\n// FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This\n// function does not remove the annotation from the document.\n//\n//   annot  - handle to an annotation.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Remove the annotation in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,\n                                                         int index);\n\n// Experimental API.\n// Get the subtype of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the annotation subtype.\nFPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV\nFPDFAnnot_GetSubtype(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for object extraction,\n// update, and removal.\n// Currently supported subtypes: ink and stamp.\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Update |obj| in |annot|. |obj| must be in |annot| already and must have\n// been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp\n// annotations are supported by this API. Also note that only path, image, and\n// text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and\n// FPDFImageObj_*().\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that |annot| needs to update.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Add a new InkStroke, represented by an array of points, to the InkList of\n// |annot|. The API creates an InkList if one doesn't already exist in |annot|.\n// This API works only for ink annotations. Please refer to ISO 32000-1:2008\n// spec, section 12.5.6.13.\n//\n//   annot       - handle to an annotation.\n//   points      - pointer to a FS_POINTF array representing input points.\n//   point_count - number of elements in |points| array. This should not exceed\n//                 the maximum value that can be represented by an int32_t).\n//\n// Returns the 0-based index at which the new InkStroke is added in the InkList\n// of the |annot|. Returns -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot,\n                                                     const FS_POINTF* points,\n                                                     size_t point_count);\n\n// Experimental API.\n// Removes an InkList in |annot|.\n// This API works only for ink annotations.\n//\n//   annot  - handle to an annotation.\n//\n// Return true on successful removal of /InkList entry from context of the\n// non-null ink |annot|. Returns false on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add |obj| to |annot|. |obj| must have been created by\n// FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and\n// will be owned by |annot|. Note that an |obj| cannot belong to more than one\n// |annot|. Currently, only ink and stamp annotations are supported by this API.\n// Also note that only path, image, and text objects have APIs for creation.\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that is to be added to |annot|.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Get the total number of objects in |annot|, including path objects, text\n// objects, external objects, image objects, and shading objects.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of objects in |annot|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object.\n//\n// Return a handle to the object, or NULL on failure.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Remove the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object to be removed.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Set the color of an annotation. Fails when called on annotations with\n// appearance streams already defined; instead use\n// FPDFPageObj_Set{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color to be set.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int R,\n                                                       unsigned int G,\n                                                       unsigned int B,\n                                                       unsigned int A);\n\n// Experimental API.\n// Get the color of an annotation. If no color is specified, default to yellow\n// for highlight annotation, black for all else. Fails when called on\n// annotations with appearance streams already defined; instead use\n// FPDFPageObj_Get{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color requested.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int* R,\n                                                       unsigned int* G,\n                                                       unsigned int* B,\n                                                       unsigned int* A);\n\n// Experimental API.\n// Check if the annotation is of a type that has attachment points\n// (i.e. quadpoints). Quadpoints are the vertices of the rectangle that\n// encompasses the texts affected by the annotation. They provide the\n// coordinates in the page where the annotation is attached. Only text markup\n// annotations (i.e. highlight, strikeout, squiggly, and underline) and link\n// annotations have quadpoints.\n//\n//   annot  - handle to an annotation.\n//\n// Returns true if the annotation is of a type that has quadpoints, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Replace the attachment points (i.e. quadpoints) set of an annotation at\n// |quad_index|. This index needs to be within the result of\n// FPDFAnnot_CountAttachmentPoints().\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Append to the list of attachment points (i.e. quadpoints) of an annotation.\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,\n                                 const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Get the number of sets of quadpoints of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of sets of quadpoints, or 0 on failure.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the attachment points (i.e. quadpoints) of an annotation.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - receives the quadpoints; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Set the annotation rectangle defining the location of the annotation. If the\n// annotation's appearance stream is defined and this annotation is of a type\n// without quadpoints, then update the bounding box too if the new rectangle\n// defines a bigger one.\n//\n//   annot  - handle to an annotation.\n//   rect   - the annotation rectangle to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,\n                                                      const FS_RECTF* rect);\n\n// Experimental API.\n// Get the annotation rectangle defining the location of the annotation.\n//\n//   annot  - handle to an annotation.\n//   rect   - receives the rectangle; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,\n                                                      FS_RECTF* rect);\n\n// Experimental API.\n// Get the vertices of a polygon or polyline annotation. |buffer| is an array of\n// points of the annotation. If |length| is less than the returned length, or\n// |annot| or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points if the annotation is of type polygon or\n// polyline, 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetVertices(FPDF_ANNOTATION annot,\n                      FS_POINTF* buffer,\n                      unsigned long length);\n\n// Experimental API.\n// Get the number of paths in the ink list of an ink annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//\n// Returns the number of paths in the ink list if the annotation is of type ink,\n// 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get a path in the ink list of an ink annotation. |buffer| is an array of\n// points of the path. If |length| is less than the returned length, or |annot|\n// or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   path_index - index of the path\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points of the path if the annotation is of type ink, 0\n// otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot,\n                         unsigned long path_index,\n                         FS_POINTF* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Get the starting and ending coordinates of a line annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   start - starting point\n//   end - ending point\n//\n// Returns true if the annotation is of type line, |start| and |end| are not\n// NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,\n                                                      FS_POINTF* start,\n                                                      FS_POINTF* end);\n\n// Experimental API.\n// Set the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if setting the border for |annot| succeeds, false otherwise.\n//\n// If |annot| contains an appearance stream that overrides the border values,\n// then the appearance stream will be removed on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot,\n                                                        float horizontal_radius,\n                                                        float vertical_radius,\n                                                        float border_width);\n\n// Experimental API.\n// Get the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are\n// not NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetBorder(FPDF_ANNOTATION annot,\n                    float* horizontal_radius,\n                    float* vertical_radius,\n                    float* border_width);\n\n// Experimental API.\n// Get the JavaScript of an event of the annotation's additional actions.\n// |buffer| is only modified if |buflen| is large enough to hold the whole\n// JavaScript string. If |buflen| is smaller, the total size of the JavaScript\n// is still returned, but nothing is copied.  If there is no JavaScript for\n// |event| in |annot|, an empty string is written to |buf| and 2 is returned,\n// denoting the size of the null terminator in the buffer.  On other errors,\n// nothing is written to |buffer| and 0 is returned.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    event       -   event type, one of the FPDF_ANNOT_AACTION_* values.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes, including the 2-byte\n// null terminator.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle,\n                                            FPDF_ANNOTATION annot,\n                                            int event,\n                                            FPDF_WCHAR* buffer,\n                                            unsigned long buflen);\n\n// Experimental API.\n// Check if |annot|'s dictionary has |key| as a key.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,\n                                                     FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in |annot|'s dictionary.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in |annot|'s dictionary,\n// overwriting the existing value if any. The value type would be\n// FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the dictionary entry to be set, encoded in UTF-8.\n//   value  - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in |annot|'s dictionary. |buffer|\n// is only modified if |buflen| is longer than the length of contents. Note that\n// if |key| does not exist in the dictionary or if |key|'s corresponding value\n// in the dictionary is not a string (i.e. the value is not of type\n// FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied\n// to |buffer| and the return value would be 2. On other errors, nothing would\n// be added to |buffer| and the return value would be 0.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   buffer - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Get the float value corresponding to |key| in |annot|'s dictionary. Writes\n// value to |value| and returns True if |key| exists in the dictionary and\n// |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False\n// otherwise.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   value  - receives the value, must not be NULL.\n//\n// Returns True if value found, False otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         float* value);\n\n// Experimental API.\n// Set the AP (appearance string) in |annot|'s dictionary for a given\n// |appearanceMode|.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   value          - the string value to be set, encoded in UTF-16LE. If\n//                    nullptr is passed, the AP is cleared for that mode. If the\n//                    mode is Normal, APs for all modes are cleared.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the AP (appearance string) from |annot|'s dictionary for a given\n// |appearanceMode|.\n// |buffer| is only modified if |buflen| is large enough to hold the whole AP\n// string. If |buflen| is smaller, the total size of the AP is still returned,\n// but nothing is copied.\n// If there is no appearance stream for |annot| in |appearanceMode|, an empty\n// string is written to |buf| and 2 is returned.\n// On other errors, nothing is written to |buffer| and 0 is returned.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   buffer         - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen         - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WCHAR* buffer,\n                unsigned long buflen);\n\n// Experimental API.\n// Get the annotation corresponding to |key| in |annot|'s dictionary. Common\n// keys for linking annotations include \"IRT\" and \"Popup\". Must call\n// FPDFPage_CloseAnnot() when the annotation returned by this function is no\n// longer needed.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//\n// Returns a handle to the linked annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//   annot    - handle to an annotation.\n//\n// Returns the annotation flags.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the |annot|'s flags to be of the value |flags|.\n//\n//   annot      - handle to an annotation.\n//   flags      - the flag values to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,\n                                                       int flags);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the annotation flags specific to interactive forms.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Sets the form field flags for an interactive form annotation.\n//\n//   handle       -   the handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//   annot        -   handle to an interactive form annotation.\n//   flags        -   the form field flags to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot,\n                            int flags);\n\n// Experimental API.\n// Retrieves an interactive form annotation whose rectangle contains a given\n// point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned\n// is no longer needed.\n//\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    page        -   handle to the page, returned by FPDF_LoadPage function.\n//    point       -   position in PDF \"user space\".\n//\n// Returns the interactive form annotation whose rectangle contains the given\n// coordinates on the page. If there is no such annotation, return NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                              FPDF_PAGE page,\n                              const FS_POINTF* point);\n\n// Experimental API.\n// Gets the name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the name string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,\n                           FPDF_ANNOTATION annot,\n                           FPDF_WCHAR* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Gets the alternate name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the alternate name string, encoded in\n//                    UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle,\n                                    FPDF_ANNOTATION annot,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen);\n\n// Experimental API.\n// Gets the form field type of |annot|, which is an interactive form annotation.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on\n// success. Returns -1 on error.\n// See field types in fpdf_formfill.h.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the value of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,\n                            FPDF_ANNOTATION annot,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen);\n\n// Experimental API.\n// Get the number of options in the |annot|'s \"Opt\" dictionary. Intended for\n// use with listbox and combobox widget annotations.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns the number of options in \"Opt\" dictionary on success. Return value\n// will be -1 if annotation does not have an \"Opt\" dictionary or other error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the string value for the label of the option at |index| in |annot|'s\n// \"Opt\" dictionary. Intended for use with listbox and combobox widget\n// annotations. |buffer| is only modified if |buflen| is longer than the length\n// of contents. If index is out of range or in case of other error, nothing\n// will be added to |buffer| and the return value will be 0. Note that\n// return value of empty string is 2 for \"\\0\\0\".\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array\n//   buffer  - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen  - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\n// If |annot| does not have an \"Opt\" array, |index| is out of range or if any\n// other error occurs, returns 0.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,\n                         FPDF_ANNOTATION annot,\n                         int index,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Determine whether or not the option at |index| in |annot|'s \"Opt\" dictionary\n// is selected. Intended for use with listbox and combobox widget annotations.\n//\n//   handle  - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array.\n//\n// Returns true if the option at |index| in |annot|'s \"Opt\" dictionary is\n// selected, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,\n                           FPDF_ANNOTATION annot,\n                           int index);\n\n// Experimental API.\n// Get the float value of the font size for an |annot| with variable text.\n// If 0, the font is to be auto-sized: its size is computed as a function of\n// the height of the annotation rectangle.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   value   - Required. Float which will be set to font size on success.\n//\n// Returns true if the font size was set in |value|, false on error or if\n// |value| not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,\n                      FPDF_ANNOTATION annot,\n                      float* value);\n\n// Experimental API.\n// Set the text color of an annotation.\n//\n//   handle   - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R        - the red component for the text color.\n//   G        - the green component for the text color.\n//   B        - the blue component for the text color.\n//\n// Returns true if successful.\n//\n// Currently supported subtypes: freetext.\n// The range for the color components is 0 to 255.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int R,\n                       unsigned int G,\n                       unsigned int B);\n\n// Experimental API.\n// Get the RGB value of the font color for an |annot| with variable text.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//\n// Returns true if the font color was set, false on error or if the font\n// color was not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int* R,\n                       unsigned int* G,\n                       unsigned int* B);\n\n// Experimental API.\n// Determine if |annot| is a form widget that is checked. Intended for use with\n// checkbox and radio button widgets.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns true if |annot| is a form widget and is checked, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,\n                                                        FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the list of focusable annotation subtypes. Annotations of subtype\n// FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API\n// will override the existing subtypes.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - list of annotation subtype which can be tabbed over.\n//   count    - total number of annotation subtype in list.\n// Returns true if list of annotation subtype is set successfully, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               const FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Get the count of focusable annotation subtypes as set by host\n// for a |hHandle|.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n// Returns the count of focusable annotation subtypes or -1 on error.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Get the list of focusable annotation subtype as set by host.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - receives the list of annotation subtype which can be tabbed\n//              over. Caller must have allocated |subtypes| more than or\n//              equal to the count obtained from\n//              FPDFAnnot_GetFocusableSubtypesCount() API.\n//   count    - size of |subtypes|.\n// Returns true on success and set list of annotation subtype to |subtypes|,\n// false otherwise.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Gets FPDF_LINK object for |annot|. Intended to use for link annotations.\n//\n//   annot   - handle to an annotation.\n//\n// Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure,\n// if the input annot is NULL or input annot's subtype is not link.\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the count of annotations in the |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns number of controls in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the index of |annot| in |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns index of a given |annot| in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the export value of |annot| which is an interactive form annotation.\n// Intended for use with radio button and checkbox widget annotations.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value\n// will be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle,\n                                  FPDF_ANNOTATION annot,\n                                  FPDF_WCHAR* buffer,\n                                  unsigned long buflen);\n\n// Experimental API.\n// Add a URI action to |annot|, overwriting the existing action, if any.\n//\n//   annot  - handle to a link annotation.\n//   uri    - the URI to be set, encoded in 7-bit ASCII.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot,\n                                                     const char* uri);\n\n// Experimental API.\n// Get the attachment from |annot|.\n//\n//   annot - handle to a file annotation.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add an embedded file with |name| to |annot|.\n//\n//   annot    - handle to a file annotation.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ANNOT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_attachment.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ATTACHMENT_H_\n#define PUBLIC_FPDF_ATTACHMENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of embedded files in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of embedded files in |document|.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Add an embedded file with |name| in |document|. If |name| is empty, or if\n// |name| is the name of a existing embedded file in |document|, or if\n// |document|'s embedded file name tree is too deep (i.e. |document| has too\n// many embedded files already), then a new attachment will not be added.\n//\n//   document - handle to a document.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name);\n\n// Experimental API.\n// Get the embedded attachment at |index| in |document|. Note that the returned\n// attachment handle is only valid while |document| is open.\n//\n//   document - handle to a document.\n//   index    - the index of the requested embedded file.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Delete the embedded attachment at |index| in |document|. Note that this does\n// not remove the attachment data from the PDF file; it simply removes the\n// file's entry in the embedded files name tree so that it does not appear in\n// the attachment list. This behavior may change in the future.\n//\n//   document - handle to a document.\n//   index    - the index of the embedded file to be deleted.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Get the name of the |attachment| file. |buffer| is only modified if |buflen|\n// is longer than the length of the file name. On errors, |buffer| is unmodified\n// and the returned length is 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the file name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetName(FPDF_ATTACHMENT attachment,\n                       FPDF_WCHAR* buffer,\n                       unsigned long buflen);\n\n// Experimental API.\n// Check if the params dictionary of |attachment| has |key| as a key.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in the params dictionary of\n// the embedded |attachment|.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|, overwriting the existing value if any. The value\n// type should be FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the dictionary entry, encoded in UTF-8.\n//   value      - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|. |buffer| is only modified if |buflen| is longer\n// than the length of the string value. Note that if |key| does not exist in the\n// dictionary or if |key|'s corresponding value in the dictionary is not a\n// string (i.e. the value is not of type FPDF_OBJECT_STRING or\n// FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the\n// return value would be 2. On other errors, nothing would be added to |buffer|\n// and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the requested string value, encoded in UTF-8.\n//   buffer     - buffer for holding the string value encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the dictionary value string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WCHAR* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Set the file data of |attachment|, overwriting the existing file data if any.\n// The creation date and checksum will be updated, while all other dictionary\n// entries will be deleted. Note that only contents with |len| smaller than\n// INT_MAX is supported.\n//\n//   attachment - handle to an attachment.\n//   contents   - buffer holding the file data to write to |attachment|.\n//   len        - length of file data in bytes.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,\n                       FPDF_DOCUMENT document,\n                       const void* contents,\n                       unsigned long len);\n\n// Experimental API.\n// Get the file data of |attachment|.\n// When the attachment file data is readable, true is returned, and |out_buflen|\n// is updated to indicate the file data size. |buffer| is only modified if\n// |buflen| is non-null and long enough to contain the entire file data. Callers\n// must check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data.\n//\n// Otherwise, when the attachment file data is unreadable or when |out_buflen|\n// is null, false is returned and |buffer| and |out_buflen| remain unmodified.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file data from |attachment|.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to the variable that will receive the minimum buffer\n//                size to contain the file data of |attachment|.\n//\n// Returns true on success, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,\n                       void* buffer,\n                       unsigned long buflen,\n                       unsigned long* out_buflen);\n\n// Experimental API.\n// Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is\n// only modified if |buflen| is longer than the length of the MIME type string.\n// If the Subtype is not found or if there is no file stream, an empty string\n// would be copied to |buffer| and the return value would be 2. On other errors,\n// nothing would be added to |buffer| and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the MIME type string encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the MIME type string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment,\n                          FPDF_WCHAR* buffer,\n                          unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ATTACHMENT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_catalog.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_CATALOG_H_\n#define PUBLIC_FPDF_CATALOG_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n//\n// Determine if |document| represents a tagged PDF.\n//\n// For the definition of tagged PDF, See (see 10.7 \"Tagged PDF\" in PDF\n// Reference 1.7).\n//\n//   document - handle to a document.\n//\n// Returns |true| iff |document| is a tagged PDF.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_IsTagged(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Gets the language of |document| from the catalog's /Lang entry.\n//\n//   document - handle to a document.\n//   buffer   - a buffer for the language string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the language string, including the\n// trailing NUL character. The number of bytes is returned regardless of the\n// |buffer| and |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE\n// encoding. The string is terminated by a UTF16 NUL character. If\n// |buflen| is less than the required length, or |buffer| is NULL,\n// |buffer| will not be modified.\n//\n// If |document| has no /Lang entry, an empty string is written to |buffer| and\n// 2 is returned. On error, nothing is written to |buffer| and 0 is returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFCatalog_GetLanguage(FPDF_DOCUMENT document,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen);\n\n// Experimental API.\n// Sets the language of |document| to |language|.\n//\n// document - handle to a document.\n// language - the language to set to.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_CATALOG_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_dataavail.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DATAAVAIL_H_\n#define PUBLIC_FPDF_DATAAVAIL_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#define PDF_LINEARIZATION_UNKNOWN -1\n#define PDF_NOT_LINEARIZED 0\n#define PDF_LINEARIZED 1\n\n#define PDF_DATA_ERROR -1\n#define PDF_DATA_NOTAVAIL 0\n#define PDF_DATA_AVAIL 1\n\n#define PDF_FORM_ERROR -1\n#define PDF_FORM_NOTAVAIL 0\n#define PDF_FORM_AVAIL 1\n#define PDF_FORM_NOTEXIST 2\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Interface for checking whether sections of the file are available.\ntypedef struct _FX_FILEAVAIL {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Reports if the specified data section is currently available. A section is\n  // available if all bytes in the section are available.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the data section in the file.\n  //   size   - the size of the data section.\n  //\n  // Returns true if the specified data section at |offset| of |size|\n  // is available.\n  FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis,\n                           size_t offset,\n                           size_t size);\n} FX_FILEAVAIL;\n\n// Create a document availability provider.\n//\n//   file_avail - pointer to file availability interface.\n//   file       - pointer to a file access interface.\n//\n// Returns a handle to the document availability provider, or NULL on error.\n//\n// FPDFAvail_Destroy() must be called when done with the availability provider.\nFPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,\n                                                      FPDF_FILEACCESS* file);\n\n// Destroy the |avail| document availability provider.\n//\n//   avail - handle to document availability provider to be destroyed.\nFPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail);\n\n// Download hints interface. Used to receive hints for further downloading.\ntypedef struct _FX_DOWNLOADHINTS {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Add a section to be downloaded.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the hint reported to be downloaded.\n  //   size   - the size of the hint reported to be downloaded.\n  //\n  // The |offset| and |size| of the section may not be unique. Part of the\n  // section might be already available. The download manager must deal with\n  // overlapping sections.\n  void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis,\n                     size_t offset,\n                     size_t size);\n} FX_DOWNLOADHINTS;\n\n// Checks if the document is ready for loading, if not, gets download hints.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// Applications should call this function whenever new data arrives, and process\n// all the generated download hints, if any, until the function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|.\n// if hints is nullptr, the function just check current document availability.\n//\n// Once all data is available, call FPDFAvail_GetDocument() to get a document\n// handle.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,\n                                                   FX_DOWNLOADHINTS* hints);\n\n// Get document from the availability provider.\n//\n//   avail    - handle to document availability provider.\n//   password - password for decrypting the PDF file. Optional.\n//\n// Returns a handle to the document.\n//\n// When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to\n// retrieve the document handle.\n// See the comments for FPDF_LoadDocument() regarding the encoding for\n// |password|.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password);\n\n// Get the page number for the first available page in a linearized PDF.\n//\n//   doc - document handle.\n//\n// Returns the zero-based index for the first available page.\n//\n// For most linearized PDFs, the first available page will be the first page,\n// however, some PDFs might make another page the first available page.\n// For non-linearized PDFs, this function will always return zero.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc);\n\n// Check if |page_index| is ready for loading, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail      - handle to document availability provider.\n//   page_index - index number of the page. Zero for the first page.\n//   hints      - pointer to a download hints interface. Populated if\n//                |page_index| is not available.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// Applications should call this function whenever new data arrives and process\n// all the generated download |hints|, if any, until this function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page\n// loading.\n// if hints is nullptr, the function just check current availability of\n// specified page.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,\n                                                    int page_index,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check if form data is ready for initialization, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface. Populated if form is not\n//           ready for initialization.\n//\n// Returns one of:\n//   PDF_FORM_ERROR: A common eror, in general incorrect parameters.\n//   PDF_FORM_NOTAVAIL: Data not available.\n//   PDF_FORM_AVAIL: Data available.\n//   PDF_FORM_NOTEXIST: No form data.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// The application should call this function whenever new data arrives and\n// process all the generated download |hints|, if any, until the function\n// |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|.\n// if hints is nullptr, the function just check current form availability.\n//\n// Applications can then perform page loading. It is recommend to call\n// FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check whether a document is a linearized PDF.\n//\n//   avail - handle to document availability provider.\n//\n// Returns one of:\n//   PDF_LINEARIZED\n//   PDF_NOT_LINEARIZED\n//   PDF_LINEARIZATION_UNKNOWN\n//\n// FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED|\n// when we have 1k  of data. If the files size less than 1k, it returns\n// |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine\n// if the PDF is linearlized.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DATAAVAIL_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_doc.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DOC_H_\n#define PUBLIC_FPDF_DOC_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported action type.\n#define PDFACTION_UNSUPPORTED 0\n// Go to a destination within current document.\n#define PDFACTION_GOTO 1\n// Go to a destination within another document.\n#define PDFACTION_REMOTEGOTO 2\n// URI, including web pages and other Internet resources.\n#define PDFACTION_URI 3\n// Launch an application or open a file.\n#define PDFACTION_LAUNCH 4\n// Go to a destination in an embedded file.\n#define PDFACTION_EMBEDDEDGOTO 5\n\n// View destination fit types. See pdfmark reference v9, page 48.\n#define PDFDEST_VIEW_UNKNOWN_MODE 0\n#define PDFDEST_VIEW_XYZ 1\n#define PDFDEST_VIEW_FIT 2\n#define PDFDEST_VIEW_FITH 3\n#define PDFDEST_VIEW_FITV 4\n#define PDFDEST_VIEW_FITR 5\n#define PDFDEST_VIEW_FITB 6\n#define PDFDEST_VIEW_FITBH 7\n#define PDFDEST_VIEW_FITBV 8\n\n// The file identifier entry type. See section 14.4 \"File Identifiers\" of the\n// ISO 32000-1:2008 spec.\ntypedef enum {\n  FILEIDTYPE_PERMANENT = 0,\n  FILEIDTYPE_CHANGING = 1\n} FPDF_FILEIDTYPE;\n\n// Get the first child of |bookmark|, or the first top-level bookmark item.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark. Pass NULL for the first top\n//              level item.\n//\n// Returns a handle to the first child of |bookmark| or the first top-level\n// bookmark item. NULL if no child or top-level bookmark found.\n// Note that another name for the bookmarks is the document outline, as\n// described in ISO 32000-1:2008, section 12.3.3.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the next sibling of |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark.\n//\n// Returns a handle to the next sibling of |bookmark|, or NULL if this is the\n// last bookmark at this level.\n//\n// Note that the caller is responsible for handling circular bookmark\n// references, as may arise from malformed documents.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the title of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//   buffer   - buffer for the title. May be NULL.\n//   buflen   - the length of the buffer in bytes. May be 0.\n//\n// Returns the number of bytes in the title, including the terminating NUL\n// character. The number of bytes is returned regardless of the |buffer| and\n// |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |buflen| is less than the\n// required length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Experimental API.\n// Get the number of chlidren of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns a signed integer that represents the number of sub-items the given\n// bookmark has. If the value is positive, child items shall be shown by default\n// (open state). If the value is negative, child items shall be hidden by\n// default (closed state). Please refer to PDF 32000-1:2008, Table 153.\n// Returns 0 if the bookmark has no children or is invalid.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark);\n\n// Find the bookmark with |title| in |document|.\n//\n//   document - handle to the document.\n//   title    - the UTF-16LE encoded Unicode title for which to search.\n//\n// Returns the handle to the bookmark, or NULL if |title| can't be found.\n//\n// FPDFBookmark_Find() will always return the first bookmark found even if\n// multiple bookmarks have the same |title|.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title);\n\n// Get the destination associated with |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the destination data, or NULL if no destination is\n// associated with |bookmark|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the action associated with |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the action data, or NULL if no action is associated\n// with |bookmark|.\n// If this function returns a valid handle, it is valid as long as |bookmark| is\n// valid.\n// If this function returns NULL, FPDFBookmark_GetDest() should be called to get\n// the |bookmark| destination data.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV\nFPDFBookmark_GetAction(FPDF_BOOKMARK bookmark);\n\n// Get the type of |action|.\n//\n//   action - handle to the action.\n//\n// Returns one of:\n//   PDFACTION_UNSUPPORTED\n//   PDFACTION_GOTO\n//   PDFACTION_REMOTEGOTO\n//   PDFACTION_URI\n//   PDFACTION_LAUNCH\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action);\n\n// Get the destination of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. |action| must be a |PDFACTION_GOTO| or\n//              |PDFACTION_REMOTEGOTO|.\n//\n// Returns a handle to the destination data, or NULL on error, typically\n// because the arguments were bad or the action was of the wrong type.\n//\n// In the case of |PDFACTION_REMOTEGOTO|, you must first call\n// FPDFAction_GetFilePath(), then load the document at that path, then pass\n// the document handle from that document as |document| to FPDFAction_GetDest().\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document,\n                                                       FPDF_ACTION action);\n\n// Get the file path of |action|.\n//\n//   action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or\n//            |PDFACTION_REMOTEGOTO|.\n//   buffer - a buffer for output the path string. May be NULL.\n//   buflen - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen);\n\n// Get the URI path of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. Must be a |PDFACTION_URI|.\n//   buffer   - a buffer for the path string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the URI path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// The |buffer| may contain badly encoded data. The caller should validate the\n// output. e.g. Check to see if it is UTF-8.\n//\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\n//\n// Historically, the documentation for this API claimed |buffer| is always\n// encoded in 7-bit ASCII, but did not actually enforce it.\n// https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592\n// added that enforcement, but that did not work well for real world PDFs that\n// used UTF-8. As of this writing, this API reverted back to its original\n// behavior prior to commit d609e84cee.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetURIPath(FPDF_DOCUMENT document,\n                      FPDF_ACTION action,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Get the page index of |dest|.\n//\n//   document - handle to the document.\n//   dest     - handle to the destination.\n//\n// Returns the 0-based page index containing |dest|. Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document,\n                                                        FPDF_DEST dest);\n\n// Experimental API.\n// Get the view (fit type) specified by |dest|.\n//\n//   dest         - handle to the destination.\n//   pNumParams   - receives the number of view parameters, which is at most 4.\n//   pParams      - buffer to write the view parameters. Must be at least 4\n//                  FS_FLOATs long.\n// Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if\n// |dest| does not specify a view.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams);\n\n// Get the (x, y, zoom) location of |dest| in the destination page, if the\n// destination is in [page /XYZ x y zoom] syntax.\n//\n//   dest       - handle to the destination.\n//   hasXVal    - out parameter; true if the x value is not null\n//   hasYVal    - out parameter; true if the y value is not null\n//   hasZoomVal - out parameter; true if the zoom value is not null\n//   x          - out parameter; the x coordinate, in page coordinates.\n//   y          - out parameter; the y coordinate, in page coordinates.\n//   zoom       - out parameter; the zoom value.\n// Returns TRUE on successfully reading the /XYZ value.\n//\n// Note the [x, y, zoom] values are only set if the corresponding hasXVal,\n// hasYVal or hasZoomVal flags are true.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDest_GetLocationInPage(FPDF_DEST dest,\n                           FPDF_BOOL* hasXVal,\n                           FPDF_BOOL* hasYVal,\n                           FPDF_BOOL* hasZoomVal,\n                           FS_FLOAT* x,\n                           FS_FLOAT* y,\n                           FS_FLOAT* zoom);\n\n// Find a link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns a handle to the link, or NULL if no link found at the given point.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Find the Z-order of link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns the Z-order of the link, or -1 if no link found at the given point.\n// Larger Z-order numbers are closer to the front.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Get destination info for |link|.\n//\n//   document - handle to the document.\n//   link     - handle to the link.\n//\n// Returns a handle to the destination, or NULL if there is no destination\n// associated with the link. In this case, you should call FPDFLink_GetAction()\n// to retrieve the action associated with |link|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document,\n                                                     FPDF_LINK link);\n\n// Get action info for |link|.\n//\n//   link - handle to the link.\n//\n// Returns a handle to the action associated to |link|, or NULL if no action.\n// If this function returns a valid handle, it is valid as long as |link| is\n// valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link);\n\n// Enumerates all the link annotations in |page|.\n//\n//   page       - handle to the page.\n//   start_pos  - the start position, should initially be 0 and is updated with\n//                the next start position on return.\n//   link_annot - the link handle for |startPos|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page,\n                                                       int* start_pos,\n                                                       FPDF_LINK* link_annot);\n\n// Experimental API.\n// Gets FPDF_ANNOTATION object for |link_annot|.\n//\n//   page       - handle to the page in which FPDF_LINK object is present.\n//   link_annot - handle to link annotation.\n//\n// Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure,\n// if the input link annot or page is NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot);\n\n// Get the rectangle for |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//   rect       - the annotation rectangle.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot,\n                                                          FS_RECTF* rect);\n\n// Get the count of quadrilateral points to the |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//\n// Returns the count of quadrilateral points.\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot);\n\n// Get the quadrilateral points for the specified |quad_index| in |link_annot|.\n//\n//   link_annot  - handle to the link annotation.\n//   quad_index  - the specified quad point index.\n//   quad_points - receives the quadrilateral points.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetQuadPoints(FPDF_LINK link_annot,\n                       int quad_index,\n                       FS_QUADPOINTSF* quad_points);\n\n// Experimental API\n// Gets an additional-action from |page|.\n//\n//   page      - handle to the page, as returned by FPDF_LoadPage().\n//   aa_type   - the type of the page object's addtional-action, defined\n//               in public/fpdf_formfill.h\n//\n//   Returns the handle to the action data, or NULL if there is no\n//   additional-action of type |aa_type|.\n//   If this function returns a valid handle, it is valid as long as |page| is\n//   valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page,\n                                                          int aa_type);\n\n// Experimental API.\n// Get the file identifer defined in the trailer of |document|.\n//\n//   document - handle to the document.\n//   id_type  - the file identifier type to retrieve.\n//   buffer   - a buffer for the file identifier. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file identifier, including the NUL\n// terminator.\n//\n// The |buffer| is always a byte string. The |buffer| is followed by a NUL\n// terminator.  If |buflen| is less than the returned length, or |buffer| is\n// NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetFileIdentifier(FPDF_DOCUMENT document,\n                       FPDF_FILEIDTYPE id_type,\n                       void* buffer,\n                       unsigned long buflen);\n\n// Get meta-data |tag| content from |document|.\n//\n//   document - handle to the document.\n//   tag      - the tag to retrieve. The tag can be one of:\n//                Title, Author, Subject, Keywords, Creator, Producer,\n//                CreationDate, or ModDate.\n//              For detailed explanations of these tags and their respective\n//              values, please refer to PDF Reference 1.6, section 10.2.1,\n//              'Document Information Dictionary'.\n//   buffer   - a buffer for the tag. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the tag, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// For linearized files, FPDFAvail_IsFormAvail must be called before this, and\n// it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there\n// is no guarantee the metadata has been loaded.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document,\n                                                         FPDF_BYTESTRING tag,\n                                                         void* buffer,\n                                                         unsigned long buflen);\n\n// Get the page label for |page_index| from |document|.\n//\n//   document    - handle to the document.\n//   page_index  - the 0-based index of the page.\n//   buffer      - a buffer for the page label. May be NULL.\n//   buflen      - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the page label, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetPageLabel(FPDF_DOCUMENT document,\n                  int page_index,\n                  void* buffer,\n                  unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DOC_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_edit.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EDIT_H_\n#define PUBLIC_FPDF_EDIT_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n#define FPDF_ARGB(a, r, g, b)                                      \\\n  ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \\\n              (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24)))\n#define FPDF_GetBValue(argb) ((uint8_t)(argb))\n#define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8))\n#define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16))\n#define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24))\n\n// Refer to PDF Reference version 1.7 table 4.12 for all color space families.\n#define FPDF_COLORSPACE_UNKNOWN 0\n#define FPDF_COLORSPACE_DEVICEGRAY 1\n#define FPDF_COLORSPACE_DEVICERGB 2\n#define FPDF_COLORSPACE_DEVICECMYK 3\n#define FPDF_COLORSPACE_CALGRAY 4\n#define FPDF_COLORSPACE_CALRGB 5\n#define FPDF_COLORSPACE_LAB 6\n#define FPDF_COLORSPACE_ICCBASED 7\n#define FPDF_COLORSPACE_SEPARATION 8\n#define FPDF_COLORSPACE_DEVICEN 9\n#define FPDF_COLORSPACE_INDEXED 10\n#define FPDF_COLORSPACE_PATTERN 11\n\n// The page object constants.\n#define FPDF_PAGEOBJ_UNKNOWN 0\n#define FPDF_PAGEOBJ_TEXT 1\n#define FPDF_PAGEOBJ_PATH 2\n#define FPDF_PAGEOBJ_IMAGE 3\n#define FPDF_PAGEOBJ_SHADING 4\n#define FPDF_PAGEOBJ_FORM 5\n\n// The path segment constants.\n#define FPDF_SEGMENT_UNKNOWN -1\n#define FPDF_SEGMENT_LINETO 0\n#define FPDF_SEGMENT_BEZIERTO 1\n#define FPDF_SEGMENT_MOVETO 2\n\n#define FPDF_FILLMODE_NONE 0\n#define FPDF_FILLMODE_ALTERNATE 1\n#define FPDF_FILLMODE_WINDING 2\n\n#define FPDF_FONT_TYPE1 1\n#define FPDF_FONT_TRUETYPE 2\n\n#define FPDF_LINECAP_BUTT 0\n#define FPDF_LINECAP_ROUND 1\n#define FPDF_LINECAP_PROJECTING_SQUARE 2\n\n#define FPDF_LINEJOIN_MITER 0\n#define FPDF_LINEJOIN_ROUND 1\n#define FPDF_LINEJOIN_BEVEL 2\n\n// See FPDF_SetPrintMode() for descriptions.\n#define FPDF_PRINTMODE_EMF 0\n#define FPDF_PRINTMODE_TEXTONLY 1\n#define FPDF_PRINTMODE_POSTSCRIPT2 2\n#define FPDF_PRINTMODE_POSTSCRIPT3 3\n#define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4\n#define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5\n#define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8\n\ntypedef struct FPDF_IMAGEOBJ_METADATA {\n  // The image width in pixels.\n  unsigned int width;\n  // The image height in pixels.\n  unsigned int height;\n  // The image's horizontal pixel-per-inch.\n  float horizontal_dpi;\n  // The image's vertical pixel-per-inch.\n  float vertical_dpi;\n  // The number of bits used to represent each pixel.\n  unsigned int bits_per_pixel;\n  // The image's colorspace. See above for the list of FPDF_COLORSPACE_*.\n  int colorspace;\n  // The image's marked content ID. Useful for pairing with associated alt-text.\n  // A value of -1 indicates no ID.\n  int marked_content_id;\n} FPDF_IMAGEOBJ_METADATA;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Create a new PDF document.\n//\n// Returns a handle to a new document, or NULL on failure.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument();\n\n// Create a new PDF page.\n//\n//   document   - handle to document.\n//   page_index - suggested 0-based index of the page to create. If it is larger\n//                than document's current last index(L), the created page index\n//                is the next available index -- L+1.\n//   width      - the page width in points.\n//   height     - the page height in points.\n//\n// Returns the handle to the new page or NULL on failure.\n//\n// The page should be closed with FPDF_ClosePage() when finished as\n// with any other page in the document.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,\n                                                 int page_index,\n                                                 double width,\n                                                 double height);\n\n// Delete the page at |page_index|.\n//\n//   document   - handle to document.\n//   page_index - the index of the page to delete.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,\n                                               int page_index);\n\n// Experimental API.\n// Move the given pages to a new index position.\n//\n//  page_indices     - the ordered list of pages to move. No duplicates allowed.\n//  page_indices_len - the number of elements in |page_indices|\n//  dest_page_index  - the new index position to which the pages in\n//                     |page_indices| are moved.\n//\n// Returns TRUE on success. If it returns FALSE, the document may be left in an\n// indeterminate state.\n//\n// Example: The PDF document starts out with pages [A, B, C, D], with indices\n// [0, 1, 2, 3].\n//\n// >  Move(doc, [3, 2], 2, 1); // returns true\n// >  // The document has pages [A, D, C, B].\n// >\n// >  Move(doc, [0, 4, 3], 3, 1); // returns false\n// >  // Returned false because index 4 is out of range.\n// >\n// >  Move(doc, [0, 3, 1], 3, 2); // returns false\n// >  // Returned false because index 2 is out of range for 3 page indices.\n// >\n// >  Move(doc, [2, 2], 2, 0); // returns false\n// >  // Returned false because [2, 2] contains duplicates.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_MovePages(FPDF_DOCUMENT document,\n               const int* page_indices,\n               unsigned long page_indices_len,\n               int dest_page_index);\n\n// Get the rotation of |page|.\n//\n//   page - handle to a page\n//\n// Returns one of the following indicating the page rotation:\n//   0 - No rotation.\n//   1 - Rotated 90 degrees clockwise.\n//   2 - Rotated 180 degrees clockwise.\n//   3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page);\n\n// Set rotation for |page|.\n//\n//   page   - handle to a page.\n//   rotate - the rotation value, one of:\n//              0 - No rotation.\n//              1 - Rotated 90 degrees clockwise.\n//              2 - Rotated 180 degrees clockwise.\n//              3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate);\n\n// Insert |page_object| into |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object. The |page_object| will be\n//                 automatically freed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Insert |page_object| into |page| at the specified |index|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object as previously obtained by\n//                 FPDFPageObj_CreateNew{Path|Rect}() or\n//                 FPDFPageObj_New{Text|Image}Obj(). Ownership of the object\n//                 is transferred back to PDFium.\n//   index       - the index position to insert the object at. If index equals\n//                 the current object count, the object will be appended to the\n//                 end. If index is greater than the object count, the function\n//                 will fail and return false.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_InsertObjectAtIndex(FPDF_PAGE page,\n                             FPDF_PAGEOBJECT page_object,\n                             size_t index);\n\n// Experimental API.\n// Remove |page_object| from |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object to be removed.\n//\n// Returns TRUE on success.\n//\n// Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free\n// it.\n// Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all\n// FPDF_TEXTPAGE handles for |page| are no longer valid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Get number of page objects inside |page|.\n//\n//   page - handle to a page.\n//\n// Returns the number of objects in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page);\n\n// Get object in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of a page object.\n//\n// Returns the handle to the page object, or NULL on failed.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,\n                                                             int index);\n\n// Checks if |page| contains transparency.\n//\n//   page - handle to a page.\n//\n// Returns TRUE if |page| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page);\n\n// Generate the content of |page|.\n//\n//   page - handle to a page.\n//\n// Returns TRUE on success.\n//\n// Before you save the page to a file, or reload the page, you must call\n// |FPDFPage_GenerateContent| or any changes to |page| will be lost.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page);\n\n// Destroy |page_object| by releasing its resources. |page_object| must have\n// been created by FPDFPageObj_CreateNew{Path|Rect}() or\n// FPDFPageObj_New{Text|Image}Obj(). This function must be called on\n// newly-created objects if they are not added to a page through\n// FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject().\n//\n//   page_object - handle to a page object.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object);\n\n// Checks if |page_object| contains transparency.\n//\n//   page_object - handle to a page object.\n//\n// Returns TRUE if |page_object| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object);\n\n// Get type of |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on\n// error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Gets active state for |page_object| within page.\n//\n//   page_object - handle to a page object.\n//   active      - pointer to variable that will receive if the page object is\n//                 active. This is a required parameter. Not filled if FALSE\n//                 is returned.\n//\n// For page objects where |active| is filled with FALSE, the |page_object| is\n// treated as if it wasn't in the document even though it is still held\n// internally.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active);\n\n// Experimental API.\n// Sets if |page_object| is active within page.\n//\n//   page_object - handle to a page object.\n//   active      - a boolean specifying if the object is active.\n//\n// Returns TRUE on success.\n//\n// Page objects all start in the active state by default, and remain in that\n// state unless this function is called.\n//\n// When |active| is false, this makes the |page_object| be treated as if it\n// wasn't in the document even though it is still held internally.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active);\n\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   a           - matrix value.\n//   b           - matrix value.\n//   c           - matrix value.\n//   d           - matrix value.\n//   e           - matrix value.\n//   f           - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page_object|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,\n                      double a,\n                      double b,\n                      double c,\n                      double d,\n                      double e,\n                      double f);\n\n// Experimental API.\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   matrix      - the transform matrix.\n//\n// Returns TRUE on success.\n//\n// This can be used to scale, rotate, shear and translate the |page_object|.\n// It is an improved version of FPDFPageObj_Transform() that does not do\n// unnecessary double to float conversions, and only uses 1 parameter for the\n// matrix. It also returns whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Experimental API.\n// Get the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct to receive the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and used to scale, rotate, shear and translate the page object.\n//\n// For page objects outside form objects, the matrix values are relative to the\n// page that contains it.\n// For page objects inside form objects, the matrix values are relative to the\n// form that contains it.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix);\n\n// Experimental API.\n// Set the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct with the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the page object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Transform all annotations in |page|.\n//\n//   page - handle to a page.\n//   a    - matrix value.\n//   b    - matrix value.\n//   c    - matrix value.\n//   d    - matrix value.\n//   e    - matrix value.\n//   f    - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page| annotations.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,\n                                                        double a,\n                                                        double b,\n                                                        double c,\n                                                        double d,\n                                                        double e,\n                                                        double f);\n\n// Create a new image object.\n//\n//   document - handle to a document.\n//\n// Returns a handle to a new image object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewImageObj(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the marked content ID for the object.\n//\n//   page_object - handle to a page object.\n//\n// Returns the page object's marked content ID, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of content marks in |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns the number of content marks in |page_object|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get content mark in |page_object| at |index|.\n//\n//   page_object - handle to a page object.\n//   index       - the index of a page object.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index);\n\n// Experimental API.\n// Add a new content mark to a |page_object|.\n//\n//   page_object - handle to a page object.\n//   name        - the name (tag) of the mark.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name);\n\n// Experimental API.\n// Removes a content |mark| from a |page_object|.\n// The mark handle will be invalid after the removal.\n//\n//   page_object - handle to a page object.\n//   mark        - handle to a content mark in that object to remove.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the name of a content mark.\n//\n//   mark       - handle to a content mark.\n//   buffer     - buffer for holding the returned name in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the name.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen,\n                        unsigned long* out_buflen);\n\n// Experimental API.\n// Get the number of key/value pair parameters in |mark|.\n//\n//   mark   - handle to a content mark.\n//\n// Returns the number of key/value pair parameters |mark|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the key of a property in a content mark.\n//\n//   mark       - handle to a content mark.\n//   index      - index of the property.\n//   buffer     - buffer for holding the returned key in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the key.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,\n                            unsigned long index,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen,\n                            unsigned long* out_buflen);\n\n// Experimental API.\n// Get the type of the value of a property in a content mark by key.\n//\n//   mark   - handle to a content mark.\n//   key    - string key of the property.\n//\n// Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as int.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,\n                                 FPDF_BYTESTRING key,\n                                 int* out_value);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as float.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark,\n                                   FPDF_BYTESTRING key,\n                                   float* out_value);\n\n// Experimental API.\n// Get the value of a string property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value in UTF-16LE. This is\n//                only modified if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,\n                                    FPDF_BYTESTRING key,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen,\n                                    unsigned long* out_buflen);\n\n// Experimental API.\n// Get the value of a blob property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value. This is only modified\n//                if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key,\n                                  unsigned char* buffer,\n                                  unsigned long buflen,\n                                  unsigned long* out_buflen);\n\n// Experimental API.\n// Set the value of an int property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - int value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,\n                            FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key,\n                            int value);\n\n// Experimental API.\n// Set the value of a float property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - float value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document,\n                              FPDF_PAGEOBJECT page_object,\n                              FPDF_PAGEOBJECTMARK mark,\n                              FPDF_BYTESTRING key,\n                              float value);\n\n// Experimental API.\n// Set the value of a string property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - string value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,\n                               FPDF_PAGEOBJECT page_object,\n                               FPDF_PAGEOBJECTMARK mark,\n                               FPDF_BYTESTRING key,\n                               FPDF_BYTESTRING value);\n\n// Experimental API.\n// Set the value of a blob property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - pointer to blob value to set.\n//   value_len   - size in bytes of |value|.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,\n                             FPDF_PAGEOBJECT page_object,\n                             FPDF_PAGEOBJECTMARK mark,\n                             FPDF_BYTESTRING key,\n                             const unsigned char* value,\n                             unsigned long value_len);\n\n// Experimental API.\n// Removes a property from a content mark by key.\n//\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,\n                          int count,\n                          FPDF_PAGEOBJECT image_object,\n                          FPDF_FILEACCESS* file_access);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value. This function loads the JPEG image inline, so the image\n// content is copied to the file. This allows |file_access| and its associated\n// data to be deleted after this function returns.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,\n                                int count,\n                                FPDF_PAGEOBJECT image_object,\n                                FPDF_FILEACCESS* file_access);\n\n// TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable.\n//\n// Set the transform matrix of |image_object|.\n//\n//   image_object - handle to an image object.\n//   a            - matrix value.\n//   b            - matrix value.\n//   c            - matrix value.\n//   d            - matrix value.\n//   e            - matrix value.\n//   f            - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |image_object|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,\n                       double a,\n                       double b,\n                       double c,\n                       double d,\n                       double e,\n                       double f);\n\n// Set |bitmap| to |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   bitmap       - handle of the bitmap.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetBitmap(FPDF_PAGE* pages,\n                       int count,\n                       FPDF_PAGEOBJECT image_object,\n                       FPDF_BITMAP bitmap);\n\n// Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only\n// operates on |image_object| and does not take the associated image mask into\n// account. It also ignores the matrix for |image_object|.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   image_object - handle to an image object.\n//\n// Returns the bitmap.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object);\n\n// Experimental API.\n// Get a bitmap rasterization of |image_object| that takes the image mask and\n// image matrix into account. To render correctly, the caller must provide the\n// |document| associated with |image_object|. If there is a |page| associated\n// with |image_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document     - handle to a document associated with |image_object|.\n//   page         - handle to an optional page associated with |image_object|.\n//   image_object - handle to an image object.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                               FPDF_PAGE page,\n                               FPDF_PAGEOBJECT image_object);\n\n// Get the decoded image data of |image_object|. The decoded data is the\n// uncompressed image data, i.e. the raw image data after having all filters\n// applied. |buffer| is only modified if |buflen| is longer than the length of\n// the decoded image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the decoded image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the decoded image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Get the raw image data of |image_object|. The raw data is the image data as\n// stored in the PDF without applying any filters. |buffer| is only modified if\n// |buflen| is longer than the length of the raw image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the raw image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the raw image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Get the number of filters (i.e. decoders) of the image in |image_object|.\n//\n//   image_object - handle to an image object.\n//\n// Returns the number of |image_object|'s filters.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object);\n\n// Get the filter at |index| of |image_object|'s list of filters. Note that the\n// filters need to be applied in order, i.e. the first filter should be applied\n// first, then the second, etc. |buffer| is only modified if |buflen| is longer\n// than the length of the filter string.\n//\n//   image_object - handle to an image object.\n//   index        - the index of the filter requested.\n//   buffer       - buffer for holding filter string, encoded in UTF-8.\n//   buflen       - length of the buffer.\n//\n// Returns the length of the filter string.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,\n                            int index,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Get the image metadata of |image_object|, including dimension, DPI, bits per\n// pixel, and colorspace. If the |image_object| is not an image object or if it\n// does not have an image, then the return value will be false. Otherwise,\n// failure to retrieve any specific parameter would result in its value being 0.\n//\n//   image_object - handle to an image object.\n//   page         - handle to the page that |image_object| is on. Required for\n//                  retrieving the image's bits per pixel and colorspace.\n//   metadata     - receives the image metadata; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,\n                              FPDF_PAGE page,\n                              FPDF_IMAGEOBJ_METADATA* metadata);\n\n// Experimental API.\n// Get the image size in pixels. Faster method to get only image size.\n//\n//   image_object - handle to an image object.\n//   width        - receives the image width in pixels; must not be NULL.\n//   height       - receives the image height in pixels; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object,\n                               unsigned int* width,\n                               unsigned int* height);\n\n// Experimental API.\n// Get ICC profile decoded data of |image_object|. If the |image_object| is not\n// an image object or if it does not have an image, then the return value will\n// be false. It also returns false if the |image_object| has no ICC profile.\n// |buffer| is only modified if ICC profile exists and |buflen| is longer than\n// the length of the ICC profile decoded data.\n//\n//   image_object - handle to an image object; must not be NULL.\n//   page         - handle to the page containing |image_object|; must not be\n//                  NULL. Required for retrieving the image's colorspace.\n//   buffer       - Buffer to receive ICC profile data; may be NULL if querying\n//                  required size via |out_buflen|.\n//   buflen       - Length of the buffer in bytes. Ignored if |buffer| is NULL.\n//   out_buflen   - Pointer to receive the ICC profile data size in bytes; must\n//                  not be NULL. Will be set if this API returns true.\n//\n// Returns true if |out_buflen| is not null and an ICC profile exists for the\n// given |image_object|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object,\n                                      FPDF_PAGE page,\n                                      uint8_t* buffer,\n                                      size_t buflen,\n                                      size_t* out_buflen);\n\n// Create a new path object at an initial position.\n//\n//   x - initial horizontal position.\n//   y - initial vertical position.\n//\n// Returns a handle to a new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,\n                                                                    float y);\n\n// Create a closed path consisting of a rectangle.\n//\n//   x - horizontal position for the left boundary of the rectangle.\n//   y - vertical position for the bottom boundary of the rectangle.\n//   w - width of the rectangle.\n//   h - height of the rectangle.\n//\n// Returns a handle to the new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,\n                                                                    float y,\n                                                                    float w,\n                                                                    float h);\n\n// Get the bounding box of |page_object|.\n//\n// page_object  - handle to a page object.\n// left         - pointer where the left coordinate will be stored\n// bottom       - pointer where the bottom coordinate will be stored\n// right        - pointer where the right coordinate will be stored\n// top          - pointer where the top coordinate will be stored\n//\n// On success, returns TRUE and fills in the 4 coordinates.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,\n                      float* left,\n                      float* bottom,\n                      float* right,\n                      float* top);\n\n// Experimental API.\n// Get the quad points that bounds |page_object|.\n//\n// page_object  - handle to a page object.\n// quad_points  - pointer where the quadrilateral points will be stored.\n//\n// On success, returns TRUE and fills in |quad_points|.\n//\n// Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page\n// object. When the object is rotated by a non-multiple of 90 degrees, this API\n// returns a tighter bound that cannot be represented with just the 4 sides of\n// a rectangle.\n//\n// Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and\n// FPDF_PAGEOBJ_IMAGE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,\n                             FS_QUADPOINTSF* quad_points);\n\n// Set the blend mode of |page_object|.\n//\n// page_object  - handle to a page object.\n// blend_mode   - string containing the blend mode.\n//\n// Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken,\n// Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal,\n// Overlay, Saturation, Screen, SoftLight\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,\n                         FPDF_BYTESTRING blend_mode);\n\n// Set the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's stroke color.\n// G            - the green component for the object's stroke color.\n// B            - the blue component for the object's stroke color.\n// A            - the stroke alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int R,\n                           unsigned int G,\n                           unsigned int B,\n                           unsigned int A);\n\n// Get the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the path stroke color.\n// G            - the green component of the object's stroke color.\n// B            - the blue component of the object's stroke color.\n// A            - the stroke alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int* R,\n                           unsigned int* G,\n                           unsigned int* B,\n                           unsigned int* A);\n\n// Set the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width);\n\n// Get the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width);\n\n// Get the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n//\n// Returns the line join, or -1 on failure.\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object);\n\n// Set the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n// line_join    - line join\n//\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join);\n\n// Get the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line cap, or -1 on failure.\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object);\n\n// Set the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n// line_cap    - line cap\n//\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap);\n\n// Set the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's fill color.\n// G            - the green component for the object's fill color.\n// B            - the blue component for the object's fill color.\n// A            - the fill alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int R,\n                         unsigned int G,\n                         unsigned int B,\n                         unsigned int A);\n\n// Get the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the object's fill color.\n// G            - the green component of the object's fill color.\n// B            - the blue component of the object's fill color.\n// A            - the fill alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int* R,\n                         unsigned int* G,\n                         unsigned int* B,\n                         unsigned int* A);\n\n// Experimental API.\n// Get the line dash |phase| of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - pointer where the dashing phase will be stored.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase);\n\n// Experimental API.\n// Set the line dash phase of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line dash array size or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - pointer where the dashing array will be stored.\n// dash_count - number of elements in |dash_array|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,\n                         float* dash_array,\n                         size_t dash_count);\n\n// Experimental API.\n// Set the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - the dash array.\n// dash_count - number of elements in |dash_array|.\n// phase - the line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,\n                         const float* dash_array,\n                         size_t dash_count,\n                         float phase);\n\n// Get number of segments inside |path|.\n//\n//   path - handle to a path.\n//\n// A segment is a command, created by e.g. FPDFPath_MoveTo(),\n// FPDFPath_LineTo() or FPDFPath_BezierTo().\n//\n// Returns the number of objects in |path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path);\n\n// Get segment in |path| at |index|.\n//\n//   path  - handle to a path.\n//   index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index);\n\n// Get coordinates of |segment|.\n//\n//   segment  - handle to a segment.\n//   x      - the horizontal position of the segment.\n//   y      - the vertical position of the segment.\n//\n// Returns TRUE on success, otherwise |x| and |y| is not set.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y);\n\n// Get type of |segment|.\n//\n//   segment - handle to a segment.\n//\n// Returns one of the FPDF_SEGMENT_* values on success,\n// FPDF_SEGMENT_UNKNOWN on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment);\n\n// Gets if the |segment| closes the current subpath of a given path.\n//\n//   segment - handle to a segment.\n//\n// Returns close flag for non-NULL segment, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment);\n\n// Move a path's current point.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new current point.\n// y      - the vertical position of the new current point.\n//\n// Note that no line will be created between the previous current point and the\n// new one.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a line between the current point and a new point in the path.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new point.\n// y      - the vertical position of the new point.\n//\n// The path's current point is changed to (x, y).\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a cubic Bezier curve to the given path, starting at the current point.\n//\n// path   - the handle to the path object.\n// x1     - the horizontal position of the first Bezier control point.\n// y1     - the vertical position of the first Bezier control point.\n// x2     - the horizontal position of the second Bezier control point.\n// y2     - the vertical position of the second Bezier control point.\n// x3     - the horizontal position of the ending point of the Bezier curve.\n// y3     - the vertical position of the ending point of the Bezier curve.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,\n                                                      float x1,\n                                                      float y1,\n                                                      float x2,\n                                                      float y2,\n                                                      float x3,\n                                                      float y3);\n\n// Close the current subpath of a given path.\n//\n// path   - the handle to the path object.\n//\n// This will add a line between the current point and the initial point of the\n// subpath, thus terminating the current subpath.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path);\n\n// Set the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path should be stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int fillmode,\n                                                         FPDF_BOOL stroke);\n\n// Get the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path is stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int* fillmode,\n                                                         FPDF_BOOL* stroke);\n\n// Create a new text object using one of the standard PDF fonts.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewTextObj(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING font,\n                       float font_size);\n\n// Set the text for a text object. If it had text, it will be replaced.\n//\n// text_object  - handle to the text object.\n// text         - the UTF-16LE encoded string containing the text to be added.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text);\n\n// Experimental API.\n// Set the text using charcodes for a text object. If it had text, it will be\n// replaced.\n//\n// text_object  - handle to the text object.\n// charcodes    - pointer to an array of charcodes to be added.\n// count        - number of elements in |charcodes|.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,\n                      const uint32_t* charcodes,\n                      size_t count);\n\n// Returns a font object loaded from a stream of data. The font is loaded\n// into the document. Various font data structures, such as the ToUnicode data,\n// are auto-generated based on the inputs.\n//\n// document  - handle to the document.\n// data      - the stream of font data, which will be copied by the font object.\n// size      - the size of the font data, in bytes.\n// font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type.\n// cid       - a boolean specifying if the font is a CID font or not.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,\n                                                      const uint8_t* data,\n                                                      uint32_t size,\n                                                      int font_type,\n                                                      FPDF_BOOL cid);\n\n// Experimental API.\n// Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred\n// way of using font style is using a dash to separate the name from the style,\n// for example 'Helvetica-BoldItalic'.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font);\n\n// Experimental API.\n// Returns a font object loaded from a stream of data for a type 2 CID font. The\n// font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode\n// data and the CIDToGIDMap data are caller provided, instead of auto-generated.\n//\n// document                 - handle to the document.\n// font_data                - the stream of font data, which will be copied by\n//                            the font object.\n// font_data_size           - the size of the font data, in bytes.\n// to_unicode_cmap          - the ToUnicode data.\n// cid_to_gid_map_data      - the stream of CIDToGIDMap data.\n// cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadCidType2Font(FPDF_DOCUMENT document,\n                          const uint8_t* font_data,\n                          uint32_t font_data_size,\n                          FPDF_BYTESTRING to_unicode_cmap,\n                          const uint8_t* cid_to_gid_map_data,\n                          uint32_t cid_to_gid_map_data_size);\n\n// Get the font size of a text object.\n//\n//   text - handle to a text.\n//   size - pointer to the font size of the text object, measured in points\n//   (about 1/72 inch)\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size);\n\n// Close a loaded PDF font.\n//\n// font   - Handle to the loaded font.\nFPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font);\n\n// Create a new text object using a loaded font.\n//\n// document   - handle to the document.\n// font       - handle to the font object.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,\n                          FPDF_FONT font,\n                          float font_size);\n\n// Get the text rendering mode of a text object.\n//\n// text     - the handle to the text object.\n//\n// Returns one of the known FPDF_TEXT_RENDERMODE enum values on success,\n// FPDF_TEXTRENDERMODE_UNKNOWN on error.\nFPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV\nFPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Set the text rendering mode of a text object.\n//\n// text         - the handle to the text object.\n// render_mode  - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to\n//                FPDF_TEXTRENDERMODE_UNKNOWN).\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,\n                              FPDF_TEXT_RENDERMODE render_mode);\n\n// Get the text of a text object.\n//\n// text_object      - the handle to the text object.\n// text_page        - the handle to the text page.\n// buffer           - the address of a buffer that receives the text.\n// length           - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the text (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,\n                    FPDF_TEXTPAGE text_page,\n                    FPDF_WCHAR* buffer,\n                    unsigned long length);\n\n// Experimental API.\n// Get a bitmap rasterization of |text_object|. To render correctly, the caller\n// must provide the |document| associated with |text_object|. If there is a\n// |page| associated with |text_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document    - handle to a document associated with |text_object|.\n//   page        - handle to an optional page associated with |text_object|.\n//   text_object - handle to a text object.\n//   scale       - the scaling factor, which must be greater than 0.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                              FPDF_PAGE page,\n                              FPDF_PAGEOBJECT text_object,\n                              float scale);\n\n// Experimental API.\n// Get the font of a text object.\n//\n// text - the handle to the text object.\n//\n// Returns a handle to the font object held by |text| which retains ownership.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Get the base name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the base font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the base name (including the trailing NUL\n// character) on success, 0 on error. The base name is typically the font's\n// PostScript name. See descriptions of \"BaseFont\" in ISO 32000-1:2008 spec.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font,\n                                                          char* buffer,\n                                                          size_t length);\n\n// Experimental API.\n// Get the family name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the family name (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font,\n                                                        char* buffer,\n                                                        size_t length);\n\n// Experimental API.\n// Get the decoded data from the |font| object.\n//\n// font       - The handle to the font object. (Required)\n// buffer     - The address of a buffer that receives the font data.\n// buflen     - Length of the buffer.\n// out_buflen - Pointer to variable that will receive the minimum buffer size\n//              to contain the font data. Not filled if the return value is\n//              FALSE. (Required)\n//\n// Returns TRUE on success. In which case, |out_buflen| will be filled, and\n// |buffer| will be filled if it is large enough. Returns FALSE if any of the\n// required parameters are null.\n//\n// The decoded data is the uncompressed font data. i.e. the raw font data after\n// having all stream filters applied, when the data is embedded.\n//\n// If the font is not embedded, then this API will instead return the data for\n// the substitution font it is using.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font,\n                                                         uint8_t* buffer,\n                                                         size_t buflen,\n                                                         size_t* out_buflen);\n\n// Experimental API.\n// Get whether |font| is embedded or not.\n//\n// font - the handle to the font object.\n//\n// Returns 1 if the font is embedded, 0 if it not, and -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font);\n\n// Experimental API.\n// Get the descriptor flags of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the bit flags specifying various characteristics of the font as\n// defined in ISO 32000-1:2008, table 123, -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font);\n\n// Experimental API.\n// Get the font weight of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the font weight, -1 on failure.\n// Typical values are 400 (normal) and 700 (bold).\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font);\n\n// Experimental API.\n// Get the italic angle of a font.\n//\n// font  - the handle to the font object.\n// angle - pointer where the italic angle will be stored\n//\n// The italic angle of a |font| is defined as degrees counterclockwise\n// from vertical. For a font that slopes to the right, this will be negative.\n//\n// Returns TRUE on success; |angle| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font,\n                                                            int* angle);\n\n// Experimental API.\n// Get ascent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// ascent     - pointer where the font ascent will be stored\n//\n// Ascent is the maximum distance in points above the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |ascent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font,\n                                                       float font_size,\n                                                       float* ascent);\n\n// Experimental API.\n// Get descent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// descent    - pointer where the font descent will be stored\n//\n// Descent is the maximum distance in points below the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |descent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font,\n                                                        float font_size,\n                                                        float* descent);\n\n// Experimental API.\n// Get the width of a glyph in a font.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph.\n// font_size  - the size of the font.\n// width      - pointer where the glyph width will be stored\n//\n// Glyph width is the distance from the end of the prior glyph to the next\n// glyph. This will be the vertical distance for vertical writing.\n//\n// Returns TRUE on success; |width| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font,\n                                                           uint32_t glyph,\n                                                           float font_size,\n                                                           float* width);\n\n// Experimental API.\n// Get the glyphpath describing how to draw a font glyph.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph being drawn.\n// font_size  - the size of the font.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font,\n                                                               uint32_t glyph,\n                                                               float font_size);\n\n// Experimental API.\n// Get number of segments inside glyphpath.\n//\n// glyphpath - handle to a glyph path.\n//\n// Returns the number of objects in |glyphpath| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath);\n\n// Experimental API.\n// Get segment in glyphpath at index.\n//\n// glyphpath  - handle to a glyph path.\n// index      - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index);\n\n// Get number of page objects inside |form_object|.\n//\n//   form_object - handle to a form object.\n//\n// Returns the number of objects in |form_object| on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object);\n\n// Get page object in |form_object| at |index|.\n//\n//   form_object - handle to a form object.\n//   index       - the 0-based index of a page object.\n//\n// Returns the handle to the page object, or NULL on error.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index);\n\n// Experimental API.\n//\n// Remove |page_object| from |form_object|.\n//\n//   form_object - handle to a form object.\n//   page_object - handle to a page object to be removed from the form.\n//\n// Returns TRUE on success.\n//\n// Ownership of the removed |page_object| is transferred to the caller.\n// Call FPDFPageObj_Destroy() on the removed page_object to free it.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object,\n                         FPDF_PAGEOBJECT page_object);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EDIT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_ext.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EXT_H_\n#define PUBLIC_FPDF_EXT_H_\n\n#include <time.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported XFA form.\n#define FPDF_UNSP_DOC_XFAFORM 1\n// Unsupported portable collection.\n#define FPDF_UNSP_DOC_PORTABLECOLLECTION 2\n// Unsupported attachment.\n#define FPDF_UNSP_DOC_ATTACHMENT 3\n// Unsupported security.\n#define FPDF_UNSP_DOC_SECURITY 4\n// Unsupported shared review.\n#define FPDF_UNSP_DOC_SHAREDREVIEW 5\n// Unsupported shared form, acrobat.\n#define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6\n// Unsupported shared form, filesystem.\n#define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7\n// Unsupported shared form, email.\n#define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8\n// Unsupported 3D annotation.\n#define FPDF_UNSP_ANNOT_3DANNOT 11\n// Unsupported movie annotation.\n#define FPDF_UNSP_ANNOT_MOVIE 12\n// Unsupported sound annotation.\n#define FPDF_UNSP_ANNOT_SOUND 13\n// Unsupported screen media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14\n// Unsupported screen rich media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15\n// Unsupported attachment annotation.\n#define FPDF_UNSP_ANNOT_ATTACHMENT 16\n// Unsupported signature annotation.\n#define FPDF_UNSP_ANNOT_SIG 17\n\n// Interface for unsupported feature notifications.\ntypedef struct _UNSUPPORT_INFO {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Unsupported object notification function.\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis - pointer to the interface structure.\n  //   nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries.\n  void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType);\n} UNSUPPORT_INFO;\n\n// Setup an unsupported object handler.\n//\n//   unsp_info - Pointer to an UNSUPPORT_INFO structure.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info);\n\n// Set replacement function for calls to time().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of time(), or\n//          NULL to restore to actual time() call itself.\nFPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)());\n\n// Set replacement function for calls to localtime().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of localtime(), or\n//          NULL to restore to actual localtime() call itself.\nFPDF_EXPORT void FPDF_CALLCONV\nFSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*));\n\n// Unknown page mode.\n#define PAGEMODE_UNKNOWN -1\n// Document outline, and thumbnails hidden.\n#define PAGEMODE_USENONE 0\n// Document outline visible.\n#define PAGEMODE_USEOUTLINES 1\n// Thumbnail images visible.\n#define PAGEMODE_USETHUMBS 2\n// Full-screen mode, no menu bar, window controls, or other decorations visible.\n#define PAGEMODE_FULLSCREEN 3\n// Optional content group panel visible.\n#define PAGEMODE_USEOC 4\n// Attachments panel visible.\n#define PAGEMODE_USEATTACHMENTS 5\n\n// Get the document's PageMode.\n//\n//   doc - Handle to document.\n//\n// Returns one of the |PAGEMODE_*| flags defined above.\n//\n// The page mode defines how the document should be initially displayed.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EXT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_flatten.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FLATTEN_H_\n#define PUBLIC_FPDF_FLATTEN_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flatten operation failed.\n#define FLATTEN_FAIL 0\n// Flatten operation succeed.\n#define FLATTEN_SUCCESS 1\n// Nothing to be flattened.\n#define FLATTEN_NOTHINGTODO 2\n\n// Flatten for normal display.\n#define FLAT_NORMALDISPLAY 0\n// Flatten for print.\n#define FLAT_PRINT 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Flatten annotations and form fields into the page contents.\n//\n//   page  - handle to the page.\n//   nFlag - One of the |FLAT_*| values denoting the page usage.\n//\n// Returns one of the |FLATTEN_*| values.\n//\n// Currently, all failures return |FLATTEN_FAIL| with no indication of the\n// cause.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FLATTEN_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_formfill.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FORMFILL_H_\n#define PUBLIC_FPDF_FORMFILL_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n// These values are return values for a public API, so should not be changed\n// other than the count when adding new values.\n#define FORMTYPE_NONE 0            // Document contains no forms\n#define FORMTYPE_ACRO_FORM 1       // Forms are specified using AcroForm spec\n#define FORMTYPE_XFA_FULL 2        // Forms are specified using entire XFA spec\n#define FORMTYPE_XFA_FOREGROUND 3  // Forms are specified using the XFAF subset\n                                   // of XFA spec\n#define FORMTYPE_COUNT 4           // The number of form types\n\n#define JSPLATFORM_ALERT_BUTTON_OK 0           // OK button\n#define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1     // OK & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNO 2        // Yes & No buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3  // Yes, No & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK\n\n#define JSPLATFORM_ALERT_ICON_ERROR 0     // Error\n#define JSPLATFORM_ALERT_ICON_WARNING 1   // Warning\n#define JSPLATFORM_ALERT_ICON_QUESTION 2  // Question\n#define JSPLATFORM_ALERT_ICON_STATUS 3    // Status\n#define JSPLATFORM_ALERT_ICON_ASTERISK 4  // Asterisk\n#define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR\n\n#define JSPLATFORM_ALERT_RETURN_OK 1      // OK\n#define JSPLATFORM_ALERT_RETURN_CANCEL 2  // Cancel\n#define JSPLATFORM_ALERT_RETURN_NO 3      // No\n#define JSPLATFORM_ALERT_RETURN_YES 4     // Yes\n\n#define JSPLATFORM_BEEP_ERROR 0           // Error\n#define JSPLATFORM_BEEP_WARNING 1         // Warning\n#define JSPLATFORM_BEEP_QUESTION 2        // Question\n#define JSPLATFORM_BEEP_STATUS 3          // Status\n#define JSPLATFORM_BEEP_DEFAULT 4         // Default\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _IPDF_JsPlatform {\n  // Version number of the interface. Currently must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: app_alert\n  //       Pop up a dialog to show warning or hint.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       Msg         -   A string containing the message to be displayed.\n  //       Title       -   The title of the dialog.\n  //       Type        -   The type of button group, one of the\n  //                       JSPLATFORM_ALERT_BUTTON_* values above.\n  //       nIcon       -   The type of the icon, one of the\n  //                       JSPLATFORM_ALERT_ICON_* above.\n  // Return Value:\n  //       Option selected by user in dialogue, one of the\n  //       JSPLATFORM_ALERT_RETURN_* values above.\n  int (*app_alert)(struct _IPDF_JsPlatform* pThis,\n                   FPDF_WIDESTRING Msg,\n                   FPDF_WIDESTRING Title,\n                   int Type,\n                   int Icon);\n\n  // Method: app_beep\n  //       Causes the system to play a sound.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nType       -   The sound type, see JSPLATFORM_BEEP_TYPE_*\n  //                       above.\n  // Return Value:\n  //       None\n  void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType);\n\n  // Method: app_response\n  //       Displays a dialog box containing a question and an entry field for\n  //       the user to reply to the question.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       Question    -   The question to be posed to the user.\n  //       Title       -   The title of the dialog box.\n  //       Default     -   A default value for the answer to the question. If\n  //                       not specified, no default value is presented.\n  //       cLabel      -   A short string to appear in front of and on the\n  //                       same line as the edit text field.\n  //       bPassword   -   If true, indicates that the user's response should\n  //                       be shown as asterisks (*) or bullets (?) to mask\n  //                       the response, which might be sensitive information.\n  //       response    -   A string buffer allocated by PDFium, to receive the\n  //                       user's response.\n  //       length      -   The length of the buffer in bytes. Currently, it is\n  //                       always 2048.\n  // Return Value:\n  //       Number of bytes the complete user input would actually require, not\n  //       including trailing zeros, regardless of the value of the length\n  //       parameter or the presence of the response buffer.\n  // Comments:\n  //       No matter on what platform, the response buffer should be always\n  //       written using UTF-16LE encoding. If a response buffer is\n  //       present and the size of the user input exceeds the capacity of the\n  //       buffer as specified by the length parameter, only the\n  //       first \"length\" bytes of the user input are to be written to the\n  //       buffer.\n  int (*app_response)(struct _IPDF_JsPlatform* pThis,\n                      FPDF_WIDESTRING Question,\n                      FPDF_WIDESTRING Title,\n                      FPDF_WIDESTRING Default,\n                      FPDF_WIDESTRING cLabel,\n                      FPDF_BOOL bPassword,\n                      void* response,\n                      int length);\n\n  // Method: Doc_getFilePath\n  //       Get the file path of the current document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       filePath    -   The string buffer to receive the file path. Can\n  //                       be NULL.\n  //       length      -   The length of the buffer, number of bytes. Can\n  //                       be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in the local encoding.\n  //       The return value always indicated number of bytes required for\n  //       the buffer, even when there is no buffer specified, or the buffer\n  //       size is less than required. In this case, the buffer will not\n  //       be modified.\n  int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis,\n                         void* filePath,\n                         int length);\n\n  // Method: Doc_mail\n  //       Mails the data buffer as an attachment to all recipients, with or\n  //       without user interaction.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       mailData    -   Pointer to the data buffer to be sent. Can be NULL.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       mailData parameter. Can be 0.\n  //       bUI         -   If true, the rest of the parameters are used in a\n  //                       compose-new-message window that is displayed to the\n  //                       user. If false, the cTo parameter is required and\n  //                       all others are optional.\n  //       To          -   A semicolon-delimited list of recipients for the\n  //                       message.\n  //       Subject     -   The subject of the message. The length limit is\n  //                       64 KB.\n  //       CC          -   A semicolon-delimited list of CC recipients for\n  //                       the message.\n  //       BCC         -   A semicolon-delimited list of BCC recipients for\n  //                       the message.\n  //       Msg         -   The content of the message. The length limit is\n  //                       64 KB.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       If the parameter mailData is NULL or length is 0, the current\n  //       document will be mailed as an attachment to all recipients.\n  void (*Doc_mail)(struct _IPDF_JsPlatform* pThis,\n                   void* mailData,\n                   int length,\n                   FPDF_BOOL bUI,\n                   FPDF_WIDESTRING To,\n                   FPDF_WIDESTRING Subject,\n                   FPDF_WIDESTRING CC,\n                   FPDF_WIDESTRING BCC,\n                   FPDF_WIDESTRING Msg);\n\n  // Method: Doc_print\n  //       Prints all or a specific number of pages of the document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis         -   Pointer to the interface structure itself.\n  //       bUI           -   If true, will cause a UI to be presented to the\n  //                         user to obtain printing information and confirm\n  //                         the action.\n  //       nStart        -   A 0-based index that defines the start of an\n  //                         inclusive range of pages.\n  //       nEnd          -   A 0-based index that defines the end of an\n  //                         inclusive page range.\n  //       bSilent       -   If true, suppresses the cancel dialog box while\n  //                         the document is printing. The default is false.\n  //       bShrinkToFit  -   If true, the page is shrunk (if necessary) to\n  //                         fit within the imageable area of the printed page.\n  //       bPrintAsImage -   If true, print pages as an image.\n  //       bReverse      -   If true, print from nEnd to nStart.\n  //       bAnnotations  -   If true (the default), annotations are\n  //                         printed.\n  // Return Value:\n  //       None.\n  void (*Doc_print)(struct _IPDF_JsPlatform* pThis,\n                    FPDF_BOOL bUI,\n                    int nStart,\n                    int nEnd,\n                    FPDF_BOOL bSilent,\n                    FPDF_BOOL bShrinkToFit,\n                    FPDF_BOOL bPrintAsImage,\n                    FPDF_BOOL bReverse,\n                    FPDF_BOOL bAnnotations);\n\n  // Method: Doc_submitForm\n  //       Send the form data to a specified URL.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       formData    -   Pointer to the data buffer to be sent.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       formData parameter.\n  //       URL         -   The URL to send to.\n  // Return Value:\n  //       None.\n  void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis,\n                         void* formData,\n                         int length,\n                         FPDF_WIDESTRING URL);\n\n  // Method: Doc_gotoPage\n  //       Jump to a specified page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nPageNum    -   The specified page number, zero for the first page.\n  // Return Value:\n  //       None.\n  void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum);\n\n  // Method: Field_browse\n  //       Show a file selection dialog, and return the selected file path.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       filePath    -   Pointer to the data buffer to receive the file\n  //                       path. Can be NULL.\n  //       length      -   The length of the buffer, in bytes. Can be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in local encoding.\n  int (*Field_browse)(struct _IPDF_JsPlatform* pThis,\n                      void* filePath,\n                      int length);\n\n  // Pointer for embedder-specific data. Unused by PDFium, and despite\n  // its name, can be any data the embedder desires, though traditionally\n  // a FPDF_FORMFILLINFO interface.\n  void* m_pFormfillinfo;\n\n  // Version 2.\n\n  void* m_isolate;               // Unused in v3, retain for compatibility.\n  unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility.\n\n  // Version 3.\n  // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG.\n} IPDF_JSPLATFORM;\n\n// Flags for Cursor type\n#define FXCT_ARROW 0\n#define FXCT_NESW 1\n#define FXCT_NWSE 2\n#define FXCT_VBEAM 3\n#define FXCT_HBEAM 4\n#define FXCT_HAND 5\n\n// Function signature for the callback function passed to the FFI_SetTimer\n// method.\n// Parameters:\n//          idEvent     -   Identifier of the timer.\n// Return value:\n//          None.\ntypedef void (*TimerCallback)(int idEvent);\n\n// Declares of a struct type to the local system time.\ntypedef struct _FPDF_SYSTEMTIME {\n  unsigned short wYear;         // years since 1900\n  unsigned short wMonth;        // months since January - [0,11]\n  unsigned short wDayOfWeek;    // days since Sunday - [0,6]\n  unsigned short wDay;          // day of the month - [1,31]\n  unsigned short wHour;         // hours since midnight - [0,23]\n  unsigned short wMinute;       // minutes after the hour - [0,59]\n  unsigned short wSecond;       // seconds after the minute - [0,59]\n  unsigned short wMilliseconds; // milliseconds after the second - [0,999]\n} FPDF_SYSTEMTIME;\n\n#ifdef PDF_ENABLE_XFA\n\n// Pageview event flags\n#define FXFA_PAGEVIEWEVENT_POSTADDED 1    // After a new pageview is added.\n#define FXFA_PAGEVIEWEVENT_POSTREMOVED 3  // After a pageview is removed.\n\n// Definitions for Right Context Menu Features Of XFA Fields\n#define FXFA_MENU_COPY 1\n#define FXFA_MENU_CUT 2\n#define FXFA_MENU_SELECTALL 4\n#define FXFA_MENU_UNDO 8\n#define FXFA_MENU_REDO 16\n#define FXFA_MENU_PASTE 32\n\n// Definitions for File Type.\n#define FXFA_SAVEAS_XML 1\n#define FXFA_SAVEAS_XDP 2\n\n#endif  // PDF_ENABLE_XFA\n\ntypedef struct _FPDF_FORMFILLINFO {\n  // Version number of the interface.\n  // Version 1 contains stable interfaces. Version 2 has additional\n  // experimental interfaces.\n  // When PDFium is built without the XFA module, version can be 1 or 2.\n  // With version 1, only stable interfaces are called. With version 2,\n  // additional experimental interfaces are also called.\n  // When PDFium is built with the XFA module, version must be 2.\n  // All the XFA related interfaces are experimental. If PDFium is built with\n  // the XFA module and version 1 then none of the XFA related interfaces\n  // would be called. When PDFium is built with XFA module then the version\n  // must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: Release\n  //       Give the implementation a chance to release any resources after the\n  //       interface is no longer used.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Comments:\n  //       Called by PDFium during the final cleanup process.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //       None\n  void (*Release)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_Invalidate\n  //       Invalidate the client area within the specified rectangle.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage().\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       All positions are measured in PDF \"user space\".\n  //       Implementation should call FPDF_RenderPageBitmap() for repainting\n  //       the specified page area.\n  void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis,\n                         FPDF_PAGE page,\n                         double left,\n                         double top,\n                         double right,\n                         double bottom);\n\n  // Method: FFI_OutputSelectedRect\n  //       When the user selects text in form fields with the mouse, this\n  //       callback function will be invoked with the selected areas.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage()/\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       This callback function is useful for implementing special text\n  //       selection effects. An implementation should first record the\n  //       returned rectangles, then draw them one by one during the next\n  //       painting period. Lastly, it should remove all the recorded\n  //       rectangles when finished painting.\n  void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_PAGE page,\n                                 double left,\n                                 double top,\n                                 double right,\n                                 double bottom);\n\n  // Method: FFI_SetCursor\n  //       Set the Cursor shape.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nCursorType -   Cursor type, see Flags for Cursor type for details.\n  // Return value:\n  //       None.\n  void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType);\n\n  // Method: FFI_SetTimer\n  //       This method installs a system timer. An interval value is specified,\n  //       and every time that interval elapses, the system must call into the\n  //       callback function with the timer ID as returned by this function.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       uElapse     -   Specifies the time-out value, in milliseconds.\n  //       lpTimerFunc -   A pointer to the callback function-TimerCallback.\n  // Return value:\n  //       The timer identifier of the new timer if the function is successful.\n  //       An application passes this value to the FFI_KillTimer method to kill\n  //       the timer. Nonzero if it is successful; otherwise, it is zero.\n  int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis,\n                      int uElapse,\n                      TimerCallback lpTimerFunc);\n\n  // Method: FFI_KillTimer\n  //       This method uninstalls a system timer, as set by an earlier call to\n  //       FFI_SetTimer.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nTimerID    -   The timer ID returned by FFI_SetTimer function.\n  // Return value:\n  //       None.\n  void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID);\n\n  // Method: FFI_GetLocalTime\n  //       This method receives the current local time on the system.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       The local time. See FPDF_SYSTEMTIME above for details.\n  // Note: Unused.\n  FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_OnChange\n  //       This method will be invoked to notify the implementation when the\n  //       value of any FormField on the document had been changed.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       None.\n  void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_GetPage\n  //       This method receives the page handle associated with a specified\n  //       page index.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  //       nPageIndex  -   Index number of the page. 0 for the first page.\n  // Return value:\n  //       Handle to the page, as previously returned to the implementation by\n  //       FPDF_LoadPage().\n  // Comments:\n  //       The implementation is expected to keep track of the page handles it\n  //       receives from PDFium, and their mappings to page numbers. In some\n  //       cases, the document-level JavaScript action may refer to a page\n  //       which hadn't been loaded yet. To successfully run the Javascript\n  //       action, the implementation needs to load the page.\n  FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_DOCUMENT document,\n                           int nPageIndex);\n\n  // Method: FFI_GetCurrentPage\n  //       This method receives the handle to the current page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       Yes when V8 support is present, otherwise unused.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  // Return value:\n  //       Handle to the page. Returned by FPDF_LoadPage().\n  // Comments:\n  //       PDFium doesn't keep keep track of the \"current page\" (e.g. the one\n  //       that is most visible on screen), so it must ask the embedder for\n  //       this information.\n  FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_DOCUMENT document);\n\n  // Method: FFI_GetRotation\n  //       This method receives currently rotation of the page view.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to page, as returned by FPDF_LoadPage().\n  // Return value:\n  //       A number to indicate the page rotation in 90 degree increments\n  //       in a clockwise direction:\n  //         0 - 0 degrees\n  //         1 - 90 degrees\n  //         2 - 180 degrees\n  //         3 - 270 degrees\n  // Note: Unused.\n  int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page);\n\n  // Method: FFI_ExecuteNamedAction\n  //       This method will execute a named action.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       namedAction     -   A byte string which indicates the named action,\n  //                           terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the\n  //       standard named actions, but note that a document may supply any\n  //       name of its choosing.\n  void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_BYTESTRING namedAction);\n  // Method: FFI_SetTextFieldFocus\n  //       Called when a text field is getting or losing focus.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       value           -   The string value of the form field, in UTF-16LE\n  //                           format.\n  //       valueLen        -   The length of the string value. This is the\n  //                           number of characters, not bytes.\n  //       is_focus        -   True if the form field is getting focus, false\n  //                           if the form field is losing focus.\n  // Return value:\n  //       None.\n  // Comments:\n  //       Only supports text fields and combobox fields.\n  void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis,\n                                FPDF_WIDESTRING value,\n                                FPDF_DWORD valueLen,\n                                FPDF_BOOL is_focus);\n\n  // Method: FFI_DoURIAction\n  //       Ask the implementation to navigate to a uniform resource identifier.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       bsURI           -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder is version 2 or higher and have implementation for\n  //       FFI_DoURIActionWithKeyboardModifier, then\n  //       FFI_DoURIActionWithKeyboardModifier takes precedence over\n  //       FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis,\n                          FPDF_BYTESTRING bsURI);\n\n  // Method: FFI_DoGoToAction\n  //       This action changes the view to a specified destination.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       nPageIndex      -   The index of the PDF page.\n  //       zoomMode        -   The zoom mode for viewing page. See below.\n  //       fPosArray       -   The float array which carries the position info.\n  //       sizeofArray     -   The size of float array.\n  // PDFZoom values:\n  //         - XYZ = 1\n  //         - FITPAGE = 2\n  //         - FITHORZ = 3\n  //         - FITVERT = 4\n  //         - FITRECT = 5\n  //         - FITBBOX = 6\n  //         - FITBHORZ = 7\n  //         - FITBVERT = 8\n  // Return value:\n  //       None.\n  // Comments:\n  //       See the Destinations description of <<PDF Reference, version 1.7>>\n  //       in 8.2.1 for more details.\n  void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis,\n                           int nPageIndex,\n                           int zoomMode,\n                           float* fPosArray,\n                           int sizeofArray);\n\n  // Pointer to IPDF_JSPLATFORM interface.\n  // Unused if PDFium is built without V8 support. Otherwise, if NULL, then\n  // JavaScript will be prevented from executing while rendering the document.\n  IPDF_JSPLATFORM* m_pJsPlatform;\n\n  // Version 2 - Experimental.\n\n  // Whether the XFA module is disabled when built with the XFA module.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  FPDF_BOOL xfa_disabled;\n\n  // Method: FFI_DisplayCaret\n  //       This method will show the caret at specified position.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   Left position of the client area in PDF page\n  //                           coordinates.\n  //       top             -   Top position of the client area in PDF page\n  //                           coordinates.\n  //       right           -   Right position of the client area in PDF page\n  //                           coordinates.\n  //       bottom          -   Bottom position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       None.\n  void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_PAGE page,\n                           FPDF_BOOL bVisible,\n                           double left,\n                           double top,\n                           double right,\n                           double bottom);\n\n  // Method: FFI_GetCurrentPageIndex\n  //       This method will get the current page index.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  // Return value:\n  //       The index of current page.\n  int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_DOCUMENT document);\n\n  // Method: FFI_SetCurrentPage\n  //       This method will set the current page.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  //       iCurPage        -   The index of the PDF page.\n  // Return value:\n  //       None.\n  void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_DOCUMENT document,\n                             int iCurPage);\n\n // Method: FFI_GotoURL\n //       This method will navigate to the specified URL.\n // Interface Version:\n //       Ignored if |version| < 2.\n // Implementation Required:\n //       Required for XFA, otherwise set to NULL.\n // Parameters:\n //       pThis            -   Pointer to the interface structure itself.\n //       document         -   Handle to document from FPDF_LoadDocument().\n //       wsURL            -   The string value of the URL, in UTF-16LE format.\n // Return value:\n //       None.\n  void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_DOCUMENT document,\n                      FPDF_WIDESTRING wsURL);\n\n  // Method: FFI_GetPageViewRect\n  //       This method will get the current page view rectangle.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   The pointer to receive left position of the page\n  //                           view area in PDF page coordinates.\n  //       top             -   The pointer to receive top position of the page\n  //                           view area in PDF page coordinates.\n  //       right           -   The pointer to receive right position of the\n  //                           page view area in PDF page coordinates.\n  //       bottom          -   The pointer to receive bottom position of the\n  //                           page view area in PDF page coordinates.\n  // Return value:\n  //     None.\n  void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis,\n                              FPDF_PAGE page,\n                              double* left,\n                              double* top,\n                              double* right,\n                              double* bottom);\n\n  // Method: FFI_PageEvent\n  //       This method fires when pages have been added to or deleted from\n  //       the XFA document.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page_count      -   The number of pages to be added or deleted.\n  //       event_type      -   See FXFA_PAGEVIEWEVENT_* above.\n  // Return value:\n  //       None.\n  // Comments:\n  //       The pages to be added or deleted always start from the last page\n  //       of document. This means that if parameter page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been\n  //       appended to the tail of document; If page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages\n  //       have been deleted.\n  void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis,\n                        int page_count,\n                        FPDF_DWORD event_type);\n\n  // Method: FFI_PopupMenu\n  //       This method will track the right context menu for XFA fields.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       hWidget         -   Always null, exists for compatibility.\n  //       menuFlag        -   The menu flags. Please refer to macro definition\n  //                           of FXFA_MENU_XXX and this can be one or a\n  //                           combination of these macros.\n  //       x               -   X position of the client area in PDF page\n  //                           coordinates.\n  //       y               -   Y position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       TRUE indicates success; otherwise false.\n  FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_PAGE page,\n                             FPDF_WIDGET hWidget,\n                             int menuFlag,\n                             float x,\n                             float y);\n\n  // Method: FFI_OpenFile\n  //       This method will open the specified file with the specified mode.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       wsURL           -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  //       mode            -   The mode for open file, e.g. \"rb\" or \"wb\".\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis,\n                                    int fileFlag,\n                                    FPDF_WIDESTRING wsURL,\n                                    const char* mode);\n\n  // Method: FFI_EmailTo\n  //       This method will email the specified file stream to the specified\n  //       contact.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       pTo             -   A semicolon-delimited list of recipients for the\n  //                           message,in UTF-16LE format.\n  //       pSubject        -   The subject of the message,in UTF-16LE format.\n  //       pCC             -   A semicolon-delimited list of CC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pBcc            -   A semicolon-delimited list of BCC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pMsg            -   Pointer to the data buffer to be sent.Can be\n  //                           NULL,in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_FILEHANDLER* fileHandler,\n                      FPDF_WIDESTRING pTo,\n                      FPDF_WIDESTRING pSubject,\n                      FPDF_WIDESTRING pCC,\n                      FPDF_WIDESTRING pBcc,\n                      FPDF_WIDESTRING pMsg);\n\n  // Method: FFI_UploadTo\n  //       This method will upload the specified file stream to the\n  //       specified URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       uploadTo        -   Pointer to the URL path, in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis,\n                       FPDF_FILEHANDLER* fileHandler,\n                       int fileFlag,\n                       FPDF_WIDESTRING uploadTo);\n\n  // Method: FFI_GetPlatform\n  //       This method will get the current platform.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       platform        -   Pointer to the data buffer to receive the\n  //                           platform,in UTF-16LE format. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* platform,\n                         int length);\n\n  // Method: FFI_GetLanguage\n  //       This method will get the current language.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       language        -   Pointer to the data buffer to receive the\n  //                           current language. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* language,\n                         int length);\n\n  // Method: FFI_DownloadFromURL\n  //       This method will download the specified file from the URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       URL             -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                           FPDF_WIDESTRING URL);\n  // Method: FFI_PostRequestURL\n  //       This method will post the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The post data,in UTF-16LE format.\n  //       wsContentType   -   The content type of the request data, in\n  //                           UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTF-16LE format.\n  //       wsHeader        -   The request header,in UTF-16LE format.\n  //       response        -   Pointer to the FPDF_BSTR to receive the response\n  //                           data from the server, in UTF-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_WIDESTRING wsURL,\n                                  FPDF_WIDESTRING wsData,\n                                  FPDF_WIDESTRING wsContentType,\n                                  FPDF_WIDESTRING wsEncode,\n                                  FPDF_WIDESTRING wsHeader,\n                                  FPDF_BSTR* response);\n\n  // Method: FFI_PutRequestURL\n  //       This method will put the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The put data, in UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTR-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_WIDESTRING wsURL,\n                                 FPDF_WIDESTRING wsData,\n                                 FPDF_WIDESTRING wsEncode);\n\n  // Method: FFI_OnFocusChange\n  //     Called when the focused annotation is updated.\n  // Interface Version:\n  //     Ignored if |version| < 2.\n  // Implementation Required:\n  //     No\n  // Parameters:\n  //     param           -   Pointer to the interface structure itself.\n  //     annot           -   The focused annotation.\n  //     page_index      -   Index number of the page which contains the\n  //                         focused annotation. 0 for the first page.\n  // Return value:\n  //     None.\n  // Comments:\n  //     This callback function is useful for implementing any view based\n  //     action such as scrolling the annotation rect into view. The\n  //     embedder should not copy and store the annot as its scope is\n  //     limited to this call only.\n  void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param,\n                            FPDF_ANNOTATION annot,\n                            int page_index);\n\n  // Method: FFI_DoURIActionWithKeyboardModifier\n  //       Ask the implementation to navigate to a uniform resource identifier\n  //       with the specified modifiers.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       param           -   Pointer to the interface structure itself.\n  //       uri             -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  //       modifiers       -   Keyboard modifier that indicates which of\n  //                           the virtual keys are down, if any.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder who is version 2 and does not implement this API,\n  //       then a call will be redirected to FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param,\n      FPDF_BYTESTRING uri,\n      int modifiers);\n} FPDF_FORMFILLINFO;\n\n// Function: FPDFDOC_InitFormFillEnvironment\n//       Initialize form fill environment.\n// Parameters:\n//       document        -   Handle to document from FPDF_LoadDocument().\n//       formInfo        -   Pointer to a FPDF_FORMFILLINFO structure.\n// Return Value:\n//       Handle to the form fill module, or NULL on failure.\n// Comments:\n//       This function should be called before any form fill operation.\n//       The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until\n//       the returned FPDF_FORMHANDLE is closed.\nFPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV\nFPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,\n                                FPDF_FORMFILLINFO* formInfo);\n\n// Function: FPDFDOC_ExitFormFillEnvironment\n//       Take ownership of |hHandle| and exit form fill environment.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This function is a no-op when |hHandle| is null.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnAfterLoadPage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked after user successfully loaded a\n//       PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,\n                                                    FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnBeforeClosePage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked before user closes the PDF page.\n// Parameters:\n//        page        -   Handle to the page, as returned by FPDF_LoadPage().\n//        hHandle     -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//        None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page,\n                                                      FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentJSAction\n//       This method is required for performing document-level JavaScript\n//       actions. It should be invoked after the PDF document has been loaded.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       If there is document-level JavaScript action embedded in the\n//       document, this method will execute the JavaScript action. Otherwise,\n//       the method will do nothing.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentOpenAction\n//       This method is required for performing open-action when the document\n//       is opened.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there are no open-actions embedded\n//       in the document.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle);\n\n// Additional actions type of document:\n//   WC, before closing document, JavaScript action.\n//   WS, before saving document, JavaScript action.\n//   DS, after saving document, JavaScript action.\n//   WP, before printing document, JavaScript action.\n//   DP, after printing document, JavaScript action.\n#define FPDFDOC_AACTION_WC 0x10\n#define FPDFDOC_AACTION_WS 0x11\n#define FPDFDOC_AACTION_DS 0x12\n#define FPDFDOC_AACTION_WP 0x13\n#define FPDFDOC_AACTION_DP 0x14\n\n// Function: FORM_DoDocumentAAction\n//       This method is required for performing the document's\n//       additional-action.\n// Parameters:\n//       hHandle     -   Handle to the form fill module. Returned by\n//                       FPDFDOC_InitFormFillEnvironment.\n//       aaType      -   The type of the additional-actions which defined\n//                       above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there is no document\n//       additional-action corresponding to the specified |aaType|.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,\n                                                      int aaType);\n\n// Additional-action types of page object:\n//   OPEN (/O) -- An action to be performed when the page is opened\n//   CLOSE (/C) -- An action to be performed when the page is closed\n#define FPDFPAGE_AACTION_OPEN 0\n#define FPDFPAGE_AACTION_CLOSE 1\n\n// Function: FORM_DoPageAAction\n//       This method is required for performing the page object's\n//       additional-action when opened or closed.\n// Parameters:\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       aaType      -   The type of the page object's additional-actions\n//                       which defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if no additional-action corresponding\n//       to the specified |aaType| exists.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page,\n                                                  FPDF_FORMHANDLE hHandle,\n                                                  int aaType);\n\n// Function: FORM_OnMouseMove\n//       Call this member function when the mouse cursor moves.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Experimental API\n// Function: FORM_OnMouseWheel\n//       Call this member function when the user scrolls the mouse wheel.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_coord  -   Specifies the coordinates of the cursor in PDF user\n//                       space.\n//       delta_x     -   Specifies the amount of wheel movement on the x-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean left.\n//       delta_y     -   Specifies the amount of wheel movement on the y-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean down.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       For |delta_x| and |delta_y|, the caller must normalize\n//       platform-specific wheel deltas. e.g. On Windows, a delta value of 240\n//       for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines\n//       WHEEL_DELTA as 120.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel(\n    FPDF_FORMHANDLE hHandle,\n    FPDF_PAGE page,\n    int modifier,\n    const FS_POINTF* page_coord,\n    int delta_x,\n    int delta_y);\n\n// Function: FORM_OnFocus\n//       This function focuses the form annotation at a given point. If the\n//       annotation at the point already has focus, nothing happens. If there\n//       is no annotation at the point, removes form focus.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True if there is an annotation at the given point and it has focus.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int modifier,\n                                                 double page_x,\n                                                 double page_y);\n\n// Function: FORM_OnLButtonDown\n//       Call this member function when the user presses the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n\n// Function: FORM_OnRButtonDown\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n// Function: FORM_OnLButtonUp\n//       Call this member function when the user releases the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in device.\n//       page_y      -   Specifies the y-coordinate of the cursor in device.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnRButtonUp\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnLButtonDoubleClick\n//       Call this member function when the user double clicks the\n//       left mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle,\n                          FPDF_PAGE page,\n                          int modifier,\n                          double page_x,\n                          double page_y);\n\n// Function: FORM_OnKeyDown\n//       Call this member function when a nonsystem key is pressed.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, aseturned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,\n                                                   FPDF_PAGE page,\n                                                   int nKeyCode,\n                                                   int modifier);\n\n// Function: FORM_OnKeyUp\n//       Call this member function when a nonsystem key is released.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       Currently unimplemented and always returns false. PDFium reserves this\n//       API and may implement it in the future on an as-needed basis.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int nKeyCode,\n                                                 int modifier);\n\n// Function: FORM_OnChar\n//       Call this member function when a keystroke translates to a\n//       nonsystem character.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nChar       -   The character code value itself.\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle,\n                                                FPDF_PAGE page,\n                                                int nChar,\n                                                int modifier);\n\n// Experimental API\n// Function: FORM_GetFocusedText\n//       Call this function to obtain the text within the current focused\n//       field, if any.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the form text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the form text string, |buffer| is\n//                       not modified.\n// Return Value:\n//       Length in bytes for the text in the focused field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetFocusedText(FPDF_FORMHANDLE hHandle,\n                    FPDF_PAGE page,\n                    void* buffer,\n                    unsigned long buflen);\n\n// Function: FORM_GetSelectedText\n//       Call this function to obtain selected text within a form text\n//       field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the selected text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the selected text string,\n//                       |buffer| is not modified.\n// Return Value:\n//       Length in bytes of selected text in form text field or form combobox\n//       text field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetSelectedText(FPDF_FORMHANDLE hHandle,\n                     FPDF_PAGE page,\n                     void* buffer,\n                     unsigned long buflen);\n\n// Experimental API\n// Function: FORM_ReplaceAndKeepSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the inserted text\n//       will be selected.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             FPDF_WIDESTRING wsText);\n\n// Function: FORM_ReplaceSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the selection range\n//       will be set to empty.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     FPDF_WIDESTRING wsText);\n\n// Experimental API\n// Function: FORM_SelectAllText\n//       Call this function to select all the text within the currently focused\n//       form text field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       Whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page);\n\n// Function: FORM_CanUndo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to undo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_CanRedo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to redo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_Undo\n//       Make the current focused widget perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the undo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_Redo\n//       Make the current focused widget perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the redo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_ForceToKillFocus.\n//       Call this member function to force to kill the focus of the form\n//       field which has focus. If it would kill the focus of a form field,\n//       save the value of form field if was changed by theuser.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Function: FORM_GetFocusedAnnot.\n//       Call this member function to get the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page_index  -   Buffer to hold the index number of the page which\n//                       contains the focused annotation. 0 for the first page.\n//                       Can't be NULL.\n//       annot       -   Buffer to hold the focused annotation. Can't be NULL.\n// Return Value:\n//       On success, return true and write to the out parameters. Otherwise\n//       return false and leave the out parameters unmodified.\n// Comments:\n//       Not currently supported for XFA forms - will report no focused\n//       annotation.\n//       Must call FPDFPage_CloseAnnot() when the annotation returned in |annot|\n//       by this function is no longer needed.\n//       This will return true and set |page_index| to -1 and |annot| to NULL,\n//       if there is no focused annotation.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_GetFocusedAnnot(FPDF_FORMHANDLE handle,\n                     int* page_index,\n                     FPDF_ANNOTATION* annot);\n\n// Experimental API.\n// Function: FORM_SetFocusedAnnot.\n//       Call this member function to set the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       annot       -   Handle to an annotation.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus()\n//       instead.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot);\n\n// Form Field Types\n// The names of the defines are stable, but the specific values associated with\n// them are not, so do not hardcode their values.\n#define FPDF_FORMFIELD_UNKNOWN 0      // Unknown.\n#define FPDF_FORMFIELD_PUSHBUTTON 1   // push button type.\n#define FPDF_FORMFIELD_CHECKBOX 2     // check box type.\n#define FPDF_FORMFIELD_RADIOBUTTON 3  // radio button type.\n#define FPDF_FORMFIELD_COMBOBOX 4     // combo box type.\n#define FPDF_FORMFIELD_LISTBOX 5      // list box type.\n#define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.\n#define FPDF_FORMFIELD_SIGNATURE 7    // text field type.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_XFA 8              // Generic XFA type.\n#define FPDF_FORMFIELD_XFA_CHECKBOX 9     // XFA check box type.\n#define FPDF_FORMFIELD_XFA_COMBOBOX 10    // XFA combo box type.\n#define FPDF_FORMFIELD_XFA_IMAGEFIELD 11  // XFA image field type.\n#define FPDF_FORMFIELD_XFA_LISTBOX 12     // XFA list box type.\n#define FPDF_FORMFIELD_XFA_PUSHBUTTON 13  // XFA push button type.\n#define FPDF_FORMFIELD_XFA_SIGNATURE 14   // XFA signture field type.\n#define FPDF_FORMFIELD_XFA_TEXTFIELD 15   // XFA text field type.\n#endif                                    // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 16\n#else  // PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 8\n#endif  // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define IS_XFA_FORMFIELD(type)                  \\\n  (((type) == FPDF_FORMFIELD_XFA) ||            \\\n   ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \\\n   ((type) == FPDF_FORMFIELD_XFA_LISTBOX) ||    \\\n   ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \\\n   ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) ||  \\\n   ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD))\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDFPage_HasFormFieldAtPoint\n//     Get the form field type by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the type of the form field; -1 indicates no field.\n//     See field types above.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             double page_x,\n                             double page_y);\n\n// Function: FPDFPage_FormFieldZOrderAtPoint\n//     Get the form field z-order by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the z-order of the form field; -1 indicates no field.\n//     Higher numbers are closer to the front.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,\n                                FPDF_PAGE page,\n                                double page_x,\n                                double page_y);\n\n// Function: FPDF_SetFormFieldHighlightColor\n//       Set the highlight color of the specified (or all) form fields\n//       in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returned by\n//                       FPDF_LoadDocument().\n//       fieldType   -   A 32-bit integer indicating the type of a form\n//                       field (defined above).\n//       color       -   The highlight color of the form field. Constructed by\n//                       0xxxrrggbb.\n// Return Value:\n//       None.\n// Comments:\n//       When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the\n//       highlight color will be applied to all the form fields in the\n//       document.\n//       Please refresh the client window to show the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,\n                                int fieldType,\n                                unsigned long color);\n\n// Function: FPDF_SetFormFieldHighlightAlpha\n//       Set the transparency of the form field highlight color in the\n//       document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returaned by\n//                       FPDF_LoadDocument().\n//       alpha       -   The transparency of the form field highlight color,\n//                       between 0-255.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha);\n\n// Function: FPDF_RemoveFormFieldHighlight\n//       Remove the form field highlight color in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       Please refresh the client window to remove the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle);\n\n// Function: FPDF_FFLDraw\n//       Render FormFields and popup window on a page to a device independent\n//       bitmap.\n// Parameters:\n//       hHandle      -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n//       bitmap       -   Handle to the device independent bitmap (as the\n//                        output buffer). Bitmap handles can be created by\n//                        FPDFBitmap_Create().\n//       page         -   Handle to the page, as returned by FPDF_LoadPage().\n//       start_x      -   Left pixel position of the display area in the\n//                        device coordinates.\n//       start_y      -   Top pixel position of the display area in the device\n//                        coordinates.\n//       size_x       -   Horizontal size (in pixels) for displaying the page.\n//       size_y       -   Vertical size (in pixels) for displaying the page.\n//       rotate       -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                        clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                        degrees counter-clockwise).\n//       flags        -   0 for normal display, or combination of flags\n//                        defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This function is designed to render annotations that are\n//       user-interactive, which are widget annotations (for FormFields) and\n//       popup annotations.\n//       With the FPDF_ANNOT flag, this function will render a popup annotation\n//       when users mouse-hover on a non-widget annotation. Regardless of\n//       FPDF_ANNOT flag, this function will always render widget annotations\n//       for FormFields.\n//       In order to implement the FormFill functions, implementation should\n//       call this function after rendering functions, such as\n//       FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have\n//       finished rendering the page contents.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,\n                                            FPDF_BITMAP bitmap,\n                                            FPDF_PAGE page,\n                                            int start_x,\n                                            int start_y,\n                                            int size_x,\n                                            int size_y,\n                                            int rotate,\n                                            int flags);\n\n#if defined(PDF_USE_SKIA)\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,\n                                                FPDF_SKIA_CANVAS canvas,\n                                                FPDF_PAGE page,\n                                                int start_x,\n                                                int start_y,\n                                                int size_x,\n                                                int size_y,\n                                                int rotate,\n                                                int flags);\n#endif\n\n// Experimental API\n// Function: FPDF_GetFormType\n//           Returns the type of form contained in the PDF document.\n// Parameters:\n//           document - Handle to document.\n// Return Value:\n//           Integer value representing one of the FORMTYPE_ values.\n// Comments:\n//           If |document| is NULL, then the return value is FORMTYPE_NONE.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document);\n\n// Experimental API\n// Function: FORM_SetIndexSelected\n//           Selects/deselects the value at the given |index| of the focused\n//           annotation.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based index of value to be set as\n//                           selected/unselected\n//           selected    -   true to select, false to deselect\n// Return Value:\n//           TRUE if the operation succeeded.\n//           FALSE if the operation failed or widget is not a supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Comboboxes\n//           have at most a single value selected at a time which cannot be\n//           deselected. Deselect on a combobox is a no-op that returns false.\n//           Default implementation is a no-op that will return false for\n//           other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetIndexSelected(FPDF_FORMHANDLE hHandle,\n                      FPDF_PAGE page,\n                      int index,\n                      FPDF_BOOL selected);\n\n// Experimental API\n// Function: FORM_IsIndexSelected\n//           Returns whether or not the value at |index| of the focused\n//           annotation is currently selected.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based Index of value to check\n// Return Value:\n//           TRUE if value at |index| is currently selected.\n//           FALSE if value at |index| is not selected or widget is not a\n//           supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Default\n//           implementation is a no-op that will return false for other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index);\n\n// Function: FPDF_LoadXFA\n//          If the document consists of XFA fields, call this method to\n//          attempt to load XFA fields.\n// Parameters:\n//          document     -   Handle to document from FPDF_LoadDocument().\n// Return Value:\n//          TRUE upon success, otherwise FALSE. If XFA support is not built\n//          into PDFium, performs no action and always returns FALSE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_FORMFILL_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_fwlevent.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FWLEVENT_H_\n#define PUBLIC_FPDF_FWLEVENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Key flags.\ntypedef enum {\n  FWL_EVENTFLAG_ShiftKey = 1 << 0,\n  FWL_EVENTFLAG_ControlKey = 1 << 1,\n  FWL_EVENTFLAG_AltKey = 1 << 2,\n  FWL_EVENTFLAG_MetaKey = 1 << 3,\n  FWL_EVENTFLAG_KeyPad = 1 << 4,\n  FWL_EVENTFLAG_AutoRepeat = 1 << 5,\n  FWL_EVENTFLAG_LeftButtonDown = 1 << 6,\n  FWL_EVENTFLAG_MiddleButtonDown = 1 << 7,\n  FWL_EVENTFLAG_RightButtonDown = 1 << 8,\n} FWL_EVENTFLAG;\n\n// Virtual keycodes.\ntypedef enum {\n  FWL_VKEY_Back = 0x08,\n  FWL_VKEY_Tab = 0x09,\n  FWL_VKEY_NewLine = 0x0A,\n  FWL_VKEY_Clear = 0x0C,\n  FWL_VKEY_Return = 0x0D,\n  FWL_VKEY_Shift = 0x10,\n  FWL_VKEY_Control = 0x11,\n  FWL_VKEY_Menu = 0x12,\n  FWL_VKEY_Pause = 0x13,\n  FWL_VKEY_Capital = 0x14,\n  FWL_VKEY_Kana = 0x15,\n  FWL_VKEY_Hangul = 0x15,\n  FWL_VKEY_Junja = 0x17,\n  FWL_VKEY_Final = 0x18,\n  FWL_VKEY_Hanja = 0x19,\n  FWL_VKEY_Kanji = 0x19,\n  FWL_VKEY_Escape = 0x1B,\n  FWL_VKEY_Convert = 0x1C,\n  FWL_VKEY_NonConvert = 0x1D,\n  FWL_VKEY_Accept = 0x1E,\n  FWL_VKEY_ModeChange = 0x1F,\n  FWL_VKEY_Space = 0x20,\n  FWL_VKEY_Prior = 0x21,\n  FWL_VKEY_Next = 0x22,\n  FWL_VKEY_End = 0x23,\n  FWL_VKEY_Home = 0x24,\n  FWL_VKEY_Left = 0x25,\n  FWL_VKEY_Up = 0x26,\n  FWL_VKEY_Right = 0x27,\n  FWL_VKEY_Down = 0x28,\n  FWL_VKEY_Select = 0x29,\n  FWL_VKEY_Print = 0x2A,\n  FWL_VKEY_Execute = 0x2B,\n  FWL_VKEY_Snapshot = 0x2C,\n  FWL_VKEY_Insert = 0x2D,\n  FWL_VKEY_Delete = 0x2E,\n  FWL_VKEY_Help = 0x2F,\n  FWL_VKEY_0 = 0x30,\n  FWL_VKEY_1 = 0x31,\n  FWL_VKEY_2 = 0x32,\n  FWL_VKEY_3 = 0x33,\n  FWL_VKEY_4 = 0x34,\n  FWL_VKEY_5 = 0x35,\n  FWL_VKEY_6 = 0x36,\n  FWL_VKEY_7 = 0x37,\n  FWL_VKEY_8 = 0x38,\n  FWL_VKEY_9 = 0x39,\n  FWL_VKEY_A = 0x41,\n  FWL_VKEY_B = 0x42,\n  FWL_VKEY_C = 0x43,\n  FWL_VKEY_D = 0x44,\n  FWL_VKEY_E = 0x45,\n  FWL_VKEY_F = 0x46,\n  FWL_VKEY_G = 0x47,\n  FWL_VKEY_H = 0x48,\n  FWL_VKEY_I = 0x49,\n  FWL_VKEY_J = 0x4A,\n  FWL_VKEY_K = 0x4B,\n  FWL_VKEY_L = 0x4C,\n  FWL_VKEY_M = 0x4D,\n  FWL_VKEY_N = 0x4E,\n  FWL_VKEY_O = 0x4F,\n  FWL_VKEY_P = 0x50,\n  FWL_VKEY_Q = 0x51,\n  FWL_VKEY_R = 0x52,\n  FWL_VKEY_S = 0x53,\n  FWL_VKEY_T = 0x54,\n  FWL_VKEY_U = 0x55,\n  FWL_VKEY_V = 0x56,\n  FWL_VKEY_W = 0x57,\n  FWL_VKEY_X = 0x58,\n  FWL_VKEY_Y = 0x59,\n  FWL_VKEY_Z = 0x5A,\n  FWL_VKEY_LWin = 0x5B,\n  FWL_VKEY_Command = 0x5B,\n  FWL_VKEY_RWin = 0x5C,\n  FWL_VKEY_Apps = 0x5D,\n  FWL_VKEY_Sleep = 0x5F,\n  FWL_VKEY_NumPad0 = 0x60,\n  FWL_VKEY_NumPad1 = 0x61,\n  FWL_VKEY_NumPad2 = 0x62,\n  FWL_VKEY_NumPad3 = 0x63,\n  FWL_VKEY_NumPad4 = 0x64,\n  FWL_VKEY_NumPad5 = 0x65,\n  FWL_VKEY_NumPad6 = 0x66,\n  FWL_VKEY_NumPad7 = 0x67,\n  FWL_VKEY_NumPad8 = 0x68,\n  FWL_VKEY_NumPad9 = 0x69,\n  FWL_VKEY_Multiply = 0x6A,\n  FWL_VKEY_Add = 0x6B,\n  FWL_VKEY_Separator = 0x6C,\n  FWL_VKEY_Subtract = 0x6D,\n  FWL_VKEY_Decimal = 0x6E,\n  FWL_VKEY_Divide = 0x6F,\n  FWL_VKEY_F1 = 0x70,\n  FWL_VKEY_F2 = 0x71,\n  FWL_VKEY_F3 = 0x72,\n  FWL_VKEY_F4 = 0x73,\n  FWL_VKEY_F5 = 0x74,\n  FWL_VKEY_F6 = 0x75,\n  FWL_VKEY_F7 = 0x76,\n  FWL_VKEY_F8 = 0x77,\n  FWL_VKEY_F9 = 0x78,\n  FWL_VKEY_F10 = 0x79,\n  FWL_VKEY_F11 = 0x7A,\n  FWL_VKEY_F12 = 0x7B,\n  FWL_VKEY_F13 = 0x7C,\n  FWL_VKEY_F14 = 0x7D,\n  FWL_VKEY_F15 = 0x7E,\n  FWL_VKEY_F16 = 0x7F,\n  FWL_VKEY_F17 = 0x80,\n  FWL_VKEY_F18 = 0x81,\n  FWL_VKEY_F19 = 0x82,\n  FWL_VKEY_F20 = 0x83,\n  FWL_VKEY_F21 = 0x84,\n  FWL_VKEY_F22 = 0x85,\n  FWL_VKEY_F23 = 0x86,\n  FWL_VKEY_F24 = 0x87,\n  FWL_VKEY_NunLock = 0x90,\n  FWL_VKEY_Scroll = 0x91,\n  FWL_VKEY_LShift = 0xA0,\n  FWL_VKEY_RShift = 0xA1,\n  FWL_VKEY_LControl = 0xA2,\n  FWL_VKEY_RControl = 0xA3,\n  FWL_VKEY_LMenu = 0xA4,\n  FWL_VKEY_RMenu = 0xA5,\n  FWL_VKEY_BROWSER_Back = 0xA6,\n  FWL_VKEY_BROWSER_Forward = 0xA7,\n  FWL_VKEY_BROWSER_Refresh = 0xA8,\n  FWL_VKEY_BROWSER_Stop = 0xA9,\n  FWL_VKEY_BROWSER_Search = 0xAA,\n  FWL_VKEY_BROWSER_Favorites = 0xAB,\n  FWL_VKEY_BROWSER_Home = 0xAC,\n  FWL_VKEY_VOLUME_Mute = 0xAD,\n  FWL_VKEY_VOLUME_Down = 0xAE,\n  FWL_VKEY_VOLUME_Up = 0xAF,\n  FWL_VKEY_MEDIA_NEXT_Track = 0xB0,\n  FWL_VKEY_MEDIA_PREV_Track = 0xB1,\n  FWL_VKEY_MEDIA_Stop = 0xB2,\n  FWL_VKEY_MEDIA_PLAY_Pause = 0xB3,\n  FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4,\n  FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5,\n  FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6,\n  FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7,\n  FWL_VKEY_OEM_1 = 0xBA,\n  FWL_VKEY_OEM_Plus = 0xBB,\n  FWL_VKEY_OEM_Comma = 0xBC,\n  FWL_VKEY_OEM_Minus = 0xBD,\n  FWL_VKEY_OEM_Period = 0xBE,\n  FWL_VKEY_OEM_2 = 0xBF,\n  FWL_VKEY_OEM_3 = 0xC0,\n  FWL_VKEY_OEM_4 = 0xDB,\n  FWL_VKEY_OEM_5 = 0xDC,\n  FWL_VKEY_OEM_6 = 0xDD,\n  FWL_VKEY_OEM_7 = 0xDE,\n  FWL_VKEY_OEM_8 = 0xDF,\n  FWL_VKEY_OEM_102 = 0xE2,\n  FWL_VKEY_ProcessKey = 0xE5,\n  FWL_VKEY_Packet = 0xE7,\n  FWL_VKEY_Attn = 0xF6,\n  FWL_VKEY_Crsel = 0xF7,\n  FWL_VKEY_Exsel = 0xF8,\n  FWL_VKEY_Ereof = 0xF9,\n  FWL_VKEY_Play = 0xFA,\n  FWL_VKEY_Zoom = 0xFB,\n  FWL_VKEY_NoName = 0xFC,\n  FWL_VKEY_PA1 = 0xFD,\n  FWL_VKEY_OEM_Clear = 0xFE,\n  FWL_VKEY_Unknown = 0,\n} FWL_VKEYCODE;\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FWLEVENT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_javascript.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_JAVASCRIPT_H_\n#define PUBLIC_FPDF_JAVASCRIPT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of JavaScript actions in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of JavaScript actions in |document| or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the JavaScript action at |index| in |document|.\n//\n//   document - handle to a document.\n//   index    - the index of the requested JavaScript action.\n//\n// Returns the handle to the JavaScript action, or NULL on failure.\n// Caller owns the returned handle and must close it with\n// FPDFDoc_CloseJavaScriptAction().\nFPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV\nFPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Close a loaded FPDF_JAVASCRIPT_ACTION object.\n\n//   javascript - Handle to a JavaScript action.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript);\n\n// Experimental API.\n// Get the name from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the name. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript,\n                             FPDF_WCHAR* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Get the script from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the script. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript,\n                               FPDF_WCHAR* buffer,\n                               unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_JAVASCRIPT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_ppo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PPO_H_\n#define PUBLIC_FPDF_PPO_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc     - The destination document for the pages.\n//   src_doc      - The document to be imported.\n//   page_indices - An array of page indices to be imported. The first page is\n//                  zero. If |page_indices| is NULL, all pages from |src_doc|\n//                  are imported.\n//   length       - The length of the |page_indices| array.\n//   index        - The page index at which to insert the first imported page\n//                  into |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |page_indices| is\n// invalid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        const int* page_indices,\n                        unsigned long length,\n                        int index);\n\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc  - The destination document for the pages.\n//   src_doc   - The document to be imported.\n//   pagerange - A page range string, Such as \"1,3,5-7\". The first page is one.\n//               If |pagerange| is NULL, all pages from |src_doc| are imported.\n//   index     - The page index at which to insert the first imported page into\n//               |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |pagerange| is\n// invalid or if |pagerange| cannot be read.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,\n                                                     FPDF_DOCUMENT src_doc,\n                                                     FPDF_BYTESTRING pagerange,\n                                                     int index);\n\n// Experimental API.\n// Create a new document from |src_doc|.  The pages of |src_doc| will be\n// combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per\n// |output_doc| page.\n//\n//   src_doc             - The document to be imported.\n//   output_width        - The output page width in PDF \"user space\" units.\n//   output_height       - The output page height in PDF \"user space\" units.\n//   num_pages_on_x_axis - The number of pages on X Axis.\n//   num_pages_on_y_axis - The number of pages on Y Axis.\n//\n// Return value:\n//   A handle to the created document, or NULL on failure.\n//\n// Comments:\n//   number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis\n//\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,\n                       float output_width,\n                       float output_height,\n                       size_t num_pages_on_x_axis,\n                       size_t num_pages_on_y_axis);\n\n// Experimental API.\n// Create a template to generate form xobjects from |src_doc|'s page at\n// |src_page_index|, for use in |dest_doc|.\n//\n// Returns a handle on success, or NULL on failure. Caller owns the newly\n// created object.\nFPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV\nFPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        int src_page_index);\n\n// Experimental API.\n// Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage().\n// FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject);\n\n// Experimental API.\n// Create a new form object from an FPDF_XOBJECT object.\n//\n// Returns a new form object on success, or NULL on failure. Caller owns the\n// newly created object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject);\n\n// Copy the viewer preferences from |src_doc| into |dest_doc|.\n//\n//   dest_doc - Document to write the viewer preferences into.\n//   src_doc  - Document to read the viewer preferences from.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_PPO_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_progressive.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PROGRESSIVE_H_\n#define PUBLIC_FPDF_PROGRESSIVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flags for progressive process status.\n#define FPDF_RENDER_READY 0\n#define FPDF_RENDER_TOBECONTINUED 1\n#define FPDF_RENDER_DONE 2\n#define FPDF_RENDER_FAILED 3\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// IFPDF_RENDERINFO interface.\ntypedef struct _IFSDK_PAUSE {\n  // Version number of the interface. Currently must be 1.\n  int version;\n\n  // Method: NeedToPauseNow\n  //           Check if we need to pause a progressive process now.\n  // Interface Version:\n  //           1\n  // Implementation Required:\n  //           yes\n  // Parameters:\n  //           pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //           Non-zero for pause now, 0 for continue.\n  FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis);\n\n  // A user defined data pointer, used by user's application. Can be NULL.\n  void* user;\n} IFSDK_PAUSE;\n\n// Experimental API.\n// Function: FPDF_RenderPageBitmapWithColorScheme_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively with a specified color scheme for the content.\n// Parameters:\n//          bitmap       -   Handle to the device independent bitmap (as the\n//                           output buffer). Bitmap handle can be created by\n//                           FPDFBitmap_Create function.\n//          page         -   Handle to the page as returned by FPDF_LoadPage\n//                           function.\n//          start_x      -   Left pixel position of the display area in the\n//                           bitmap coordinate.\n//          start_y      -   Top pixel position of the display area in the\n//                           bitmap coordinate.\n//          size_x       -   Horizontal size (in pixels) for displaying the\n//                           page.\n//          size_y       -   Vertical size (in pixels) for displaying the page.\n//          rotate       -   Page orientation: 0 (normal), 1 (rotated 90\n//                           degrees clockwise), 2 (rotated 180 degrees),\n//                           3 (rotated 90 degrees counter-clockwise).\n//          flags        -   0 for normal display, or combination of flags\n//                           defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                           renders all annotations that does not require\n//                           user-interaction, which are all annotations except\n//                           widget and popup annotations.\n//          color_scheme -   Color scheme to be used in rendering the |page|.\n//                           If null, this function will work similar to\n//                           FPDF_RenderPageBitmap_Start().\n//          pause        -   The IFSDK_PAUSE interface. A callback mechanism\n//                           allowing the page rendering process.\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap,\n                                           FPDF_PAGE page,\n                                           int start_x,\n                                           int start_y,\n                                           int size_x,\n                                           int size_y,\n                                           int rotate,\n                                           int flags,\n                                           const FPDF_COLORSCHEME* color_scheme,\n                                           IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPageBitmap_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). Bitmap handle can be created by\n//                          FPDFBitmap_Create().\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          start_x     -   Left pixel position of the display area in the\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in the bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                          clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                          degrees counter-clockwise).\n//          flags       -   0 for normal display, or combination of flags\n//                          defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                          renders all annotations that does not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n//          pause       -   The IFSDK_PAUSE interface.A callback mechanism\n//                          allowing the page rendering process\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,\n                                                          FPDF_PAGE page,\n                                                          int start_x,\n                                                          int start_y,\n                                                          int size_x,\n                                                          int size_y,\n                                                          int rotate,\n                                                          int flags,\n                                                          IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Continue\n//          Continue rendering a PDF page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          pause       -   The IFSDK_PAUSE interface (a callback mechanism\n//                          allowing the page rendering process to be paused\n//                          before it's finished). This can be NULL if you\n//                          don't want to pause.\n// Return value:\n//          The rendering status. See flags for progressive process status for\n//          the details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page,\n                                                       IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Close\n//          Release the resource allocate during page rendering. Need to be\n//          called after finishing rendering or\n//          cancel the rendering.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_PROGRESSIVE_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_save.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SAVE_H_\n#define PUBLIC_FPDF_SAVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Structure for custom file write\ntypedef struct FPDF_FILEWRITE_ {\n  //\n  // Version number of the interface. Currently must be 1.\n  //\n  int version;\n\n  // Method: WriteBlock\n  //          Output a block of data in your custom way.\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          Yes\n  // Comments:\n  //          Called by function FPDF_SaveDocument\n  // Parameters:\n  //          self        -   Pointer to the structure itself\n  //          data        -   Pointer to a buffer to output\n  //          size        -   The size of the buffer.\n  // Return value:\n  //          Should be non-zero if successful, zero for error.\n  int (*WriteBlock)(struct FPDF_FILEWRITE_* self,\n                    const void* data,\n                    unsigned long size);\n} FPDF_FILEWRITE;\n\n// Flags for FPDF_SaveAsCopy().\n// FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together.\n#define FPDF_INCREMENTAL (1 << 0)\n#define FPDF_NO_INCREMENTAL (1 << 1)\n // Deprecated. Use FPDF_REMOVE_SECURITY instead.\n // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED.\n#define FPDF_REMOVE_SECURITY_DEPRECATED 3\n#define FPDF_REMOVE_SECURITY (1 << 2)\n// Experimental. Subsets any embedded font files for new text objects added to\n// the document.\n#define FPDF_SUBSET_NEW_FONTS (1 << 3)\n\n// Function: FPDF_SaveAsCopy\n//          Saves the copy of specified document in custom way.\n// Parameters:\n//          document        -   Handle to document, as returned by\n//                              FPDF_LoadDocument() or FPDF_CreateNewDocument().\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   Flags above that affect how the PDF gets saved.\n//                              Pass in 0 when there are no flags.\n// Return value:\n//          TRUE for succeed, FALSE for failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,\n                                                    FPDF_FILEWRITE* file_write,\n                                                    FPDF_DWORD flags);\n\n// Function: FPDF_SaveWithVersion\n//          Same as FPDF_SaveAsCopy(), except the file version of the\n//          saved document can be specified by the caller.\n// Parameters:\n//          document        -   Handle to document.\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   The creating flags.\n//          file_version    -   The PDF file version. File version: 14 for 1.4,\n//                              15 for 1.5, ...\n// Return value:\n//          TRUE if succeed, FALSE if failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_SaveWithVersion(FPDF_DOCUMENT document,\n                     FPDF_FILEWRITE* file_write,\n                     FPDF_DWORD flags,\n                     int file_version);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SAVE_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_searchex.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SEARCHEX_H_\n#define PUBLIC_FPDF_SEARCHEX_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Get the character index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nTextIndex - index of the text returned from FPDFText_GetText().\n//\n// Returns the index of the character in internal character list. -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex);\n\n// Get the text index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nCharIndex - index of the character in internal character list.\n//\n// Returns the index of the text returned from FPDFText_GetText(). -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SEARCHEX_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_signature.h",
    "content": "// Copyright 2020 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_SIGNATURE_H_\n#define PUBLIC_FPDF_SIGNATURE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Function: FPDF_GetSignatureCount\n//          Get total number of signatures in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n// Return value:\n//          Total number of signatures in the document on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetSignatureObject\n//          Get the Nth signature of the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          index       -   Index into the array of signatures of the document.\n// Return value:\n//          Returns the handle to the signature, or NULL on failure. The caller\n//          does not take ownership of the returned FPDF_SIGNATURE. Instead, it\n//          remains valid until FPDF_CloseDocument() is called for the document.\nFPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV\nFPDF_GetSignatureObject(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetContents\n//          Get the contents of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the contents.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the contents on success, 0 on error.\n//\n// For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or\n// a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetContents(FPDF_SIGNATURE signature,\n                             void* buffer,\n                             unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetByteRange\n//          Get the byte range of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the\n//                          byte range.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the byte range on\n//          success, 0 on error.\n//\n// |buffer| is an array of pairs of integers (starting byte offset,\n// length in bytes) that describes the exact byte range for the digest\n// calculation. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,\n                              int* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetSubFilter\n//          Get the encoding of the value of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the encoding.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature,\n                              char* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetReason\n//          Get the reason (comment) of the signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the reason.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the reason on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetReason(FPDF_SIGNATURE signature,\n                           void* buffer,\n                           unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetTime\n//          Get the time of signing of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the time.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's\n// percision is seconds, with timezone information. This value should be used\n// only when the time of signing is not available in the (PKCS#7 binary)\n// signature.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetTime(FPDF_SIGNATURE signature,\n                         char* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetDocMDPPermission\n//          Get the DocMDP permission of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n// Return value:\n//          Returns the permission (1, 2 or 3) on success, 0 on error.\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SIGNATURE_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_structtree.h",
    "content": "// Copyright 2016 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_STRUCTTREE_H_\n#define PUBLIC_FPDF_STRUCTTREE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDF_StructTree_GetForPage\n//          Get the structure tree for a page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          A handle to the structure tree or NULL on error. The caller owns the\n//          returned handle and must use FPDF_StructTree_Close() to release it.\n//          The handle should be released before |page| gets released.\nFPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV\nFPDF_StructTree_GetForPage(FPDF_PAGE page);\n\n// Function: FPDF_StructTree_Close\n//          Release a resource allocated by FPDF_StructTree_GetForPage().\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_CountChildren\n//          Count the number of children for the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_GetChildAtIndex\n//          Get a child in the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n//          index       -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error. The caller does not\n//          own the handle. The handle remains valid as long as |struct_tree|\n//          remains valid.\n// Comments:\n//          The |index| must be less than the FPDF_StructTree_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index);\n\n// Function: FPDF_StructElement_GetAltText\n//          Get the alt text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the alt text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the alt text, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetActualText\n//          Get the actual text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the actual text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the actual text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetExpansion\n//          Get the expansion of an abbreviation or acronym for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the expansion text. May be\n//                             NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the expansion text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element,\n                                void* buffer,\n                                unsigned long buflen);\n\n// Function: FPDF_StructElement_GetID\n//          Get the ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the ID string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,\n                         void* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetLang\n//          Get the case-insensitive IETF BCP 47 language code for an element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the lang string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetStringAttribute\n//          Get a struct element attribute of type \"name\" or \"string\".\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          attr_name      -   The name of the attribute to retrieve.\n//          buffer         -   A buffer for output. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the attribute value, including the\n//          terminating NUL character. The number of bytes is returned\n//          regardless of the |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,\n                                      FPDF_BYTESTRING attr_name,\n                                      void* buffer,\n                                      unsigned long buflen);\n\n// Function: FPDF_StructElement_GetMarkedContentID\n//          Get the marked content ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to\n//          extract more marked content IDs out of |struct_element|. This API\n//          may be deprecated in the future.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetType\n//           Get the type (/S) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the type, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetObjType\n//           Get the object type (/Type) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the object type, including the terminating\n//           NUL character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Function: FPDF_StructElement_GetTitle\n//           Get the title (/T) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the title, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Function: FPDF_StructElement_CountChildren\n//          Count the number of children for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetChildAtIndex\n//          Get a child in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error.\n// Comments:\n//          If the child exists but is not an element, then this function will\n//          return NULL. This will also return NULL for out of bounds indices.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                   int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetChildMarkedContentID\n//          Get the child's content id\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The marked content ID of the child. If no ID exists, returns -1.\n// Comments:\n//          If the child exists but is not a stream or object, then this\n//          function will return -1. This will also return -1 for out of bounds\n//          indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex,\n//          it is scoped to the current page.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element,\n                                           int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetParent\n//          Get the parent of the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The parent structure element or NULL on error.\n// Comments:\n//          If structure element is StructTreeRoot, then this function will\n//          return NULL.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetAttributeCount\n//          Count the number of attributes for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetAttributeAtIndex\n//          Get an attribute object in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the attribute object, 0-based.\n// Return value:\n//          The attribute object at the n-th index or NULL on error.\n// Comments:\n//          If the attribute object exists but is not a dict, then this\n//          function will return NULL. This will also return NULL for out of\n//          bounds indices. The caller does not own the handle. The handle\n//          remains valid as long as |struct_element| remains valid.\n//          The |index| must be less than the\n//          FPDF_StructElement_GetAttributeCount() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV\nFPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetCount\n//          Count the number of attributes in a structure element attribute map.\n// Parameters:\n//          struct_attribute - Handle to the struct element attribute.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute);\n\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetName\n//          Get the name of an attribute in a structure element attribute map.\n// Parameters:\n//          struct_attribute   - Handle to the struct element attribute.\n//          index              - The index of attribute in the map.\n//          buffer             - A buffer for output. May be NULL. This is only\n//                               modified if |buflen| is longer than the length\n//                               of the key. Optional, pass null to just\n//                               retrieve the size of the buffer needed.\n//          buflen             - The length of the buffer.\n//          out_buflen         - A pointer to variable that will receive the\n//                               minimum buffer size to contain the key. Not\n//                               filled if FALSE is returned.\n// Return value:\n//          TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                int index,\n                                void* buffer,\n                                unsigned long buflen,\n                                unsigned long* out_buflen);\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetValue\n//           Get a handle to a value for an attribute in a structure element\n//           attribute map.\n// Parameters:\n//           struct_attribute   - Handle to the struct element attribute.\n//           name               - The attribute name.\n// Return value:\n//           Returns a handle to the value associated with the input, if any.\n//           Returns NULL on failure. The caller does not own the handle.\n//           The handle remains valid as long as |struct_attribute| remains\n//           valid.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                 FPDF_BYTESTRING name);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetType\n//           Get the type of an attribute in a structure element attribute map.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of\n//           failure. Note that this will never return FPDF_OBJECT_REFERENCE, as\n//           references are always dereferenced.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBooleanValue\n//           Get the value of a boolean attribute in an attribute map as\n//           FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_BOOLEAN for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a boolean value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        FPDF_BOOL* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetNumberValue\n//           Get the value of a number attribute in an attribute map as float.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_NUMBER for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a number value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       float* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetStringValue\n//           Get the value of a string attribute in an attribute map as string.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned key in UTF-16LE.\n//                        This is only modified if |buflen| is longer than the\n//                        length of the key. Optional, pass null to just\n//                        retrieve the size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       void* buffer,\n                                       unsigned long buflen,\n                                       unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBlobValue\n//           Get the value of a blob attribute in an attribute map as string.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned value. This is only\n//                        modified if |buflen| is at least as long as the length\n//                        of the value. Optional, pass null to just retrieve the\n//                        size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                     void* buffer,\n                                     unsigned long buflen,\n                                     unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_CountChildren\n//           Count the number of children values in an attribute.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetChildAtIndex\n//           Get a child from an attribute.\n// Parameters:\n//           value - Handle to the value.\n//           index - The index for the child, 0-based.\n// Return value:\n//           The child at the n-th index or NULL on error.\n// Comments:\n//           The |index| must be less than the\n//           FPDF_StructElement_Attr_CountChildren() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdCount\n//          Get the count of marked content ids for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The count of marked content ids or -1 if none exists.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdAtIndex\n//          Get the marked content id at a given index for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index of the marked content id, 0-based.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          The |index| must be less than the\n//          FPDF_StructElement_GetMarkedContentIdCount() return value.\n//          This will likely supersede FPDF_StructElement_GetMarkedContentID().\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                             int index);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n#endif  // PUBLIC_FPDF_STRUCTTREE_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_sysfontinfo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SYSFONTINFO_H_\n#define PUBLIC_FPDF_SYSFONTINFO_H_\n\n#include <stddef.h>\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Character sets for the font\n#define FXFONT_ANSI_CHARSET 0\n#define FXFONT_DEFAULT_CHARSET 1\n#define FXFONT_SYMBOL_CHARSET 2\n#define FXFONT_SHIFTJIS_CHARSET 128\n#define FXFONT_HANGEUL_CHARSET 129\n#define FXFONT_GB2312_CHARSET 134\n#define FXFONT_CHINESEBIG5_CHARSET 136\n#define FXFONT_GREEK_CHARSET 161\n#define FXFONT_VIETNAMESE_CHARSET 163\n#define FXFONT_HEBREW_CHARSET 177\n#define FXFONT_ARABIC_CHARSET 178\n#define FXFONT_CYRILLIC_CHARSET 204\n#define FXFONT_THAI_CHARSET 222\n#define FXFONT_EASTERNEUROPEAN_CHARSET 238\n\n// Font pitch and family flags\n#define FXFONT_FF_FIXEDPITCH (1 << 0)\n#define FXFONT_FF_ROMAN (1 << 4)\n#define FXFONT_FF_SCRIPT (4 << 4)\n\n// Typical weight values\n#define FXFONT_FW_NORMAL 400\n#define FXFONT_FW_BOLD 700\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Interface: FPDF_SYSFONTINFO\n//          Interface for getting system font information and font mapping\ntypedef struct _FPDF_SYSFONTINFO {\n  // Version number of the interface. Currently must be 1 or 2.\n  // Version 1: Traditional behavior - calls EnumFonts during initialization.\n  // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont.\n  //            Experimental: Subject to change based on feedback.\n  int version;\n\n  // Method: Release\n  //          Give implementation a chance to release any data after the\n  //          interface is no longer used.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //          None\n  // Comments:\n  //          Called by PDFium during the final cleanup process.\n  void (*Release)(struct _FPDF_SYSFONTINFO* pThis);\n\n  // Method: EnumFonts\n  //          Enumerate all fonts installed on the system\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          pMapper     -   An opaque pointer to internal font mapper, used\n  //                          when calling FPDF_AddInstalledFont().\n  // Return Value:\n  //          None\n  // Comments:\n  //          Implementations should call FPDF_AddInstalledFont() function for\n  //          each font found. Only TrueType/OpenType and Type1 fonts are\n  //          accepted by PDFium.\n  //          NOTE: This method will not be called when version is set to 2.\n  //          Version 2 relies entirely on MapFont() for per-request matching.\n  void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper);\n\n  // Method: MapFont\n  //          Use the system font mapper to get a font handle from requested\n  //          parameters.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if GetFont method is not implemented.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          weight      -   Weight of the requested font. 400 is normal and\n  //                          700 is bold.\n  //          bItalic     -   Italic option of the requested font, TRUE or\n  //                          FALSE.\n  //          charset     -   Character set identifier for the requested font.\n  //                          See above defined constants.\n  //          pitch_family -  A combination of flags. See above defined\n  //                          constants.\n  //          face        -   Typeface name. Currently use system local encoding\n  //                          only.\n  //          bExact      -   Obsolete: this parameter is now ignored.\n  // Return Value:\n  //          An opaque pointer for font handle, or NULL if system mapping is\n  //          not supported.\n  // Comments:\n  //          If the system supports native font mapper (like Windows),\n  //          implementation can implement this method to get a font handle.\n  //          Otherwise, PDFium will do the mapping and then call GetFont\n  //          method. Only TrueType/OpenType and Type1 fonts are accepted\n  //          by PDFium.\n  void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis,\n                   int weight,\n                   FPDF_BOOL bItalic,\n                   int charset,\n                   int pitch_family,\n                   const char* face,\n                   FPDF_BOOL* bExact);\n\n  // Method: GetFont\n  //          Get a handle to a particular font by its internal ID\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if MapFont method is not implemented.\n  // Return Value:\n  //          An opaque pointer for font handle.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          face        -   Typeface name in system local encoding.\n  // Comments:\n  //          If the system mapping not supported, PDFium will do the font\n  //          mapping and use this method to get a font handle.\n  void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face);\n\n  // Method: GetFontData\n  //          Get font data from a font\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          table       -   TrueType/OpenType table identifier (refer to\n  //                          TrueType specification), or 0 for the whole file.\n  //          buffer      -   The buffer receiving the font data. Can be NULL if\n  //                          not provided.\n  //          buf_size    -   Buffer size, can be zero if not provided.\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  // Comments:\n  //          Can read either the full font file, or a particular\n  //          TrueType/OpenType table.\n  unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               unsigned int table,\n                               unsigned char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFaceName\n  //          Get face name from a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          buffer      -   The buffer receiving the face name. Can be NULL if\n  //                          not provided\n  //          buf_size    -   Buffer size, can be zero if not provided\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFontCharset\n  //          Get character set information for a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          Character set identifier. See defined constants above.\n  int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n\n  // Method: DeleteFont\n  //          Delete a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          None\n  void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n} FPDF_SYSFONTINFO;\n\n// Struct: FPDF_CharsetFontMap\n//    Provides the name of a font to use for a given charset value.\ntypedef struct FPDF_CharsetFontMap_ {\n  int charset;  // Character Set Enum value, see FXFONT_*_CHARSET above.\n  const char* fontname;  // Name of default font to use with that charset.\n} FPDF_CharsetFontMap;\n\n// Function: FPDF_GetDefaultTTFMap\n//    Returns a pointer to the default character set to TT Font name map. The\n//    map is an array of FPDF_CharsetFontMap structs, with its end indicated\n//    by a { -1, NULL } entry.\n// Parameters:\n//     None.\n// Return Value:\n//     Pointer to the Charset Font Map.\n// Note:\n//     Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no\n//     longer experimental, this API will be marked as deprecated.\n//     See https://crbug.com/348468114\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapCount\n//    Returns the number of entries in the default character set to TT Font name\n//    map.\n// Parameters:\n//    None.\n// Return Value:\n//    The number of entries in the map.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapEntry\n//    Returns an entry in the default character set to TT Font name map.\n// Parameters:\n//    index    -   The index to the entry in the map to retrieve.\n// Return Value:\n//     A pointer to the entry, if it is in the map, or NULL if the index is out\n//     of bounds.\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV\nFPDF_GetDefaultTTFMapEntry(size_t index);\n\n// Function: FPDF_AddInstalledFont\n//          Add a system font to the list in PDFium.\n// Comments:\n//          This function is only called during the system font list building\n//          process.\n// Parameters:\n//          mapper          -   Opaque pointer to Foxit font mapper\n//          face            -   The font face name\n//          charset         -   Font character set. See above defined constants.\n// Return Value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper,\n                                                     const char* face,\n                                                     int charset);\n\n// Function: FPDF_SetSystemFontInfo\n//          Set the system font info interface into PDFium\n// Parameters:\n//          font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//          None\n// Comments:\n//          Platform support implementation should implement required methods of\n//          FFDF_SYSFONTINFO interface, then call this function during PDFium\n//          initialization process.\n//\n//          Call this with NULL to tell PDFium to stop using a previously set\n//          |FPDF_SYSFONTINFO|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n// Function: FPDF_GetDefaultSystemFontInfo\n//          Get default system font info interface for current platform\n// Parameters:\n//          None\n// Return Value:\n//          Pointer to a FPDF_SYSFONTINFO structure describing the default\n//          interface, or NULL if the platform doesn't have a default interface.\n//          Application should call FPDF_FreeDefaultSystemFontInfo to free the\n//          returned pointer.\n// Comments:\n//          For some platforms, PDFium implements a default version of system\n//          font info interface. The default implementation can be passed to\n//          FPDF_SetSystemFontInfo().\nFPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo();\n\n// Function: FPDF_FreeDefaultSystemFontInfo\n//           Free a default system font info interface\n// Parameters:\n//           font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//           None\n// Comments:\n//           This function should be called on the output from\n//           FPDF_GetDefaultSystemFontInfo() once it is no longer needed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SYSFONTINFO_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_text.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TEXT_H_\n#define PUBLIC_FPDF_TEXT_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDFText_LoadPage\n//          Prepare information about all characters in a page.\n// Parameters:\n//          page    -   Handle to the page. Returned by FPDF_LoadPage function\n//                      (in FPDFVIEW module).\n// Return value:\n//          A handle to the text page information structure.\n//          NULL if something goes wrong.\n// Comments:\n//          Application must call FPDFText_ClosePage to release the text page\n//          information.\n//\nFPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page);\n\n// Function: FPDFText_ClosePage\n//          Release all resources allocated for a text page information\n//          structure.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_CountChars\n//          Get number of characters in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return value:\n//          Number of characters in the page. Return -1 for error.\n//          Generated characters, like additional space characters, new line\n//          characters, are also counted.\n// Comments:\n//          Characters in a page form a \"stream\", inside the stream, each\n//          character has an index.\n//          We will use the index parameters in many of FPDFTEXT functions. The\n//          first character in the page\n//          has an index value of zero.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_GetUnicode\n//          Get Unicode of a character in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The Unicode of the particular character.\n//          If a character is not encoded in Unicode and Foxit engine can't\n//          convert to Unicode,\n//          the return value will be zero.\n//\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_GetTextObject\n//          Get the FPDF_PAGEOBJECT associated with a given character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The associated text object for the character at |index|, or NULL on\n//          error. The returned text object, if non-null, is of type\n//          |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object.\n//\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsGenerated\n//          Get if a character in a page is generated by PDFium.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is generated by PDFium.\n//          0 if the character is not generated by PDFium.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsHyphen\n//          Get if a character in a page is a hyphen.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is a hyphen.\n//          0 if the character is not a hyphen.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_HasUnicodeMapError\n//          Get if a character in a page has an invalid unicode mapping.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character has an invalid unicode mapping.\n//          0 if the character has no known unicode mapping issues.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index);\n\n// Function: FPDFText_GetFontSize\n//          Get the font size of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The font size of the particular character, measured in points (about\n//          1/72 inch). This is the typographic size of the font (so called\n//          \"em size\").\n//\nFPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Experimental API.\n// Function: FPDFText_GetFontInfo\n//          Get the font name and flags of a particular character.\n// Parameters:\n//          text_page - Handle to a text page information structure.\n//                      Returned by FPDFText_LoadPage function.\n//          index     - Zero-based index of the character.\n//          buffer    - A buffer receiving the font name.\n//          buflen    - The length of |buffer| in bytes.\n//          flags     - Optional pointer to an int receiving the font flags.\n//                      These flags should be interpreted per PDF spec 1.7\n//                      Section 5.7.1 Font Descriptor Flags.\n// Return value:\n//          On success, return the length of the font name, including the\n//          trailing NUL character, in bytes. If this length is less than or\n//          equal to |length|, |buffer| is set to the font name, |flags| is\n//          set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on\n//          failure.\n//\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,\n                     int index,\n                     void* buffer,\n                     unsigned long buflen,\n                     int* flags);\n\n// Experimental API.\n// Function: FPDFText_GetFontWeight\n//          Get the font weight of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          On success, return the font weight of the particular character. If\n//          |text_page| is invalid, if |index| is out of bounds, or if the\n//          character's text object is undefined, return -1.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,\n                                                     int index);\n\n// Experimental API.\n// Function: FPDFText_GetFillColor\n//          Get the fill color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the fill color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the fill color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the fill color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the fill color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetFillColor(FPDF_TEXTPAGE text_page,\n                      int index,\n                      unsigned int* R,\n                      unsigned int* G,\n                      unsigned int* B,\n                      unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetStrokeColor\n//          Get the stroke color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the stroke color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the stroke color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the stroke color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the stroke color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,\n                        int index,\n                        unsigned int* R,\n                        unsigned int* G,\n                        unsigned int* B,\n                        unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetCharAngle\n//          Get character rotation angle.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return Value:\n//          On success, return the angle value in radian. Value will always be\n//          greater or equal to 0. If |text_page| is invalid, or if |index| is\n//          out of bounds, then return -1.\n//\nFPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Function: FPDFText_GetCharBox\n//          Get bounding box of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          left        -   Pointer to a double number receiving left position\n//                          of the character box.\n//          right       -   Pointer to a double number receiving right position\n//                          of the character box.\n//          bottom      -   Pointer to a double number receiving bottom position\n//                          of the character box.\n//          top         -   Pointer to a double number receiving top position of\n//                          the character box.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |right|, |bottom|, and\n//          |top|. If |text_page| is invalid, or if |index| is out of bounds,\n//          then return FALSE, and the out parameters remain unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,\n                                                        int index,\n                                                        double* left,\n                                                        double* right,\n                                                        double* bottom,\n                                                        double* top);\n\n// Experimental API.\n// Function: FPDFText_GetLooseCharBox\n//          Get a \"loose\" bounding box of a particular character, i.e., covering\n//          the entire glyph bounds, without taking the actual glyph shape into\n//          account.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          rect        -   Pointer to a FS_RECTF receiving the character box.\n// Return Value:\n//          On success, return TRUE and fill in |rect|. If |text_page| is\n//          invalid, or if |index| is out of bounds, then return FALSE, and the\n//          |rect| out parameter remains unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDFText_GetMatrix\n//          Get the effective transformation matrix for a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage().\n//          index       -   Zero-based index of the character.\n//          matrix      -   Pointer to a FS_MATRIX receiving the transformation\n//                          matrix.\n// Return Value:\n//          On success, return TRUE and fill in |matrix|. If |text_page| is\n//          invalid, or if |index| is out of bounds, or if |matrix| is NULL,\n//          then return FALSE, and |matrix| remains unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,\n                                                       int index,\n                                                       FS_MATRIX* matrix);\n\n// Function: FPDFText_GetCharOrigin\n//          Get origin of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          x           -   Pointer to a double number receiving x coordinate of\n//                          the character origin.\n//          y           -   Pointer to a double number receiving y coordinate of\n//                          the character origin.\n// Return Value:\n//          Whether the call succeeded. If false, x and y are unchanged.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,\n                       int index,\n                       double* x,\n                       double* y);\n\n// Function: FPDFText_GetCharIndexAtPos\n//          Get the index of a character at or nearby a certain position on the\n//          page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          x           -   X position in PDF \"user space\".\n//          y           -   Y position in PDF \"user space\".\n//          xTolerance  -   An x-axis tolerance value for character hit\n//                          detection, in point units.\n//          yTolerance  -   A y-axis tolerance value for character hit\n//                          detection, in point units.\n// Return Value:\n//          The zero-based index of the character at, or nearby the point (x,y).\n//          If there is no character at or nearby the point, return value will\n//          be -1. If an error occurs, -3 will be returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,\n                           double x,\n                           double y,\n                           double xTolerance,\n                           double yTolerance);\n\n// Function: FPDFText_GetText\n//          Extract unicode text string from the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start characters.\n//          count       -   Number of UCS-2 values to be extracted.\n//          result      -   A buffer (allocated by application) receiving the\n//                          extracted UCS-2 values. The buffer must be able to\n//                          hold `count` UCS-2 values plus a terminator.\n// Return Value:\n//          Number of characters written into the result buffer, including the\n//          trailing terminator.\n// Comments:\n//          This function ignores characters without UCS-2 representations.\n//          It considers all characters on the page, even those that are not\n//          visible when the page has a cropbox. To filter out the characters\n//          outside of the cropbox, use FPDF_GetPageBoundingBox() and\n//          FPDFText_GetCharBox().\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page,\n                                               int start_index,\n                                               int count,\n                                               unsigned short* result);\n\n// Function: FPDFText_CountRects\n//          Counts number of rectangular areas occupied by a segment of text,\n//          and caches the result for subsequent FPDFText_GetRect() calls.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start character.\n//          count       -   Number of characters, or -1 for all remaining.\n// Return value:\n//          Number of rectangles, 0 if text_page is null, or -1 on bad\n//          start_index.\n// Comments:\n//          This function, along with FPDFText_GetRect can be used by\n//          applications to detect the position on the page for a text segment,\n//          so proper areas can be highlighted. The FPDFText_* functions will\n//          automatically merge small character boxes into bigger one if those\n//          characters are on the same line and use same font settings.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,\n                                                  int start_index,\n                                                  int count);\n\n// Function: FPDFText_GetRect\n//          Get a rectangular area from the result generated by\n//          FPDFText_CountRects.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          rect_index  -   Zero-based index for the rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |text_page| is invalid then return FALSE, and the out\n//          parameters remain unmodified. If |text_page| is valid but\n//          |rect_index| is out of bounds, then return FALSE and set the out\n//          parameters to 0.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Function: FPDFText_GetBoundedText\n//          Extract unicode text within a rectangular boundary on the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          left        -   Left boundary.\n//          top         -   Top boundary.\n//          right       -   Right boundary.\n//          bottom      -   Bottom boundary.\n//          buffer      -   Caller-allocated buffer to receive UTF-16 values.\n//          buflen      -   Number of UTF-16 values (not bytes) that `buffer`\n//                          is capable of holding.\n// Return Value:\n//          If buffer is NULL or buflen is zero, return number of UTF-16\n//          values (not bytes) of text present within the rectangle, excluding\n//          a terminating NUL. Generally you should pass a buffer at least one\n//          larger than this if you want a terminating NUL, which will be\n//          provided if space is available. Otherwise, return number of UTF-16\n//          values copied into the buffer, including the terminating NUL when\n//          space for it is available.\n// Comment:\n//          If the buffer is too small, as much text as will fit is copied into\n//          it. May return a split surrogate in that case.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,\n                                                      double left,\n                                                      double top,\n                                                      double right,\n                                                      double bottom,\n                                                      unsigned short* buffer,\n                                                      int buflen);\n\n// Flags used by FPDFText_FindStart function.\n//\n// If not set, it will not match case by default.\n#define FPDF_MATCHCASE 0x00000001\n// If not set, it will not match the whole word by default.\n#define FPDF_MATCHWHOLEWORD 0x00000002\n// If not set, it will skip past the current match to look for the next match.\n#define FPDF_CONSECUTIVE 0x00000004\n\n// Function: FPDFText_FindStart\n//          Start a search.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          findwhat    -   A unicode match pattern.\n//          flags       -   Option flags.\n//          start_index -   Start from this character. -1 for end of the page.\n// Return Value:\n//          A handle for the search context. FPDFText_FindClose must be called\n//          to release this handle.\n//\nFPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV\nFPDFText_FindStart(FPDF_TEXTPAGE text_page,\n                   FPDF_WIDESTRING findwhat,\n                   unsigned long flags,\n                   int start_index);\n\n// Function: FPDFText_FindNext\n//          Search in the direction from page start to end.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindPrev\n//          Search in the direction from page end to start.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchResultIndex\n//          Get the starting character index of the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Index for the starting character.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchCount\n//          Get the number of matched characters in the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Number of matched characters.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindClose\n//          Release a search context.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle);\n\n// Function: FPDFLink_LoadWebLinks\n//          Prepare information about weblinks in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          A handle to the page's links information structure, or\n//          NULL if something goes wrong.\n// Comments:\n//          Weblinks are those links implicitly embedded in PDF pages. PDF also\n//          has a type of annotation called \"link\" (FPDFTEXT doesn't deal with\n//          that kind of link). FPDFTEXT weblink feature is useful for\n//          automatically detecting links in the page contents. For example,\n//          things like \"https://www.example.com\" will be detected, so\n//          applications can allow user to click on those characters to activate\n//          the link, even the PDF doesn't come with link annotations.\n//\n//          FPDFLink_CloseWebLinks must be called to release resources.\n//\nFPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV\nFPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFLink_CountWebLinks\n//          Count number of detected web links.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          Number of detected web links.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page);\n\n// Function: FPDFLink_GetURL\n//          Fetch the URL information for a detected web link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          buffer      -   A unicode buffer for the result.\n//          buflen      -   Number of 16-bit code units (not bytes) for the\n//                          buffer, including an additional terminator.\n// Return Value:\n//          If |buffer| is NULL or |buflen| is zero, return the number of 16-bit\n//          code units (not bytes) needed to buffer the result (an additional\n//          terminator is included in this count).\n//          Otherwise, copy the result into |buffer|, truncating at |buflen| if\n//          the result is too large to fit, and return the number of 16-bit code\n//          units actually copied into the buffer (the additional terminator is\n//          also included in this count).\n//          If |link_index| does not correspond to a valid link, then the result\n//          is an empty string.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,\n                                              int link_index,\n                                              unsigned short* buffer,\n                                              int buflen);\n\n// Function: FPDFLink_CountRects\n//          Count number of rectangular areas for the link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n// Return Value:\n//          Number of rectangular areas for the link.  If |link_index| does\n//          not correspond to a valid link, then 0 is returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,\n                                                  int link_index);\n\n// Function: FPDFLink_GetRect\n//          Fetch the boundaries of a rectangle for a link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          rect_index  -   Zero-based index for a rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |link_page| is invalid or if |link_index| does not\n//          correspond to a valid link, then return FALSE, and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,\n                                                     int link_index,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Experimental API.\n// Function: FPDFLink_GetTextRange\n//          Fetch the start char index and char count for a link.\n// Parameters:\n//          link_page         -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index        -   Zero-based index for the link.\n//          start_char_index  -   pointer to int receiving the start char index\n//          char_count        -   pointer to int receiving the char count\n// Return Value:\n//          On success, return TRUE and fill in |start_char_index| and\n//          |char_count|. if |link_page| is invalid or if |link_index| does\n//          not correspond to a valid link, then return FALSE and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetTextRange(FPDF_PAGELINK link_page,\n                      int link_index,\n                      int* start_char_index,\n                      int* char_count);\n\n// Function: FPDFLink_CloseWebLinks\n//          Release resources used by weblink feature.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TEXT_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_thumbnail.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_THUMBNAIL_H_\n#define PUBLIC_FPDF_THUMBNAIL_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Gets the decoded data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| less than or equal to the\n// size of the decoded data. Returns the size of the decoded\n// data or 0 if thumbnail DNE. Optional, pass null to just retrieve\n// the size of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the decoded image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetDecodedThumbnailData(FPDF_PAGE page,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Gets the raw data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| is less than or equal to\n// the size of the raw data. Returns the size of the raw data or 0\n// if thumbnail DNE. Optional, pass null to just retrieve the size\n// of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the raw image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetRawThumbnailData(FPDF_PAGE page,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr\n// if unable to access the thumbnail's stream.\n//\n//   page - handle to a page.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_THUMBNAIL_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdf_transformpage.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_\n#define PUBLIC_FPDF_TRANSFORMPAGE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Set \"MediaBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"CropBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"BleedBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"TrimBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"ArtBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page,\n                                                  float left,\n                                                  float bottom,\n                                                  float right,\n                                                  float top);\n\n// Get \"MediaBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"CropBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"BleedBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"TrimBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"ArtBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page,\n                                                       float* left,\n                                                       float* bottom,\n                                                       float* right,\n                                                       float* top);\n\n// Apply transforms to |page|.\n//\n// If |matrix| is provided it will be applied to transform the page.\n// If |clipRect| is provided it will be used to clip the resulting page.\n// If neither |matrix| or |clipRect| are provided this method returns |false|.\n// Returns |true| if transforms are applied.\n//\n// This function will transform the whole page, and would take effect to all the\n// objects in the page.\n//\n// page        - Page handle.\n// matrix      - Transform matrix.\n// clipRect    - Clipping rectangle.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_TransFormWithClip(FPDF_PAGE page,\n                           const FS_MATRIX* matrix,\n                           const FS_RECTF* clipRect);\n\n// Transform (scale, rotate, shear, move) the clip path of page object.\n// page_object - Handle to a page object. Returned by\n// FPDFPageObj_NewImageObj().\n//\n// a  - The coefficient \"a\" of the matrix.\n// b  - The coefficient \"b\" of the matrix.\n// c  - The coefficient \"c\" of the matrix.\n// d  - The coefficient \"d\" of the matrix.\n// e  - The coefficient \"e\" of the matrix.\n// f  - The coefficient \"f\" of the matrix.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,\n                              double a,\n                              double b,\n                              double c,\n                              double d,\n                              double e,\n                              double f);\n\n// Experimental API.\n// Get the clip path of the page object.\n//\n//   page object - Handle to a page object. Returned by e.g.\n//                 FPDFPage_GetObject().\n//\n// Returns the handle to the clip path, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until\n// FPDF_ClosePage() is called for the page containing |page_object|.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV\nFPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of paths inside |clip_path|.\n//\n//   clip_path - handle to a clip_path.\n//\n// Returns the number of objects in |clip_path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path);\n\n// Experimental API.\n// Get number of segments inside one path of |clip_path|.\n//\n//   clip_path  - handle to a clip_path.\n//   path_index - index into the array of paths of the clip path.\n//\n// Returns the number of segments or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index);\n\n// Experimental API.\n// Get segment in one specific path of |clip_path| at index.\n//\n//   clip_path     - handle to a clip_path.\n//   path_index    - the index of a path.\n//   segment_index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid\n// until FPDF_ClosePage() is called for the page containing |clip_path|.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,\n                            int path_index,\n                            int segment_index);\n\n// Create a new clip path, with a rectangle inserted.\n//\n// Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with\n// FPDF_DestroyClipPath().\n//\n// left   - The left of the clip box.\n// bottom - The bottom of the clip box.\n// right  - The right of the clip box.\n// top    - The top of the clip box.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,\n                                                            float bottom,\n                                                            float right,\n                                                            float top);\n\n// Destroy the clip path.\n//\n// clipPath - A handle to the clip path. It will be invalid after this call.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath);\n\n// Clip the page content, the page content that outside the clipping region\n// become invisible.\n//\n// A clip path will be inserted before the page content stream or content array.\n// In this way, the page content will be clipped by this clip path.\n//\n// page        - A page handle.\n// clipPath    - A handle to the clip path. (Does not take ownership.)\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,\n                                                       FPDF_CLIPPATH clipPath);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TRANSFORMPAGE_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdfview.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/include/fpdfview.h.orig",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(COMPONENT_BUILD)\n// FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer\n// template in testing/fuzzers/BUILD.gn.\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n#else\n#define FPDF_EXPORT\n#endif  // defined(COMPONENT_BUILD)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/abseil.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/agg23.txt",
    "content": "//----------------------------------------------------------------------------\n// Anti-Grain Geometry - Version 2.3\n// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)\n//\n// Permission to copy, use, modify, sell and distribute this software\n// is granted provided this copyright notice appears in all copies.\n// This software is provided \"as is\" without express or implied\n// warranty, and with no claim as to its suitability for any purpose.\n//\n//----------------------------------------------------------------------------\n// Contact: mcseem@antigrain.com\n//          mcseemagg@yahoo.com\n//          http://www.antigrain.com\n//----------------------------------------------------------------------------\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/fast_float.txt",
    "content": "MIT License\n\nCopyright (c) 2021 The fast_float authors\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/freetype.txt",
    "content": "                    The FreeType Project LICENSE\n                    ----------------------------\n\n                            2006-Jan-27\n\n                    Copyright 1996-2002, 2006 by\n          David Turner, Robert Wilhelm, and Werner Lemberg\n\n\n\nIntroduction\n============\n\n  The FreeType  Project is distributed in  several archive packages;\n  some of them may contain, in addition to the FreeType font engine,\n  various tools and  contributions which rely on, or  relate to, the\n  FreeType Project.\n\n  This  license applies  to all  files found  in such  packages, and\n  which do not  fall under their own explicit  license.  The license\n  affects  thus  the  FreeType   font  engine,  the  test  programs,\n  documentation and makefiles, at the very least.\n\n  This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG\n  (Independent JPEG  Group) licenses, which  all encourage inclusion\n  and  use of  free  software in  commercial  and freeware  products\n  alike.  As a consequence, its main points are that:\n\n    o We don't promise that this software works. However, we will be\n      interested in any kind of bug reports. (`as is' distribution)\n\n    o You can  use this software for whatever you  want, in parts or\n      full form, without having to pay us. (`royalty-free' usage)\n\n    o You may not pretend that  you wrote this software.  If you use\n      it, or  only parts of it,  in a program,  you must acknowledge\n      somewhere  in  your  documentation  that  you  have  used  the\n      FreeType code. (`credits')\n\n  We  specifically  permit  and  encourage  the  inclusion  of  this\n  software, with  or without modifications,  in commercial products.\n  We  disclaim  all warranties  covering  The  FreeType Project  and\n  assume no liability related to The FreeType Project.\n\n\n  Finally,  many  people  asked  us  for  a  preferred  form  for  a\n  credit/disclaimer to use in compliance with this license.  We thus\n  encourage you to use the following text:\n\n   \"\"\"\n    Portions of this software are copyright  <year> The FreeType\n    Project (www.freetype.org).  All rights reserved.\n   \"\"\"\n\n  Please replace <year> with the value from the FreeType version you\n  actually use.\n\n\nLegal Terms\n===========\n\n0. Definitions\n--------------\n\n  Throughout this license,  the terms `package', `FreeType Project',\n  and  `FreeType  archive' refer  to  the  set  of files  originally\n  distributed  by the  authors  (David Turner,  Robert Wilhelm,  and\n  Werner Lemberg) as the `FreeType Project', be they named as alpha,\n  beta or final release.\n\n  `You' refers to  the licensee, or person using  the project, where\n  `using' is a generic term including compiling the project's source\n  code as  well as linking it  to form a  `program' or `executable'.\n  This  program is  referred to  as  `a program  using the  FreeType\n  engine'.\n\n  This  license applies  to all  files distributed  in  the original\n  FreeType  Project,   including  all  source   code,  binaries  and\n  documentation,  unless  otherwise  stated   in  the  file  in  its\n  original, unmodified form as  distributed in the original archive.\n  If you are  unsure whether or not a particular  file is covered by\n  this license, you must contact us to verify this.\n\n  The FreeType  Project is copyright (C) 1996-2000  by David Turner,\n  Robert Wilhelm, and Werner Lemberg.  All rights reserved except as\n  specified below.\n\n1. No Warranty\n--------------\n\n  THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY\n  KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,\n  WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR\n  PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS\n  BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO\n  USE, OF THE FREETYPE PROJECT.\n\n2. Redistribution\n-----------------\n\n  This  license  grants  a  worldwide, royalty-free,  perpetual  and\n  irrevocable right  and license to use,  execute, perform, compile,\n  display,  copy,   create  derivative  works   of,  distribute  and\n  sublicense the  FreeType Project (in  both source and  object code\n  forms)  and  derivative works  thereof  for  any  purpose; and  to\n  authorize others  to exercise  some or all  of the  rights granted\n  herein, subject to the following conditions:\n\n    o Redistribution of  source code  must retain this  license file\n      (`FTL.TXT') unaltered; any  additions, deletions or changes to\n      the original  files must be clearly  indicated in accompanying\n      documentation.   The  copyright   notices  of  the  unaltered,\n      original  files must  be  preserved in  all  copies of  source\n      files.\n\n    o Redistribution in binary form must provide a  disclaimer  that\n      states  that  the software is based in part of the work of the\n      FreeType Team,  in  the  distribution  documentation.  We also\n      encourage you to put an URL to the FreeType web page  in  your\n      documentation, though this isn't mandatory.\n\n  These conditions  apply to any  software derived from or  based on\n  the FreeType Project,  not just the unmodified files.   If you use\n  our work, you  must acknowledge us.  However, no  fee need be paid\n  to us.\n\n3. Advertising\n--------------\n\n  Neither the  FreeType authors and  contributors nor you  shall use\n  the name of the  other for commercial, advertising, or promotional\n  purposes without specific prior written permission.\n\n  We suggest,  but do not require, that  you use one or  more of the\n  following phrases to refer  to this software in your documentation\n  or advertising  materials: `FreeType Project',  `FreeType Engine',\n  `FreeType library', or `FreeType Distribution'.\n\n  As  you have  not signed  this license,  you are  not  required to\n  accept  it.   However,  as  the FreeType  Project  is  copyrighted\n  material, only  this license, or  another one contracted  with the\n  authors, grants you  the right to use, distribute,  and modify it.\n  Therefore,  by  using,  distributing,  or modifying  the  FreeType\n  Project, you indicate that you understand and accept all the terms\n  of this license.\n\n4. Contacts\n-----------\n\n  There are two mailing lists related to FreeType:\n\n    o freetype@nongnu.org\n\n      Discusses general use and applications of FreeType, as well as\n      future and  wanted additions to the  library and distribution.\n      If  you are looking  for support,  start in  this list  if you\n      haven't found anything to help you in the documentation.\n\n    o freetype-devel@nongnu.org\n\n      Discusses bugs,  as well  as engine internals,  design issues,\n      specific licenses, porting, etc.\n\n  Our home page can be found at\n\n    http://www.freetype.org\n\n\n--- end of FTL.TXT ---\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/icu.txt",
    "content": "UNICODE LICENSE V3\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright © 2016-2025 Unicode, Inc.\n\nNOTICE TO USER: Carefully read the following legal agreement. BY\nDOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\nSOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\nTERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\nDOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of data files and any associated documentation (the \"Data Files\") or\nsoftware and any associated documentation (the \"Software\") to deal in the\nData Files or Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, and/or sell\ncopies of the Data Files or Software, and to permit persons to whom the\nData Files or Software are furnished to do so, provided that either (a)\nthis copyright and permission notice appear with all copies of the Data\nFiles or Software, or (b) this copyright and permission notice appear in\nassociated Documentation.\n\nTHE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\nKIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\nTHIRD PARTY RIGHTS.\n\nIN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\nBE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\nFILES OR SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder shall\nnot be used in advertising or otherwise to promote the sale, use or other\ndealings in these Data Files or Software without prior written\nauthorization of the copyright holder.\n\nSPDX-License-Identifier: Unicode-3.0\n\n----------------------------------------------------------------------\n\nThird-Party Software Licenses\n\nThis section contains third-party software notices and/or additional\nterms for licensed third-party software components included within ICU\nlibraries.\n\n----------------------------------------------------------------------\n\nICU License - ICU 1.8.1 to ICU 57.1\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright (c) 1995-2016 International Business Machines Corporation and others\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, and/or sell copies of the Software, and to permit persons\nto whom the Software is furnished to do so, provided that the above\ncopyright notice(s) and this permission notice appear in all copies of\nthe Software and that both the above copyright notice(s) and this\npermission notice appear in supporting documentation.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\nHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\nSPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\nRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\nCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder\nshall not be used in advertising or otherwise to promote the sale, use\nor other dealings in this Software without prior written authorization\nof the copyright holder.\n\nAll trademarks and registered trademarks mentioned herein are the\nproperty of their respective owners.\n\n----------------------------------------------------------------------\n\nChinese/Japanese Word Break Dictionary Data (cjdict.txt)\n\n #     The Google Chrome software developed by Google is licensed under\n # the BSD license. Other software included in this distribution is\n # provided under other licenses, as set forth below.\n #\n #  The BSD License\n #  http://opensource.org/licenses/bsd-license.php\n #  Copyright (C) 2006-2008, Google Inc.\n #\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice,\n # this list of conditions and the following disclaimer.\n #  Redistributions in binary form must reproduce the above\n # copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided with\n # the distribution.\n #  Neither the name of  Google Inc. nor the names of its\n # contributors may be used to endorse or promote products derived from\n # this software without specific prior written permission.\n #\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #\n #\n #  The word list in cjdict.txt are generated by combining three word lists\n # listed below with further processing for compound word breaking. The\n # frequency is generated with an iterative training against Google web\n # corpora.\n #\n #  * Libtabe (Chinese)\n #    - https://sourceforge.net/project/?group_id=1519\n #    - Its license terms and conditions are shown below.\n #\n #  * IPADIC (Japanese)\n #    - http://chasen.aist-nara.ac.jp/chasen/distribution.html\n #    - Its license terms and conditions are shown below.\n #\n #  ---------COPYING.libtabe ---- BEGIN--------------------\n #\n #  /*\n #   * Copyright (c) 1999 TaBE Project.\n #   * Copyright (c) 1999 Pai-Hsiang Hsiao.\n #   * All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the TaBE Project nor the names of its\n #   *   contributors may be used to endorse or promote products derived\n #   *   from this software without specific prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  /*\n #   * Copyright (c) 1999 Computer Systems and Communication Lab,\n #   *                    Institute of Information Science, Academia\n #       *                    Sinica. All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the Computer Systems and Communication Lab\n #   *   nor the names of its contributors may be used to endorse or\n #   *   promote products derived from this software without specific\n #   *   prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\n #      University of Illinois\n #  c-tsai4@uiuc.edu  http://casper.beckman.uiuc.edu/~c-tsai4\n #\n #  ---------------COPYING.libtabe-----END--------------------------------\n #\n #\n #  ---------------COPYING.ipadic-----BEGIN-------------------------------\n #\n #  Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\n #  and Technology.  All Rights Reserved.\n #\n #  Use, reproduction, and distribution of this software is permitted.\n #  Any copy of this software, whether in its original form or modified,\n #  must include both the above copyright notice and the following\n #  paragraphs.\n #\n #  Nara Institute of Science and Technology (NAIST),\n #  the copyright holders, disclaims all warranties with regard to this\n #  software, including all implied warranties of merchantability and\n #  fitness, in no event shall NAIST be liable for\n #  any special, indirect or consequential damages or any damages\n #  whatsoever resulting from loss of use, data or profits, whether in an\n #  action of contract, negligence or other tortuous action, arising out\n #  of or in connection with the use or performance of this software.\n #\n #  A large portion of the dictionary entries\n #  originate from ICOT Free Software.  The following conditions for ICOT\n #  Free Software applies to the current dictionary as well.\n #\n #  Each User may also freely distribute the Program, whether in its\n #  original form or modified, to any third party or parties, PROVIDED\n #  that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\n #  on, or be attached to, the Program, which is distributed substantially\n #  in the same form as set out herein and that such intended\n #  distribution, if actually made, will neither violate or otherwise\n #  contravene any of the laws and regulations of the countries having\n #  jurisdiction over the User or the intended distribution itself.\n #\n #  NO WARRANTY\n #\n #  The program was produced on an experimental basis in the course of the\n #  research and development conducted during the project and is provided\n #  to users as so produced on an experimental basis.  Accordingly, the\n #  program is provided without any warranty whatsoever, whether express,\n #  implied, statutory or otherwise.  The term \"warranty\" used herein\n #  includes, but is not limited to, any warranty of the quality,\n #  performance, merchantability and fitness for a particular purpose of\n #  the program and the nonexistence of any infringement or violation of\n #  any right of any third party.\n #\n #  Each user of the program will agree and understand, and be deemed to\n #  have agreed and understood, that there is no warranty whatsoever for\n #  the program and, accordingly, the entire risk arising from or\n #  otherwise connected with the program is assumed by the user.\n #\n #  Therefore, neither ICOT, the copyright holder, or any other\n #  organization that participated in or was otherwise related to the\n #  development of the program and their respective officials, directors,\n #  officers and other employees shall be held liable for any and all\n #  damages, including, without limitation, general, special, incidental\n #  and consequential damages, arising out of or otherwise in connection\n #  with the use or inability to use the program or any product, material\n #  or result produced or otherwise obtained by using the program,\n #  regardless of whether they have been advised of, or otherwise had\n #  knowledge of, the possibility of such damages at any time during the\n #  project or thereafter.  Each user will be deemed to have agreed to the\n #  foregoing by his or her commencement of use of the program.  The term\n #  \"use\" as used herein includes, but is not limited to, the use,\n #  modification, copying and distribution of the program and the\n #  production of secondary products from the program.\n #\n #  In the case where the program, whether in its original form or\n #  modified, was distributed or delivered to or received by a user from\n #  any person, organization or entity other than ICOT, unless it makes or\n #  grants independently of ICOT any specific warranty to the user in\n #  writing, such person, organization or entity, will also be exempted\n #  from and not be held liable to the user for any such damages as noted\n #  above as far as the program is concerned.\n #\n #  ---------------COPYING.ipadic-----END----------------------------------\n\n----------------------------------------------------------------------\n\nLao Word Break Dictionary Data (laodict.txt)\n\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\n # License & terms of use: http://www.unicode.org/copyright.html\n # Copyright (c) 2015 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # Project: https://github.com/rober42539/lao-dictionary\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\n #          (copied below)\n #\n #\tThis file is derived from the above dictionary version of Nov 22, 2020\n #  ----------------------------------------------------------------------\n #  Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice, this\n #  list of conditions and the following disclaimer. Redistributions in binary\n #  form must reproduce the above copyright notice, this list of conditions and\n #  the following disclaimer in the documentation and/or other materials\n #  provided with the distribution.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # OF THE POSSIBILITY OF SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nBurmese Word Break Dictionary Data (burmesedict.txt)\n\n #  Copyright (c) 2014 International Business Machines Corporation\n #  and others. All Rights Reserved.\n #\n #  This list is part of a project hosted at:\n #    github.com/kanyawtech/myanmar-karen-word-lists\n #\n #  --------------------------------------------------------------------------\n #  Copyright (c) 2013, LeRoy Benjamin Sharon\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions\n #  are met: Redistributions of source code must retain the above\n #  copyright notice, this list of conditions and the following\n #  disclaimer.  Redistributions in binary form must reproduce the\n #  above copyright notice, this list of conditions and the following\n #  disclaimer in the documentation and/or other materials provided\n #  with the distribution.\n #\n #    Neither the name Myanmar Karen Word Lists, nor the names of its\n #    contributors may be used to endorse or promote products derived\n #    from this software without specific prior written permission.\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n #  CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n #  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n #  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n #  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n #  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n #  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n #  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\n #  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n #  SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nTime Zone Database\n\n  ICU uses the public domain data and code derived from Time Zone\nDatabase for its time zone support. The ownership of the TZ database\nis explained in BCP 175: Procedure for Maintaining the Time Zone\nDatabase section 7.\n\n # 7.  Database Ownership\n #\n #    The TZ database itself is not an IETF Contribution or an IETF\n #    document.  Rather it is a pre-existing and regularly updated work\n #    that is in the public domain, and is intended to remain in the\n #    public domain.  Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\n #    not apply to the TZ Database or contributions that individuals make\n #    to it.  Should any claims be made and substantiated against the TZ\n #    Database, the organization that is providing the IANA\n #    Considerations defined in this RFC, under the memorandum of\n #    understanding with the IETF, currently ICANN, may act in accordance\n #    with all competent court orders.  No ownership claims will be made\n #    by ICANN or the IETF Trust on the database or the code.  Any person\n #    making a contribution to the database or code waives all rights to\n #    future claims in that contribution or in the TZ Database.\n\n----------------------------------------------------------------------\n\nGoogle double-conversion\n\nCopyright 2006-2011, the V8 project authors. All rights reserved.\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials provided\n      with the distribution.\n    * Neither the name of Google Inc. nor the names of its\n      contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n----------------------------------------------------------------------\n\nJSON parsing library (nlohmann/json)\n\nFile: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\n\nMIT License\n\nCopyright (c) 2013-2022 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n----------------------------------------------------------------------\n\nFile: aclocal.m4 (only for ICU4C)\nSection: pkg.m4 - Macros to locate and utilise pkg-config.\n\n\nCopyright © 2004 Scott James Remnant <scott@netsplit.com>.\nCopyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n02111-1307, USA.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: config.guess (only for ICU4C)\n\n\nThis file is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, see <https://www.gnu.org/licenses/>.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.  This Exception is an additional permission under section 7\nof the GNU General Public License, version 3 (\"GPLv3\").\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: install-sh (only for ICU4C)\n\n\nCopyright 1991 by the Massachusetts Institute of Technology\n\nPermission to use, copy, modify, distribute, and sell this software and its\ndocumentation for any purpose is hereby granted without fee, provided that\nthe above copyright notice appear in all copies and that both that\ncopyright notice and this permission notice appear in supporting\ndocumentation, and that the name of M.I.T. not be used in advertising or\npublicity pertaining to distribution of the software without specific,\nwritten prior permission.  M.I.T. makes no representations about the\nsuitability of this software for any purpose.  It is provided \"as is\"\nwithout express or implied warranty.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/lcms.txt",
    "content": "//---------------------------------------------------------------------------------\n//\n//  Little Color Management System\n//  Copyright (c) 1998-2023 Marti Maria Saguer\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the Software\n// is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n//---------------------------------------------------------------------------------\n//\n// Version 2.15 \n//\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/libjpeg_turbo.ijg",
    "content": "libjpeg-turbo note:  This file has been modified by The libjpeg-turbo Project\nto include only information relevant to libjpeg-turbo, to wordsmith certain\nsections, and to remove impolitic language that existed in the libjpeg v8\nREADME.  It is included only for reference.  Please see README.md for\ninformation specific to libjpeg-turbo.\n\n\nThe Independent JPEG Group's JPEG software\n==========================================\n\nThis distribution contains a release of the Independent JPEG Group's free JPEG\nsoftware.  You are welcome to redistribute this software and to use it for any\npurpose, subject to the conditions under LEGAL ISSUES, below.\n\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\nJulian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,\nand other members of the Independent JPEG Group.\n\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\n(also known as JPEG, together with ITU-T SG16).\n\n\nDOCUMENTATION ROADMAP\n=====================\n\nThis file contains the following sections:\n\nOVERVIEW            General description of JPEG and the IJG software.\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\nREFERENCES          Where to learn more about JPEG.\nARCHIVE LOCATIONS   Where to find newer versions of this software.\nFILE FORMAT WARS    Software *not* to get.\nTO DO               Plans for future IJG releases.\n\nOther documentation files in the distribution are:\n\nUser documentation:\n  doc/usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\n                        rdjpgcom, and wrjpgcom.\n  doc/*.1               Unix-style man pages for programs (same info as\n                        usage.txt).\n  doc/wizard.txt        Advanced usage instructions for JPEG wizards only.\n  doc/change.log        Version-to-version change highlights.\nProgrammer and internal documentation:\n  doc/libjpeg.txt       How to use the JPEG library in your own programs.\n  src/example.c         Sample code for calling the JPEG library.\n  doc/structure.txt     Overview of the JPEG library's internal structure.\n  doc/coderules.txt     Coding style rules --- please read if you contribute\n                        code.\n\nPlease read at least usage.txt.  Some information can also be found in the JPEG\nFAQ (Frequently Asked Questions) article.  See ARCHIVE LOCATIONS below to find\nout where to obtain the FAQ article.\n\nIf you want to understand how the JPEG code works, we suggest reading one or\nmore of the REFERENCES, then looking at the documentation files (in roughly\nthe order listed) before diving into the code.\n\n\nOVERVIEW\n========\n\nThis package contains C software to implement JPEG image encoding, decoding,\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\nmethod for full-color and grayscale images.  JPEG's strong suit is compressing\nphotographic images or other types of images that have smooth color and\nbrightness transitions between neighboring pixels.  Images with sharp lines or\nother abrupt features may not compress well with JPEG, and a higher JPEG\nquality may have to be used to avoid visible compression artifacts with such\nimages.\n\nJPEG is normally lossy, meaning that the output pixels are not necessarily\nidentical to the input pixels.  However, on photographic content and other\n\"smooth\" images, very good compression ratios can be obtained with no visible\ncompression artifacts, and extremely high compression ratios are possible if\nyou are willing to sacrifice image quality (by reducing the \"quality\" setting\nin the compressor.)\n\nThis software implements JPEG baseline, extended-sequential, progressive, and\nlossless compression processes.  Provision is made for supporting all variants\nof these processes, although some uncommon parameter settings aren't\nimplemented yet.  We have made no provision for supporting the hierarchical\nprocesses defined in the standard.\n\nWe provide a set of library routines for reading and writing JPEG image files,\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\nperform conversion between JPEG and some other popular image file formats.\nThe library is intended to be reused in other applications.\n\nIn order to support file conversion and viewing software, we have included\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\nfor example, the color quantization modules are not strictly part of JPEG\ndecoding, but they are essential for output to colormapped file formats.  These\nextra functions can be compiled out of the library if not required for a\nparticular application.\n\nWe have also included \"jpegtran\", a utility for lossless transcoding between\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\napplications for inserting and extracting textual comments in JFIF files.\n\nThe emphasis in designing this software has been on achieving portability and\nflexibility, while also making it fast enough to be useful.  In particular,\nthe software is not intended to be read as a tutorial on JPEG.  (See the\nREFERENCES section for introductory material.)  Rather, it is intended to\nbe reliable, portable, industrial-strength code.  We do not claim to have\nachieved that goal in every aspect of the software, but we strive for it.\n\nWe welcome the use of this software as a component of commercial products.\nNo royalty is required, but we do ask for an acknowledgement in product\ndocumentation, as described under LEGAL ISSUES.\n\n\nLEGAL ISSUES\n============\n\nIn plain English:\n\n1. We don't promise that this software works.  (But if you find any bugs,\n   please let us know!)\n2. You can use this software for whatever you want.  You don't have to pay us.\n3. You may not pretend that you wrote this software.  If you use it in a\n   program, you must acknowledge somewhere in your documentation that\n   you've used the IJG code.\n\nIn legalese:\n\nThe authors make NO WARRANTY or representation, either express or implied,\nwith respect to this software, its quality, accuracy, merchantability, or\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\nits user, assume the entire risk as to its quality and accuracy.\n\nThis software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.\nAll Rights Reserved except as specified below.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nPermission is NOT granted for the use of any IJG author's name or company name\nin advertising or publicity relating to this software or products derived from\nit.  This software may be referred to only as \"the Independent JPEG Group's\nsoftware\".\n\nWe specifically permit and encourage the use of this software as the basis of\ncommercial products, provided that all warranty or liability claims are\nassumed by the product vendor.\n\n\nREFERENCES\n==========\n\nWe recommend reading one or more of these references before trying to\nunderstand the innards of the JPEG software.\n\nThe best short technical introduction to the JPEG compression algorithm is\n        Wallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\n        Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\n(Adjacent articles in that issue discuss MPEG motion picture compression,\napplications of JPEG, and related topics.)  If you don't have the CACM issue\nhandy, a PDF file containing a revised version of Wallace's article is\navailable at http://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\nomits the sample images that appeared in CACM, but it includes corrections\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\nand it may not be used for commercial purposes.\n\nA somewhat less technical, more leisurely introduction to JPEG can be found in\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\ngood explanations and example C code for a multitude of compression methods\nincluding JPEG.  It is an excellent source if you are comfortable reading C\ncode but don't know much about data compression in general.  The book's JPEG\nsample code is far from industrial-strength, but when you are ready to look\nat a full implementation, you've got one here...\n\nThe best currently available description of JPEG is the textbook \"JPEG Still\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\nstandards (DIS 10918-1 and draft DIS 10918-2).\n\nThe original JPEG standard is divided into two parts, Part 1 being the actual\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\n\nThe JPEG standard does not specify all details of an interchangeable file\nformat.  For the omitted details, we follow the \"JFIF\" conventions, revision\n1.02.  JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and\nRecommendation ITU-T T.871 (05/2011): Information technology - Digital\ncompression and coding of continuous-tone still images: JPEG File Interchange\nFormat (JFIF).  It is available as a free download in PDF file format from\nhttps://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.\nA PDF file of the older JFIF 1.02 specification is available at\nhttp://www.w3.org/Graphics/JPEG/jfif3.pdf.\n\nThe TIFF 6.0 file format specification can be obtained from\nhttp://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation\nscheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious\nproblems.  IJG does not recommend use of the TIFF 6.0 design (TIFF Compression\ntag 6).  Instead, we recommend the JPEG design proposed by TIFF Technical Note\n#2 (Compression tag 7).  Copies of this Note can be obtained from\nhttp://www.ijg.org/files/.  It is expected that the next revision\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\nuses our library to implement TIFF/JPEG per the Note.\n\n\nARCHIVE LOCATIONS\n=================\n\nThe \"official\" archive site for this software is www.ijg.org.\nThe most recent released version can always be found there in\ndirectory \"files\".\n\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\ngeneral information about JPEG.  It is available at\nhttp://www.faqs.org/faqs/jpeg-faq.\n\n\nFILE FORMAT COMPATIBILITY\n=========================\n\nThis software implements ITU T.81 | ISO/IEC 10918 with some extensions from\nITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).\nInformally, the term \"JPEG image\" or \"JPEG file\" most often refers to JFIF or\na subset thereof, but there are other formats containing the name \"JPEG\" that\nare incompatible with the original JPEG standard or with JFIF (for instance,\nJPEG 2000 and JPEG XR).  This software therefore does not support these\nformats.  Indeed, one of the original reasons for developing this free software\nwas to help force convergence on a common, interoperable format standard for\nJPEG files.\n\nJFIF is a minimal or \"low end\" representation.  TIFF/JPEG (TIFF revision 6.0 as\nmodified by TIFF Technical Note #2) can be used for \"high end\" applications\nthat need to record a lot of additional data about an image.\n\n\nTO DO\n=====\n\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/libjpeg_turbo.md",
    "content": "libjpeg-turbo Licenses\n======================\n\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\n\n- The IJG (Independent JPEG Group) License, which is listed in\n  [README.ijg](README.ijg)\n\n  This license applies to the libjpeg API library and associated programs,\n  including any code inherited from libjpeg and any modifications to that\n  code.  Note that the libjpeg-turbo SIMD source code bears the\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\n  the overall libjpeg API library, the terms of the zlib License are subsumed\n  by the terms of the IJG License.\n\n- The Modified (3-clause) BSD License, which is listed below\n\n  This license applies to the TurboJPEG API library and associated programs, as\n  well as the build system.  Note that the TurboJPEG API library wraps the\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\n  both the terms of the IJG License and the terms of the Modified (3-clause)\n  BSD License apply.\n\n\nComplying with the libjpeg-turbo Licenses\n=========================================\n\nThis section provides a roll-up of the libjpeg-turbo licensing terms, to the\nbest of our understanding.  This is not a license in and of itself.  It is\nintended solely for clarification.\n\n1.  If you are distributing a modified version of the libjpeg-turbo source,\n    then:\n\n    1.  You cannot alter or remove any existing copyright or license notices\n        from the source.\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 1 of the Modified BSD License\n        - Clauses 1 and 3 of the zlib License\n\n    2.  You must add your own copyright notice to the header of each source\n        file you modified, so others can tell that you modified that file.  (If\n        there is not an existing copyright header in that file, then you can\n        simply add a notice stating that you modified the file.)\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 2 of the zlib License\n\n    3.  You must include the IJG README file, and you must not alter any of the\n        copyright or license text in that file.\n\n        **Origin**\n        - Clause 1 of the IJG License\n\n2.  If you are distributing only libjpeg-turbo binaries without the source, or\n    if you are distributing an application that statically links with\n    libjpeg-turbo, then:\n\n    1.  Your product documentation must include a message stating:\n\n        This software is based in part on the work of the Independent JPEG\n        Group.\n\n        **Origin**\n        - Clause 2 of the IJG license\n\n    2.  If your binary distribution includes or uses the TurboJPEG API, then\n        your product documentation must include the text of the Modified BSD\n        License (see below.)\n\n        **Origin**\n        - Clause 2 of the Modified BSD License\n\n3.  You cannot use the name of the IJG or The libjpeg-turbo Project or the\n    contributors thereof in advertising, publicity, etc.\n\n    **Origin**\n    - IJG License\n    - Clause 3 of the Modified BSD License\n\n4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be\n    free of defects, nor do we accept any liability for undesirable\n    consequences resulting from your use of the software.\n\n    **Origin**\n    - IJG License\n    - Modified BSD License\n    - zlib License\n\n\nThe Modified (3-clause) BSD License\n===================================\n\nCopyright (C)2009-2024 D. R. Commander.  All Rights Reserved.<br>\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n- Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n- Neither the name of the libjpeg-turbo Project nor the names of its\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n\nWhy Two Licenses?\n=================\n\nThe zlib License could have been used instead of the Modified (3-clause) BSD\nLicense, and since the IJG License effectively subsumes the distribution\nconditions of the zlib License, this would have effectively placed\nlibjpeg-turbo binary distributions under the IJG License.  However, the IJG\nLicense specifically refers to the Independent JPEG Group and does not extend\nattribution and endorsement protections to other entities.  Thus, it was\ndesirable to choose a license that granted us the same protections for new code\nthat were granted to the IJG for code derived from their software.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/libopenjpeg.txt",
    "content": "/*\n * The copyright in this software is being made available under the 2-clauses\n * BSD License, included below. This software may be subject to other third\n * party and contributor rights, including patent rights, and no such rights\n * are granted under this license.\n *\n * Copyright (c) 2005, Herve Drolon, FreeImage Team\n * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR\n * Copyright (c) 2012, CS Systemes d'Information, France\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/libpng.txt",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n=========================================\n\nPNG Reference Library License version 2\n---------------------------------------\n\n * Copyright (c) 1995-2019 The PNG Reference Library Authors.\n * Copyright (c) 2018-2019 Cosmin Truta.\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n * Copyright (c) 1996-1997 Andreas Dilger.\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nThe software is supplied \"as is\", without warranty of any kind,\nexpress or implied, including, without limitation, the warranties\nof merchantability, fitness for a particular purpose, title, and\nnon-infringement.  In no event shall the Copyright owners, or\nanyone distributing the software, be liable for any damages or\nother liability, whether in contract, tort or otherwise, arising\nfrom, out of, or in connection with the software, or the use or\nother dealings in the software, even if advised of the possibility\nof such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute\nthis software, or portions hereof, for any purpose, without fee,\nsubject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you\n    must not claim that you wrote the original software.  If you\n    use this software in a product, an acknowledgment in the product\n    documentation would be appreciated, but is not required.\n\n 2. Altered source versions must be plainly marked as such, and must\n    not be misrepresented as being the original software.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\n\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n-----------------------------------------------------------------------\n\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\nderived from libpng-1.0.6, and are distributed according to the same\ndisclaimer and license as libpng-1.0.6 with the following individuals\nadded to the list of Contributing Authors:\n\n    Simon-Pierre Cadieux\n    Eric S. Raymond\n    Mans Rullgard\n    Cosmin Truta\n    Gilles Vollant\n    James Yu\n    Mandar Sahastrabuddhe\n    Google Inc.\n    Vadim Barkov\n\nand with the following additions to the disclaimer:\n\n    There is no warranty against interference with your enjoyment of\n    the library or against infringement.  There is no warranty that our\n    efforts or the library will fulfill any of your particular purposes\n    or needs.  This library is provided with all faults, and the entire\n    risk of satisfactory quality, performance, accuracy, and effort is\n    with the user.\n\nSome files in the \"contrib\" directory and some configure-generated\nfiles that are distributed with libpng have other copyright owners, and\nare released under other open source licenses.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\nlibpng-0.96, and are distributed according to the same disclaimer and\nlicense as libpng-0.96, with the following individuals added to the\nlist of Contributing Authors:\n\n    Tom Lane\n    Glenn Randers-Pehrson\n    Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\nand are distributed according to the same disclaimer and license as\nlibpng-0.88, with the following individuals added to the list of\nContributing Authors:\n\n    John Bowler\n    Kevin Bracey\n    Sam Bushell\n    Magnus Holmgren\n    Greg Roelofs\n    Tom Tanner\n\nSome files in the \"scripts\" directory have other copyright owners,\nbut are released under this license.\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n    Andreas Dilger\n    Dave Martindale\n    Guy Eric Schalnat\n    Paul Schmidt\n    Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\nimplied, including, without limitation, the warranties of\nmerchantability and of fitness for any purpose.  The Contributing\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\nincidental, special, exemplary, or consequential damages, which may\nresult from the use of the PNG Reference Library, even if advised of\nthe possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n 1. The origin of this source code must not be misrepresented.\n\n 2. Altered versions must be plainly marked as such and must not\n    be misrepresented as being the original source.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit,\nwithout fee, and encourage the use of this source code as a component\nto supporting the PNG file format in commercial products.  If you use\nthis source code in a product, acknowledgment is not required but would\nbe appreciated.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/libtiff.txt",
    "content": "Copyright (c) 1988-1997 Sam Leffler\nCopyright (c) 1991-1997 Silicon Graphics, Inc.\n\nPermission to use, copy, modify, distribute, and sell this software and\nits documentation for any purpose is hereby granted without fee, provided\nthat (i) the above copyright notices and this permission notice appear in\nall copies of the software and related documentation, and (ii) the names of\nSam Leffler and Silicon Graphics may not be used in any advertising or\npublicity relating to the software without the specific, prior written\npermission of Sam Leffler and Silicon Graphics.\n\nTHE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\nEXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\nWARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n\nIN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR\nANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF\nLIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\nOF THIS SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/llvm-libc.txt",
    "content": "==============================================================================\nThe LLVM Project is under the Apache License v2.0 with LLVM Exceptions:\n==============================================================================\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n    1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n    2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n    3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n    4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n    5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n    6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n    7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n    8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n    9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    END OF TERMS AND CONDITIONS\n\n    APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n    Copyright [yyyy] [name of copyright owner]\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n---- LLVM Exceptions to the Apache 2.0 License ----\n\nAs an exception, if, as a result of your compiling your source code, portions\nof this Software are embedded into an Object form of such source code, you\nmay redistribute such embedded portions in such Object form without complying\nwith the conditions of Sections 4(a), 4(b) and 4(d) of the License.\n\nIn addition, if you combine or link compiled forms of this Software with\nsoftware that is licensed under the GPLv2 (\"Combined Software\") and if a\ncourt of competent jurisdiction determines that the patent provision (Section\n3), the indemnity provision (Section 9) or other Section of the License\nconflicts with the conditions of the GPLv2, you may retroactively and\nprospectively choose to deem waived or otherwise exclude such Section(s) of\nthe License, but only in their entirety and only with respect to the Combined\nSoftware.\n\n==============================================================================\nSoftware from third parties included in the LLVM Project:\n==============================================================================\nThe LLVM Project contains third party software which is under different license\nterms. All such code will be identified clearly using at least one of two\nmechanisms:\n1) It will be in a separate directory tree with its own `LICENSE.txt` or\n   `LICENSE` file at the top containing the specific license and restrictions\n   which apply to that software, or\n2) It will contain specific license and restriction terms at the top of every\n   file.\n\n==============================================================================\nLegacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):\n==============================================================================\nUniversity of Illinois/NCSA\nOpen Source License\n\nCopyright (c) 2007-2019 University of Illinois at Urbana-Champaign.\nAll rights reserved.\n\nDeveloped by:\n\n    LLVM Team\n\n    University of Illinois at Urbana-Champaign\n\n    http://llvm.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal with\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimers.\n\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimers in the\n      documentation and/or other materials provided with the distribution.\n\n    * Neither the names of the LLVM Team, University of Illinois at\n      Urbana-Champaign, nor the names of its contributors may be used to\n      endorse or promote products derived from this Software without specific\n      prior written permission.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nCONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE\nSOFTWARE.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/pdfium.txt",
    "content": "Copyright 2014 The PDFium Authors\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/simdutf.txt",
    "content": "Copyright 2021 The simdutf authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/linux-x64/licenses/zlib.txt",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.3.1, January 22nd, 2024\n\n  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n"
  },
  {
    "path": "external/pdfium/macos-arm64/LICENSE",
    "content": "Copyright 2014-2025 Benoit Blanchon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nThis package also includes third-party software. See the licenses/ directory for their respective licenses.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/PDFiumConfig.cmake",
    "content": "# PDFium Package Configuration for CMake\n#\n# To use PDFium in your CMake project:\n#\n#   1. set the environment variable PDFium_DIR to the folder containing this file.\n#   2. in your CMakeLists.txt, add\n#       find_package(PDFium)\n#   3. then link your executable with PDFium\n#       target_link_libraries(my_exe pdfium)\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_path(PDFium_INCLUDE_DIR\n    NAMES \"fpdfview.h\"\n    PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n    PATH_SUFFIXES \"include\"\n)\n\nset(PDFium_VERSION \"147.0.7713.0\")\n\nif(WIN32)\n  find_file(PDFium_LIBRARY\n        NAMES \"pdfium.dll\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"bin\")\n\n  find_file(PDFium_IMPLIB\n        NAMES \"pdfium.dll.lib\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    IMPORTED_IMPLIB               \"${PDFium_IMPLIB}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nelse()\n  find_library(PDFium_LIBRARY\n        NAMES \"pdfium\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nendif()\n"
  },
  {
    "path": "external/pdfium/macos-arm64/VERSION",
    "content": "MAJOR=147\nMINOR=0\nBUILD=7713\nPATCH=0\n"
  },
  {
    "path": "external/pdfium/macos-arm64/args.gn",
    "content": "clang_use_chrome_plugins = false\nis_component_build = false\nis_debug = false\npdf_enable_v8 = false\npdf_enable_xfa = false\npdf_is_standalone = true\npdf_use_partition_alloc = false\ntarget_cpu = \"arm64\"\ntarget_os = \"mac\"\ntreat_warnings_as_errors = false\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/cpp/fpdf_deleters.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_DELETERS_H_\n#define PUBLIC_CPP_FPDF_DELETERS_H_\n\n#include \"../fpdf_annot.h\"\n#include \"../fpdf_dataavail.h\"\n#include \"../fpdf_edit.h\"\n#include \"../fpdf_formfill.h\"\n#include \"../fpdf_javascript.h\"\n#include \"../fpdf_structtree.h\"\n#include \"../fpdf_text.h\"\n#include \"../fpdf_transformpage.h\"\n#include \"../fpdfview.h\"\n\n// Custom deleters for using FPDF_* types with std::unique_ptr<>.\n\nstruct FPDFAnnotationDeleter {\n  inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); }\n};\n\nstruct FPDFAvailDeleter {\n  inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); }\n};\n\nstruct FPDFBitmapDeleter {\n  inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); }\n};\n\nstruct FPDFClipPathDeleter {\n  inline void operator()(FPDF_CLIPPATH clip_path) {\n    FPDF_DestroyClipPath(clip_path);\n  }\n};\n\nstruct FPDFDocumentDeleter {\n  inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); }\n};\n\nstruct FPDFFontDeleter {\n  inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); }\n};\n\nstruct FPDFFormHandleDeleter {\n  inline void operator()(FPDF_FORMHANDLE form) {\n    FPDFDOC_ExitFormFillEnvironment(form);\n  }\n};\n\nstruct FPDFJavaScriptActionDeleter {\n  inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) {\n    FPDFDoc_CloseJavaScriptAction(javascript);\n  }\n};\n\nstruct FPDFPageDeleter {\n  inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); }\n};\n\nstruct FPDFPageLinkDeleter {\n  inline void operator()(FPDF_PAGELINK pagelink) {\n    FPDFLink_CloseWebLinks(pagelink);\n  }\n};\n\nstruct FPDFPageObjectDeleter {\n  inline void operator()(FPDF_PAGEOBJECT object) {\n    FPDFPageObj_Destroy(object);\n  }\n};\n\nstruct FPDFStructTreeDeleter {\n  inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); }\n};\n\nstruct FPDFTextFindDeleter {\n  inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); }\n};\n\nstruct FPDFTextPageDeleter {\n  inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); }\n};\n\n#endif  // PUBLIC_CPP_FPDF_DELETERS_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/cpp/fpdf_scopers.h",
    "content": "// Copyright 2018 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_SCOPERS_H_\n#define PUBLIC_CPP_FPDF_SCOPERS_H_\n\n#include <memory>\n#include <type_traits>\n\n#include \"fpdf_deleters.h\"\n\n// Versions of FPDF types that clean up the object at scope exit.\n\nusing ScopedFPDFAnnotation =\n    std::unique_ptr<std::remove_pointer<FPDF_ANNOTATION>::type,\n                    FPDFAnnotationDeleter>;\n\nusing ScopedFPDFAvail =\n    std::unique_ptr<std::remove_pointer<FPDF_AVAIL>::type, FPDFAvailDeleter>;\n\nusing ScopedFPDFBitmap =\n    std::unique_ptr<std::remove_pointer<FPDF_BITMAP>::type, FPDFBitmapDeleter>;\n\nusing ScopedFPDFClipPath =\n    std::unique_ptr<std::remove_pointer<FPDF_CLIPPATH>::type,\n                    FPDFClipPathDeleter>;\n\nusing ScopedFPDFDocument =\n    std::unique_ptr<std::remove_pointer<FPDF_DOCUMENT>::type,\n                    FPDFDocumentDeleter>;\n\nusing ScopedFPDFFont =\n    std::unique_ptr<std::remove_pointer<FPDF_FONT>::type, FPDFFontDeleter>;\n\nusing ScopedFPDFFormHandle =\n    std::unique_ptr<std::remove_pointer<FPDF_FORMHANDLE>::type,\n                    FPDFFormHandleDeleter>;\n\nusing ScopedFPDFJavaScriptAction =\n    std::unique_ptr<std::remove_pointer<FPDF_JAVASCRIPT_ACTION>::type,\n                    FPDFJavaScriptActionDeleter>;\n\nusing ScopedFPDFPage =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGE>::type, FPDFPageDeleter>;\n\nusing ScopedFPDFPageLink =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGELINK>::type,\n                    FPDFPageLinkDeleter>;\n\nusing ScopedFPDFPageObject =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGEOBJECT>::type,\n                    FPDFPageObjectDeleter>;\n\nusing ScopedFPDFStructTree =\n    std::unique_ptr<std::remove_pointer<FPDF_STRUCTTREE>::type,\n                    FPDFStructTreeDeleter>;\n\nusing ScopedFPDFTextFind =\n    std::unique_ptr<std::remove_pointer<FPDF_SCHHANDLE>::type,\n                    FPDFTextFindDeleter>;\n\nusing ScopedFPDFTextPage =\n    std::unique_ptr<std::remove_pointer<FPDF_TEXTPAGE>::type,\n                    FPDFTextPageDeleter>;\n\n#endif  // PUBLIC_CPP_FPDF_SCOPERS_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_annot.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ANNOT_H_\n#define PUBLIC_FPDF_ANNOT_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdf_formfill.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n#define FPDF_ANNOT_UNKNOWN 0\n#define FPDF_ANNOT_TEXT 1\n#define FPDF_ANNOT_LINK 2\n#define FPDF_ANNOT_FREETEXT 3\n#define FPDF_ANNOT_LINE 4\n#define FPDF_ANNOT_SQUARE 5\n#define FPDF_ANNOT_CIRCLE 6\n#define FPDF_ANNOT_POLYGON 7\n#define FPDF_ANNOT_POLYLINE 8\n#define FPDF_ANNOT_HIGHLIGHT 9\n#define FPDF_ANNOT_UNDERLINE 10\n#define FPDF_ANNOT_SQUIGGLY 11\n#define FPDF_ANNOT_STRIKEOUT 12\n#define FPDF_ANNOT_STAMP 13\n#define FPDF_ANNOT_CARET 14\n#define FPDF_ANNOT_INK 15\n#define FPDF_ANNOT_POPUP 16\n#define FPDF_ANNOT_FILEATTACHMENT 17\n#define FPDF_ANNOT_SOUND 18\n#define FPDF_ANNOT_MOVIE 19\n#define FPDF_ANNOT_WIDGET 20\n#define FPDF_ANNOT_SCREEN 21\n#define FPDF_ANNOT_PRINTERMARK 22\n#define FPDF_ANNOT_TRAPNET 23\n#define FPDF_ANNOT_WATERMARK 24\n#define FPDF_ANNOT_THREED 25\n#define FPDF_ANNOT_RICHMEDIA 26\n#define FPDF_ANNOT_XFAWIDGET 27\n#define FPDF_ANNOT_REDACT 28\n\n// Refer to PDF Reference (6th edition) table 8.16 for all annotation flags.\n#define FPDF_ANNOT_FLAG_NONE 0\n#define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0)\n#define FPDF_ANNOT_FLAG_HIDDEN (1 << 1)\n#define FPDF_ANNOT_FLAG_PRINT (1 << 2)\n#define FPDF_ANNOT_FLAG_NOZOOM (1 << 3)\n#define FPDF_ANNOT_FLAG_NOROTATE (1 << 4)\n#define FPDF_ANNOT_FLAG_NOVIEW (1 << 5)\n#define FPDF_ANNOT_FLAG_READONLY (1 << 6)\n#define FPDF_ANNOT_FLAG_LOCKED (1 << 7)\n#define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8)\n\n#define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0\n#define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1\n#define FPDF_ANNOT_APPEARANCEMODE_DOWN 2\n#define FPDF_ANNOT_APPEARANCEMODE_COUNT 3\n\n// Refer to PDF Reference version 1.7 table 8.70 for field flags common to all\n// interactive form field types.\n#define FPDF_FORMFLAG_NONE 0\n#define FPDF_FORMFLAG_READONLY (1 << 0)\n#define FPDF_FORMFLAG_REQUIRED (1 << 1)\n#define FPDF_FORMFLAG_NOEXPORT (1 << 2)\n\n// Refer to PDF Reference version 1.7 table 8.77 for field flags specific to\n// interactive form text fields.\n#define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12)\n#define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13)\n\n// Refer to PDF Reference version 1.7 table 8.79 for field flags specific to\n// interactive form choice fields.\n#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17)\n#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18)\n#define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21)\n\n// Additional actions type of form field:\n//   K, on key stroke, JavaScript action.\n//   F, on format, JavaScript action.\n//   V, on validate, JavaScript action.\n//   C, on calculate, JavaScript action.\n#define FPDF_ANNOT_AACTION_KEY_STROKE 12\n#define FPDF_ANNOT_AACTION_FORMAT 13\n#define FPDF_ANNOT_AACTION_VALIDATE 14\n#define FPDF_ANNOT_AACTION_CALCULATE 15\n\ntypedef enum FPDFANNOT_COLORTYPE {\n  FPDFANNOT_COLORTYPE_Color = 0,\n  FPDFANNOT_COLORTYPE_InteriorColor\n} FPDFANNOT_COLORTYPE;\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for creation.\n// Currently supported subtypes:\n//    - circle\n//    - fileattachment\n//    - freetext\n//    - highlight\n//    - ink\n//    - link\n//    - popup\n//    - square,\n//    - squiggly\n//    - stamp\n//    - strikeout\n//    - text\n//    - underline\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Create an annotation in |page| of the subtype |subtype|. If the specified\n// subtype is illegal or unsupported, then a new annotation will not be created.\n// Must call FPDFPage_CloseAnnot() when the annotation returned by this\n// function is no longer needed.\n//\n//   page      - handle to a page.\n//   subtype   - the subtype of the new annotation.\n//\n// Returns a handle to the new annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Get the number of annotations in |page|.\n//\n//   page   - handle to a page.\n//\n// Returns the number of annotations in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page);\n\n// Experimental API.\n// Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the\n// annotation returned by this function is no longer needed.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns a handle to the annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,\n                                                            int index);\n\n// Experimental API.\n// Get the index of |annot| in |page|. This is the opposite of\n// FPDFPage_GetAnnot().\n//\n//   page  - handle to the page that the annotation is on.\n//   annot - handle to an annotation.\n//\n// Returns the index of |annot|, or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,\n                                                     FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Close an annotation. Must be called when the annotation returned by\n// FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This\n// function does not remove the annotation from the document.\n//\n//   annot  - handle to an annotation.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Remove the annotation in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,\n                                                         int index);\n\n// Experimental API.\n// Get the subtype of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the annotation subtype.\nFPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV\nFPDFAnnot_GetSubtype(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for object extraction,\n// update, and removal.\n// Currently supported subtypes: ink and stamp.\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Update |obj| in |annot|. |obj| must be in |annot| already and must have\n// been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp\n// annotations are supported by this API. Also note that only path, image, and\n// text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and\n// FPDFImageObj_*().\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that |annot| needs to update.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Add a new InkStroke, represented by an array of points, to the InkList of\n// |annot|. The API creates an InkList if one doesn't already exist in |annot|.\n// This API works only for ink annotations. Please refer to ISO 32000-1:2008\n// spec, section 12.5.6.13.\n//\n//   annot       - handle to an annotation.\n//   points      - pointer to a FS_POINTF array representing input points.\n//   point_count - number of elements in |points| array. This should not exceed\n//                 the maximum value that can be represented by an int32_t).\n//\n// Returns the 0-based index at which the new InkStroke is added in the InkList\n// of the |annot|. Returns -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot,\n                                                     const FS_POINTF* points,\n                                                     size_t point_count);\n\n// Experimental API.\n// Removes an InkList in |annot|.\n// This API works only for ink annotations.\n//\n//   annot  - handle to an annotation.\n//\n// Return true on successful removal of /InkList entry from context of the\n// non-null ink |annot|. Returns false on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add |obj| to |annot|. |obj| must have been created by\n// FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and\n// will be owned by |annot|. Note that an |obj| cannot belong to more than one\n// |annot|. Currently, only ink and stamp annotations are supported by this API.\n// Also note that only path, image, and text objects have APIs for creation.\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that is to be added to |annot|.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Get the total number of objects in |annot|, including path objects, text\n// objects, external objects, image objects, and shading objects.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of objects in |annot|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object.\n//\n// Return a handle to the object, or NULL on failure.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Remove the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object to be removed.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Set the color of an annotation. Fails when called on annotations with\n// appearance streams already defined; instead use\n// FPDFPageObj_Set{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color to be set.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int R,\n                                                       unsigned int G,\n                                                       unsigned int B,\n                                                       unsigned int A);\n\n// Experimental API.\n// Get the color of an annotation. If no color is specified, default to yellow\n// for highlight annotation, black for all else. Fails when called on\n// annotations with appearance streams already defined; instead use\n// FPDFPageObj_Get{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color requested.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int* R,\n                                                       unsigned int* G,\n                                                       unsigned int* B,\n                                                       unsigned int* A);\n\n// Experimental API.\n// Check if the annotation is of a type that has attachment points\n// (i.e. quadpoints). Quadpoints are the vertices of the rectangle that\n// encompasses the texts affected by the annotation. They provide the\n// coordinates in the page where the annotation is attached. Only text markup\n// annotations (i.e. highlight, strikeout, squiggly, and underline) and link\n// annotations have quadpoints.\n//\n//   annot  - handle to an annotation.\n//\n// Returns true if the annotation is of a type that has quadpoints, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Replace the attachment points (i.e. quadpoints) set of an annotation at\n// |quad_index|. This index needs to be within the result of\n// FPDFAnnot_CountAttachmentPoints().\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Append to the list of attachment points (i.e. quadpoints) of an annotation.\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,\n                                 const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Get the number of sets of quadpoints of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of sets of quadpoints, or 0 on failure.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the attachment points (i.e. quadpoints) of an annotation.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - receives the quadpoints; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Set the annotation rectangle defining the location of the annotation. If the\n// annotation's appearance stream is defined and this annotation is of a type\n// without quadpoints, then update the bounding box too if the new rectangle\n// defines a bigger one.\n//\n//   annot  - handle to an annotation.\n//   rect   - the annotation rectangle to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,\n                                                      const FS_RECTF* rect);\n\n// Experimental API.\n// Get the annotation rectangle defining the location of the annotation.\n//\n//   annot  - handle to an annotation.\n//   rect   - receives the rectangle; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,\n                                                      FS_RECTF* rect);\n\n// Experimental API.\n// Get the vertices of a polygon or polyline annotation. |buffer| is an array of\n// points of the annotation. If |length| is less than the returned length, or\n// |annot| or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points if the annotation is of type polygon or\n// polyline, 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetVertices(FPDF_ANNOTATION annot,\n                      FS_POINTF* buffer,\n                      unsigned long length);\n\n// Experimental API.\n// Get the number of paths in the ink list of an ink annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//\n// Returns the number of paths in the ink list if the annotation is of type ink,\n// 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get a path in the ink list of an ink annotation. |buffer| is an array of\n// points of the path. If |length| is less than the returned length, or |annot|\n// or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   path_index - index of the path\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points of the path if the annotation is of type ink, 0\n// otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot,\n                         unsigned long path_index,\n                         FS_POINTF* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Get the starting and ending coordinates of a line annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   start - starting point\n//   end - ending point\n//\n// Returns true if the annotation is of type line, |start| and |end| are not\n// NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,\n                                                      FS_POINTF* start,\n                                                      FS_POINTF* end);\n\n// Experimental API.\n// Set the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if setting the border for |annot| succeeds, false otherwise.\n//\n// If |annot| contains an appearance stream that overrides the border values,\n// then the appearance stream will be removed on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot,\n                                                        float horizontal_radius,\n                                                        float vertical_radius,\n                                                        float border_width);\n\n// Experimental API.\n// Get the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are\n// not NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetBorder(FPDF_ANNOTATION annot,\n                    float* horizontal_radius,\n                    float* vertical_radius,\n                    float* border_width);\n\n// Experimental API.\n// Get the JavaScript of an event of the annotation's additional actions.\n// |buffer| is only modified if |buflen| is large enough to hold the whole\n// JavaScript string. If |buflen| is smaller, the total size of the JavaScript\n// is still returned, but nothing is copied.  If there is no JavaScript for\n// |event| in |annot|, an empty string is written to |buf| and 2 is returned,\n// denoting the size of the null terminator in the buffer.  On other errors,\n// nothing is written to |buffer| and 0 is returned.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    event       -   event type, one of the FPDF_ANNOT_AACTION_* values.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes, including the 2-byte\n// null terminator.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle,\n                                            FPDF_ANNOTATION annot,\n                                            int event,\n                                            FPDF_WCHAR* buffer,\n                                            unsigned long buflen);\n\n// Experimental API.\n// Check if |annot|'s dictionary has |key| as a key.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,\n                                                     FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in |annot|'s dictionary.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in |annot|'s dictionary,\n// overwriting the existing value if any. The value type would be\n// FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the dictionary entry to be set, encoded in UTF-8.\n//   value  - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in |annot|'s dictionary. |buffer|\n// is only modified if |buflen| is longer than the length of contents. Note that\n// if |key| does not exist in the dictionary or if |key|'s corresponding value\n// in the dictionary is not a string (i.e. the value is not of type\n// FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied\n// to |buffer| and the return value would be 2. On other errors, nothing would\n// be added to |buffer| and the return value would be 0.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   buffer - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Get the float value corresponding to |key| in |annot|'s dictionary. Writes\n// value to |value| and returns True if |key| exists in the dictionary and\n// |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False\n// otherwise.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   value  - receives the value, must not be NULL.\n//\n// Returns True if value found, False otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         float* value);\n\n// Experimental API.\n// Set the AP (appearance string) in |annot|'s dictionary for a given\n// |appearanceMode|.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   value          - the string value to be set, encoded in UTF-16LE. If\n//                    nullptr is passed, the AP is cleared for that mode. If the\n//                    mode is Normal, APs for all modes are cleared.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the AP (appearance string) from |annot|'s dictionary for a given\n// |appearanceMode|.\n// |buffer| is only modified if |buflen| is large enough to hold the whole AP\n// string. If |buflen| is smaller, the total size of the AP is still returned,\n// but nothing is copied.\n// If there is no appearance stream for |annot| in |appearanceMode|, an empty\n// string is written to |buf| and 2 is returned.\n// On other errors, nothing is written to |buffer| and 0 is returned.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   buffer         - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen         - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WCHAR* buffer,\n                unsigned long buflen);\n\n// Experimental API.\n// Get the annotation corresponding to |key| in |annot|'s dictionary. Common\n// keys for linking annotations include \"IRT\" and \"Popup\". Must call\n// FPDFPage_CloseAnnot() when the annotation returned by this function is no\n// longer needed.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//\n// Returns a handle to the linked annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//   annot    - handle to an annotation.\n//\n// Returns the annotation flags.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the |annot|'s flags to be of the value |flags|.\n//\n//   annot      - handle to an annotation.\n//   flags      - the flag values to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,\n                                                       int flags);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the annotation flags specific to interactive forms.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Sets the form field flags for an interactive form annotation.\n//\n//   handle       -   the handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//   annot        -   handle to an interactive form annotation.\n//   flags        -   the form field flags to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot,\n                            int flags);\n\n// Experimental API.\n// Retrieves an interactive form annotation whose rectangle contains a given\n// point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned\n// is no longer needed.\n//\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    page        -   handle to the page, returned by FPDF_LoadPage function.\n//    point       -   position in PDF \"user space\".\n//\n// Returns the interactive form annotation whose rectangle contains the given\n// coordinates on the page. If there is no such annotation, return NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                              FPDF_PAGE page,\n                              const FS_POINTF* point);\n\n// Experimental API.\n// Gets the name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the name string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,\n                           FPDF_ANNOTATION annot,\n                           FPDF_WCHAR* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Gets the alternate name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the alternate name string, encoded in\n//                    UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle,\n                                    FPDF_ANNOTATION annot,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen);\n\n// Experimental API.\n// Gets the form field type of |annot|, which is an interactive form annotation.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on\n// success. Returns -1 on error.\n// See field types in fpdf_formfill.h.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the value of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,\n                            FPDF_ANNOTATION annot,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen);\n\n// Experimental API.\n// Get the number of options in the |annot|'s \"Opt\" dictionary. Intended for\n// use with listbox and combobox widget annotations.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns the number of options in \"Opt\" dictionary on success. Return value\n// will be -1 if annotation does not have an \"Opt\" dictionary or other error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the string value for the label of the option at |index| in |annot|'s\n// \"Opt\" dictionary. Intended for use with listbox and combobox widget\n// annotations. |buffer| is only modified if |buflen| is longer than the length\n// of contents. If index is out of range or in case of other error, nothing\n// will be added to |buffer| and the return value will be 0. Note that\n// return value of empty string is 2 for \"\\0\\0\".\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array\n//   buffer  - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen  - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\n// If |annot| does not have an \"Opt\" array, |index| is out of range or if any\n// other error occurs, returns 0.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,\n                         FPDF_ANNOTATION annot,\n                         int index,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Determine whether or not the option at |index| in |annot|'s \"Opt\" dictionary\n// is selected. Intended for use with listbox and combobox widget annotations.\n//\n//   handle  - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array.\n//\n// Returns true if the option at |index| in |annot|'s \"Opt\" dictionary is\n// selected, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,\n                           FPDF_ANNOTATION annot,\n                           int index);\n\n// Experimental API.\n// Get the float value of the font size for an |annot| with variable text.\n// If 0, the font is to be auto-sized: its size is computed as a function of\n// the height of the annotation rectangle.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   value   - Required. Float which will be set to font size on success.\n//\n// Returns true if the font size was set in |value|, false on error or if\n// |value| not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,\n                      FPDF_ANNOTATION annot,\n                      float* value);\n\n// Experimental API.\n// Set the text color of an annotation.\n//\n//   handle   - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R        - the red component for the text color.\n//   G        - the green component for the text color.\n//   B        - the blue component for the text color.\n//\n// Returns true if successful.\n//\n// Currently supported subtypes: freetext.\n// The range for the color components is 0 to 255.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int R,\n                       unsigned int G,\n                       unsigned int B);\n\n// Experimental API.\n// Get the RGB value of the font color for an |annot| with variable text.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//\n// Returns true if the font color was set, false on error or if the font\n// color was not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int* R,\n                       unsigned int* G,\n                       unsigned int* B);\n\n// Experimental API.\n// Determine if |annot| is a form widget that is checked. Intended for use with\n// checkbox and radio button widgets.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns true if |annot| is a form widget and is checked, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,\n                                                        FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the list of focusable annotation subtypes. Annotations of subtype\n// FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API\n// will override the existing subtypes.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - list of annotation subtype which can be tabbed over.\n//   count    - total number of annotation subtype in list.\n// Returns true if list of annotation subtype is set successfully, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               const FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Get the count of focusable annotation subtypes as set by host\n// for a |hHandle|.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n// Returns the count of focusable annotation subtypes or -1 on error.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Get the list of focusable annotation subtype as set by host.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - receives the list of annotation subtype which can be tabbed\n//              over. Caller must have allocated |subtypes| more than or\n//              equal to the count obtained from\n//              FPDFAnnot_GetFocusableSubtypesCount() API.\n//   count    - size of |subtypes|.\n// Returns true on success and set list of annotation subtype to |subtypes|,\n// false otherwise.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Gets FPDF_LINK object for |annot|. Intended to use for link annotations.\n//\n//   annot   - handle to an annotation.\n//\n// Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure,\n// if the input annot is NULL or input annot's subtype is not link.\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the count of annotations in the |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns number of controls in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the index of |annot| in |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns index of a given |annot| in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the export value of |annot| which is an interactive form annotation.\n// Intended for use with radio button and checkbox widget annotations.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value\n// will be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle,\n                                  FPDF_ANNOTATION annot,\n                                  FPDF_WCHAR* buffer,\n                                  unsigned long buflen);\n\n// Experimental API.\n// Add a URI action to |annot|, overwriting the existing action, if any.\n//\n//   annot  - handle to a link annotation.\n//   uri    - the URI to be set, encoded in 7-bit ASCII.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot,\n                                                     const char* uri);\n\n// Experimental API.\n// Get the attachment from |annot|.\n//\n//   annot - handle to a file annotation.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add an embedded file with |name| to |annot|.\n//\n//   annot    - handle to a file annotation.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ANNOT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_attachment.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ATTACHMENT_H_\n#define PUBLIC_FPDF_ATTACHMENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of embedded files in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of embedded files in |document|.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Add an embedded file with |name| in |document|. If |name| is empty, or if\n// |name| is the name of a existing embedded file in |document|, or if\n// |document|'s embedded file name tree is too deep (i.e. |document| has too\n// many embedded files already), then a new attachment will not be added.\n//\n//   document - handle to a document.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name);\n\n// Experimental API.\n// Get the embedded attachment at |index| in |document|. Note that the returned\n// attachment handle is only valid while |document| is open.\n//\n//   document - handle to a document.\n//   index    - the index of the requested embedded file.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Delete the embedded attachment at |index| in |document|. Note that this does\n// not remove the attachment data from the PDF file; it simply removes the\n// file's entry in the embedded files name tree so that it does not appear in\n// the attachment list. This behavior may change in the future.\n//\n//   document - handle to a document.\n//   index    - the index of the embedded file to be deleted.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Get the name of the |attachment| file. |buffer| is only modified if |buflen|\n// is longer than the length of the file name. On errors, |buffer| is unmodified\n// and the returned length is 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the file name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetName(FPDF_ATTACHMENT attachment,\n                       FPDF_WCHAR* buffer,\n                       unsigned long buflen);\n\n// Experimental API.\n// Check if the params dictionary of |attachment| has |key| as a key.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in the params dictionary of\n// the embedded |attachment|.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|, overwriting the existing value if any. The value\n// type should be FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the dictionary entry, encoded in UTF-8.\n//   value      - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|. |buffer| is only modified if |buflen| is longer\n// than the length of the string value. Note that if |key| does not exist in the\n// dictionary or if |key|'s corresponding value in the dictionary is not a\n// string (i.e. the value is not of type FPDF_OBJECT_STRING or\n// FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the\n// return value would be 2. On other errors, nothing would be added to |buffer|\n// and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the requested string value, encoded in UTF-8.\n//   buffer     - buffer for holding the string value encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the dictionary value string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WCHAR* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Set the file data of |attachment|, overwriting the existing file data if any.\n// The creation date and checksum will be updated, while all other dictionary\n// entries will be deleted. Note that only contents with |len| smaller than\n// INT_MAX is supported.\n//\n//   attachment - handle to an attachment.\n//   contents   - buffer holding the file data to write to |attachment|.\n//   len        - length of file data in bytes.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,\n                       FPDF_DOCUMENT document,\n                       const void* contents,\n                       unsigned long len);\n\n// Experimental API.\n// Get the file data of |attachment|.\n// When the attachment file data is readable, true is returned, and |out_buflen|\n// is updated to indicate the file data size. |buffer| is only modified if\n// |buflen| is non-null and long enough to contain the entire file data. Callers\n// must check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data.\n//\n// Otherwise, when the attachment file data is unreadable or when |out_buflen|\n// is null, false is returned and |buffer| and |out_buflen| remain unmodified.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file data from |attachment|.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to the variable that will receive the minimum buffer\n//                size to contain the file data of |attachment|.\n//\n// Returns true on success, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,\n                       void* buffer,\n                       unsigned long buflen,\n                       unsigned long* out_buflen);\n\n// Experimental API.\n// Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is\n// only modified if |buflen| is longer than the length of the MIME type string.\n// If the Subtype is not found or if there is no file stream, an empty string\n// would be copied to |buffer| and the return value would be 2. On other errors,\n// nothing would be added to |buffer| and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the MIME type string encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the MIME type string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment,\n                          FPDF_WCHAR* buffer,\n                          unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ATTACHMENT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_catalog.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_CATALOG_H_\n#define PUBLIC_FPDF_CATALOG_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n//\n// Determine if |document| represents a tagged PDF.\n//\n// For the definition of tagged PDF, See (see 10.7 \"Tagged PDF\" in PDF\n// Reference 1.7).\n//\n//   document - handle to a document.\n//\n// Returns |true| iff |document| is a tagged PDF.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_IsTagged(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Gets the language of |document| from the catalog's /Lang entry.\n//\n//   document - handle to a document.\n//   buffer   - a buffer for the language string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the language string, including the\n// trailing NUL character. The number of bytes is returned regardless of the\n// |buffer| and |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE\n// encoding. The string is terminated by a UTF16 NUL character. If\n// |buflen| is less than the required length, or |buffer| is NULL,\n// |buffer| will not be modified.\n//\n// If |document| has no /Lang entry, an empty string is written to |buffer| and\n// 2 is returned. On error, nothing is written to |buffer| and 0 is returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFCatalog_GetLanguage(FPDF_DOCUMENT document,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen);\n\n// Experimental API.\n// Sets the language of |document| to |language|.\n//\n// document - handle to a document.\n// language - the language to set to.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_CATALOG_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_dataavail.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DATAAVAIL_H_\n#define PUBLIC_FPDF_DATAAVAIL_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#define PDF_LINEARIZATION_UNKNOWN -1\n#define PDF_NOT_LINEARIZED 0\n#define PDF_LINEARIZED 1\n\n#define PDF_DATA_ERROR -1\n#define PDF_DATA_NOTAVAIL 0\n#define PDF_DATA_AVAIL 1\n\n#define PDF_FORM_ERROR -1\n#define PDF_FORM_NOTAVAIL 0\n#define PDF_FORM_AVAIL 1\n#define PDF_FORM_NOTEXIST 2\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Interface for checking whether sections of the file are available.\ntypedef struct _FX_FILEAVAIL {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Reports if the specified data section is currently available. A section is\n  // available if all bytes in the section are available.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the data section in the file.\n  //   size   - the size of the data section.\n  //\n  // Returns true if the specified data section at |offset| of |size|\n  // is available.\n  FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis,\n                           size_t offset,\n                           size_t size);\n} FX_FILEAVAIL;\n\n// Create a document availability provider.\n//\n//   file_avail - pointer to file availability interface.\n//   file       - pointer to a file access interface.\n//\n// Returns a handle to the document availability provider, or NULL on error.\n//\n// FPDFAvail_Destroy() must be called when done with the availability provider.\nFPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,\n                                                      FPDF_FILEACCESS* file);\n\n// Destroy the |avail| document availability provider.\n//\n//   avail - handle to document availability provider to be destroyed.\nFPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail);\n\n// Download hints interface. Used to receive hints for further downloading.\ntypedef struct _FX_DOWNLOADHINTS {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Add a section to be downloaded.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the hint reported to be downloaded.\n  //   size   - the size of the hint reported to be downloaded.\n  //\n  // The |offset| and |size| of the section may not be unique. Part of the\n  // section might be already available. The download manager must deal with\n  // overlapping sections.\n  void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis,\n                     size_t offset,\n                     size_t size);\n} FX_DOWNLOADHINTS;\n\n// Checks if the document is ready for loading, if not, gets download hints.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// Applications should call this function whenever new data arrives, and process\n// all the generated download hints, if any, until the function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|.\n// if hints is nullptr, the function just check current document availability.\n//\n// Once all data is available, call FPDFAvail_GetDocument() to get a document\n// handle.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,\n                                                   FX_DOWNLOADHINTS* hints);\n\n// Get document from the availability provider.\n//\n//   avail    - handle to document availability provider.\n//   password - password for decrypting the PDF file. Optional.\n//\n// Returns a handle to the document.\n//\n// When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to\n// retrieve the document handle.\n// See the comments for FPDF_LoadDocument() regarding the encoding for\n// |password|.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password);\n\n// Get the page number for the first available page in a linearized PDF.\n//\n//   doc - document handle.\n//\n// Returns the zero-based index for the first available page.\n//\n// For most linearized PDFs, the first available page will be the first page,\n// however, some PDFs might make another page the first available page.\n// For non-linearized PDFs, this function will always return zero.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc);\n\n// Check if |page_index| is ready for loading, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail      - handle to document availability provider.\n//   page_index - index number of the page. Zero for the first page.\n//   hints      - pointer to a download hints interface. Populated if\n//                |page_index| is not available.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// Applications should call this function whenever new data arrives and process\n// all the generated download |hints|, if any, until this function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page\n// loading.\n// if hints is nullptr, the function just check current availability of\n// specified page.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,\n                                                    int page_index,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check if form data is ready for initialization, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface. Populated if form is not\n//           ready for initialization.\n//\n// Returns one of:\n//   PDF_FORM_ERROR: A common eror, in general incorrect parameters.\n//   PDF_FORM_NOTAVAIL: Data not available.\n//   PDF_FORM_AVAIL: Data available.\n//   PDF_FORM_NOTEXIST: No form data.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// The application should call this function whenever new data arrives and\n// process all the generated download |hints|, if any, until the function\n// |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|.\n// if hints is nullptr, the function just check current form availability.\n//\n// Applications can then perform page loading. It is recommend to call\n// FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check whether a document is a linearized PDF.\n//\n//   avail - handle to document availability provider.\n//\n// Returns one of:\n//   PDF_LINEARIZED\n//   PDF_NOT_LINEARIZED\n//   PDF_LINEARIZATION_UNKNOWN\n//\n// FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED|\n// when we have 1k  of data. If the files size less than 1k, it returns\n// |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine\n// if the PDF is linearlized.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DATAAVAIL_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_doc.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DOC_H_\n#define PUBLIC_FPDF_DOC_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported action type.\n#define PDFACTION_UNSUPPORTED 0\n// Go to a destination within current document.\n#define PDFACTION_GOTO 1\n// Go to a destination within another document.\n#define PDFACTION_REMOTEGOTO 2\n// URI, including web pages and other Internet resources.\n#define PDFACTION_URI 3\n// Launch an application or open a file.\n#define PDFACTION_LAUNCH 4\n// Go to a destination in an embedded file.\n#define PDFACTION_EMBEDDEDGOTO 5\n\n// View destination fit types. See pdfmark reference v9, page 48.\n#define PDFDEST_VIEW_UNKNOWN_MODE 0\n#define PDFDEST_VIEW_XYZ 1\n#define PDFDEST_VIEW_FIT 2\n#define PDFDEST_VIEW_FITH 3\n#define PDFDEST_VIEW_FITV 4\n#define PDFDEST_VIEW_FITR 5\n#define PDFDEST_VIEW_FITB 6\n#define PDFDEST_VIEW_FITBH 7\n#define PDFDEST_VIEW_FITBV 8\n\n// The file identifier entry type. See section 14.4 \"File Identifiers\" of the\n// ISO 32000-1:2008 spec.\ntypedef enum {\n  FILEIDTYPE_PERMANENT = 0,\n  FILEIDTYPE_CHANGING = 1\n} FPDF_FILEIDTYPE;\n\n// Get the first child of |bookmark|, or the first top-level bookmark item.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark. Pass NULL for the first top\n//              level item.\n//\n// Returns a handle to the first child of |bookmark| or the first top-level\n// bookmark item. NULL if no child or top-level bookmark found.\n// Note that another name for the bookmarks is the document outline, as\n// described in ISO 32000-1:2008, section 12.3.3.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the next sibling of |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark.\n//\n// Returns a handle to the next sibling of |bookmark|, or NULL if this is the\n// last bookmark at this level.\n//\n// Note that the caller is responsible for handling circular bookmark\n// references, as may arise from malformed documents.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the title of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//   buffer   - buffer for the title. May be NULL.\n//   buflen   - the length of the buffer in bytes. May be 0.\n//\n// Returns the number of bytes in the title, including the terminating NUL\n// character. The number of bytes is returned regardless of the |buffer| and\n// |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |buflen| is less than the\n// required length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Experimental API.\n// Get the number of chlidren of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns a signed integer that represents the number of sub-items the given\n// bookmark has. If the value is positive, child items shall be shown by default\n// (open state). If the value is negative, child items shall be hidden by\n// default (closed state). Please refer to PDF 32000-1:2008, Table 153.\n// Returns 0 if the bookmark has no children or is invalid.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark);\n\n// Find the bookmark with |title| in |document|.\n//\n//   document - handle to the document.\n//   title    - the UTF-16LE encoded Unicode title for which to search.\n//\n// Returns the handle to the bookmark, or NULL if |title| can't be found.\n//\n// FPDFBookmark_Find() will always return the first bookmark found even if\n// multiple bookmarks have the same |title|.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title);\n\n// Get the destination associated with |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the destination data, or NULL if no destination is\n// associated with |bookmark|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the action associated with |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the action data, or NULL if no action is associated\n// with |bookmark|.\n// If this function returns a valid handle, it is valid as long as |bookmark| is\n// valid.\n// If this function returns NULL, FPDFBookmark_GetDest() should be called to get\n// the |bookmark| destination data.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV\nFPDFBookmark_GetAction(FPDF_BOOKMARK bookmark);\n\n// Get the type of |action|.\n//\n//   action - handle to the action.\n//\n// Returns one of:\n//   PDFACTION_UNSUPPORTED\n//   PDFACTION_GOTO\n//   PDFACTION_REMOTEGOTO\n//   PDFACTION_URI\n//   PDFACTION_LAUNCH\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action);\n\n// Get the destination of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. |action| must be a |PDFACTION_GOTO| or\n//              |PDFACTION_REMOTEGOTO|.\n//\n// Returns a handle to the destination data, or NULL on error, typically\n// because the arguments were bad or the action was of the wrong type.\n//\n// In the case of |PDFACTION_REMOTEGOTO|, you must first call\n// FPDFAction_GetFilePath(), then load the document at that path, then pass\n// the document handle from that document as |document| to FPDFAction_GetDest().\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document,\n                                                       FPDF_ACTION action);\n\n// Get the file path of |action|.\n//\n//   action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or\n//            |PDFACTION_REMOTEGOTO|.\n//   buffer - a buffer for output the path string. May be NULL.\n//   buflen - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen);\n\n// Get the URI path of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. Must be a |PDFACTION_URI|.\n//   buffer   - a buffer for the path string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the URI path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// The |buffer| may contain badly encoded data. The caller should validate the\n// output. e.g. Check to see if it is UTF-8.\n//\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\n//\n// Historically, the documentation for this API claimed |buffer| is always\n// encoded in 7-bit ASCII, but did not actually enforce it.\n// https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592\n// added that enforcement, but that did not work well for real world PDFs that\n// used UTF-8. As of this writing, this API reverted back to its original\n// behavior prior to commit d609e84cee.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetURIPath(FPDF_DOCUMENT document,\n                      FPDF_ACTION action,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Get the page index of |dest|.\n//\n//   document - handle to the document.\n//   dest     - handle to the destination.\n//\n// Returns the 0-based page index containing |dest|. Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document,\n                                                        FPDF_DEST dest);\n\n// Experimental API.\n// Get the view (fit type) specified by |dest|.\n//\n//   dest         - handle to the destination.\n//   pNumParams   - receives the number of view parameters, which is at most 4.\n//   pParams      - buffer to write the view parameters. Must be at least 4\n//                  FS_FLOATs long.\n// Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if\n// |dest| does not specify a view.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams);\n\n// Get the (x, y, zoom) location of |dest| in the destination page, if the\n// destination is in [page /XYZ x y zoom] syntax.\n//\n//   dest       - handle to the destination.\n//   hasXVal    - out parameter; true if the x value is not null\n//   hasYVal    - out parameter; true if the y value is not null\n//   hasZoomVal - out parameter; true if the zoom value is not null\n//   x          - out parameter; the x coordinate, in page coordinates.\n//   y          - out parameter; the y coordinate, in page coordinates.\n//   zoom       - out parameter; the zoom value.\n// Returns TRUE on successfully reading the /XYZ value.\n//\n// Note the [x, y, zoom] values are only set if the corresponding hasXVal,\n// hasYVal or hasZoomVal flags are true.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDest_GetLocationInPage(FPDF_DEST dest,\n                           FPDF_BOOL* hasXVal,\n                           FPDF_BOOL* hasYVal,\n                           FPDF_BOOL* hasZoomVal,\n                           FS_FLOAT* x,\n                           FS_FLOAT* y,\n                           FS_FLOAT* zoom);\n\n// Find a link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns a handle to the link, or NULL if no link found at the given point.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Find the Z-order of link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns the Z-order of the link, or -1 if no link found at the given point.\n// Larger Z-order numbers are closer to the front.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Get destination info for |link|.\n//\n//   document - handle to the document.\n//   link     - handle to the link.\n//\n// Returns a handle to the destination, or NULL if there is no destination\n// associated with the link. In this case, you should call FPDFLink_GetAction()\n// to retrieve the action associated with |link|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document,\n                                                     FPDF_LINK link);\n\n// Get action info for |link|.\n//\n//   link - handle to the link.\n//\n// Returns a handle to the action associated to |link|, or NULL if no action.\n// If this function returns a valid handle, it is valid as long as |link| is\n// valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link);\n\n// Enumerates all the link annotations in |page|.\n//\n//   page       - handle to the page.\n//   start_pos  - the start position, should initially be 0 and is updated with\n//                the next start position on return.\n//   link_annot - the link handle for |startPos|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page,\n                                                       int* start_pos,\n                                                       FPDF_LINK* link_annot);\n\n// Experimental API.\n// Gets FPDF_ANNOTATION object for |link_annot|.\n//\n//   page       - handle to the page in which FPDF_LINK object is present.\n//   link_annot - handle to link annotation.\n//\n// Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure,\n// if the input link annot or page is NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot);\n\n// Get the rectangle for |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//   rect       - the annotation rectangle.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot,\n                                                          FS_RECTF* rect);\n\n// Get the count of quadrilateral points to the |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//\n// Returns the count of quadrilateral points.\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot);\n\n// Get the quadrilateral points for the specified |quad_index| in |link_annot|.\n//\n//   link_annot  - handle to the link annotation.\n//   quad_index  - the specified quad point index.\n//   quad_points - receives the quadrilateral points.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetQuadPoints(FPDF_LINK link_annot,\n                       int quad_index,\n                       FS_QUADPOINTSF* quad_points);\n\n// Experimental API\n// Gets an additional-action from |page|.\n//\n//   page      - handle to the page, as returned by FPDF_LoadPage().\n//   aa_type   - the type of the page object's addtional-action, defined\n//               in public/fpdf_formfill.h\n//\n//   Returns the handle to the action data, or NULL if there is no\n//   additional-action of type |aa_type|.\n//   If this function returns a valid handle, it is valid as long as |page| is\n//   valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page,\n                                                          int aa_type);\n\n// Experimental API.\n// Get the file identifer defined in the trailer of |document|.\n//\n//   document - handle to the document.\n//   id_type  - the file identifier type to retrieve.\n//   buffer   - a buffer for the file identifier. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file identifier, including the NUL\n// terminator.\n//\n// The |buffer| is always a byte string. The |buffer| is followed by a NUL\n// terminator.  If |buflen| is less than the returned length, or |buffer| is\n// NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetFileIdentifier(FPDF_DOCUMENT document,\n                       FPDF_FILEIDTYPE id_type,\n                       void* buffer,\n                       unsigned long buflen);\n\n// Get meta-data |tag| content from |document|.\n//\n//   document - handle to the document.\n//   tag      - the tag to retrieve. The tag can be one of:\n//                Title, Author, Subject, Keywords, Creator, Producer,\n//                CreationDate, or ModDate.\n//              For detailed explanations of these tags and their respective\n//              values, please refer to PDF Reference 1.6, section 10.2.1,\n//              'Document Information Dictionary'.\n//   buffer   - a buffer for the tag. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the tag, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// For linearized files, FPDFAvail_IsFormAvail must be called before this, and\n// it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there\n// is no guarantee the metadata has been loaded.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document,\n                                                         FPDF_BYTESTRING tag,\n                                                         void* buffer,\n                                                         unsigned long buflen);\n\n// Get the page label for |page_index| from |document|.\n//\n//   document    - handle to the document.\n//   page_index  - the 0-based index of the page.\n//   buffer      - a buffer for the page label. May be NULL.\n//   buflen      - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the page label, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetPageLabel(FPDF_DOCUMENT document,\n                  int page_index,\n                  void* buffer,\n                  unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DOC_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_edit.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EDIT_H_\n#define PUBLIC_FPDF_EDIT_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n#define FPDF_ARGB(a, r, g, b)                                      \\\n  ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \\\n              (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24)))\n#define FPDF_GetBValue(argb) ((uint8_t)(argb))\n#define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8))\n#define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16))\n#define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24))\n\n// Refer to PDF Reference version 1.7 table 4.12 for all color space families.\n#define FPDF_COLORSPACE_UNKNOWN 0\n#define FPDF_COLORSPACE_DEVICEGRAY 1\n#define FPDF_COLORSPACE_DEVICERGB 2\n#define FPDF_COLORSPACE_DEVICECMYK 3\n#define FPDF_COLORSPACE_CALGRAY 4\n#define FPDF_COLORSPACE_CALRGB 5\n#define FPDF_COLORSPACE_LAB 6\n#define FPDF_COLORSPACE_ICCBASED 7\n#define FPDF_COLORSPACE_SEPARATION 8\n#define FPDF_COLORSPACE_DEVICEN 9\n#define FPDF_COLORSPACE_INDEXED 10\n#define FPDF_COLORSPACE_PATTERN 11\n\n// The page object constants.\n#define FPDF_PAGEOBJ_UNKNOWN 0\n#define FPDF_PAGEOBJ_TEXT 1\n#define FPDF_PAGEOBJ_PATH 2\n#define FPDF_PAGEOBJ_IMAGE 3\n#define FPDF_PAGEOBJ_SHADING 4\n#define FPDF_PAGEOBJ_FORM 5\n\n// The path segment constants.\n#define FPDF_SEGMENT_UNKNOWN -1\n#define FPDF_SEGMENT_LINETO 0\n#define FPDF_SEGMENT_BEZIERTO 1\n#define FPDF_SEGMENT_MOVETO 2\n\n#define FPDF_FILLMODE_NONE 0\n#define FPDF_FILLMODE_ALTERNATE 1\n#define FPDF_FILLMODE_WINDING 2\n\n#define FPDF_FONT_TYPE1 1\n#define FPDF_FONT_TRUETYPE 2\n\n#define FPDF_LINECAP_BUTT 0\n#define FPDF_LINECAP_ROUND 1\n#define FPDF_LINECAP_PROJECTING_SQUARE 2\n\n#define FPDF_LINEJOIN_MITER 0\n#define FPDF_LINEJOIN_ROUND 1\n#define FPDF_LINEJOIN_BEVEL 2\n\n// See FPDF_SetPrintMode() for descriptions.\n#define FPDF_PRINTMODE_EMF 0\n#define FPDF_PRINTMODE_TEXTONLY 1\n#define FPDF_PRINTMODE_POSTSCRIPT2 2\n#define FPDF_PRINTMODE_POSTSCRIPT3 3\n#define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4\n#define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5\n#define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8\n\ntypedef struct FPDF_IMAGEOBJ_METADATA {\n  // The image width in pixels.\n  unsigned int width;\n  // The image height in pixels.\n  unsigned int height;\n  // The image's horizontal pixel-per-inch.\n  float horizontal_dpi;\n  // The image's vertical pixel-per-inch.\n  float vertical_dpi;\n  // The number of bits used to represent each pixel.\n  unsigned int bits_per_pixel;\n  // The image's colorspace. See above for the list of FPDF_COLORSPACE_*.\n  int colorspace;\n  // The image's marked content ID. Useful for pairing with associated alt-text.\n  // A value of -1 indicates no ID.\n  int marked_content_id;\n} FPDF_IMAGEOBJ_METADATA;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Create a new PDF document.\n//\n// Returns a handle to a new document, or NULL on failure.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument();\n\n// Create a new PDF page.\n//\n//   document   - handle to document.\n//   page_index - suggested 0-based index of the page to create. If it is larger\n//                than document's current last index(L), the created page index\n//                is the next available index -- L+1.\n//   width      - the page width in points.\n//   height     - the page height in points.\n//\n// Returns the handle to the new page or NULL on failure.\n//\n// The page should be closed with FPDF_ClosePage() when finished as\n// with any other page in the document.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,\n                                                 int page_index,\n                                                 double width,\n                                                 double height);\n\n// Delete the page at |page_index|.\n//\n//   document   - handle to document.\n//   page_index - the index of the page to delete.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,\n                                               int page_index);\n\n// Experimental API.\n// Move the given pages to a new index position.\n//\n//  page_indices     - the ordered list of pages to move. No duplicates allowed.\n//  page_indices_len - the number of elements in |page_indices|\n//  dest_page_index  - the new index position to which the pages in\n//                     |page_indices| are moved.\n//\n// Returns TRUE on success. If it returns FALSE, the document may be left in an\n// indeterminate state.\n//\n// Example: The PDF document starts out with pages [A, B, C, D], with indices\n// [0, 1, 2, 3].\n//\n// >  Move(doc, [3, 2], 2, 1); // returns true\n// >  // The document has pages [A, D, C, B].\n// >\n// >  Move(doc, [0, 4, 3], 3, 1); // returns false\n// >  // Returned false because index 4 is out of range.\n// >\n// >  Move(doc, [0, 3, 1], 3, 2); // returns false\n// >  // Returned false because index 2 is out of range for 3 page indices.\n// >\n// >  Move(doc, [2, 2], 2, 0); // returns false\n// >  // Returned false because [2, 2] contains duplicates.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_MovePages(FPDF_DOCUMENT document,\n               const int* page_indices,\n               unsigned long page_indices_len,\n               int dest_page_index);\n\n// Get the rotation of |page|.\n//\n//   page - handle to a page\n//\n// Returns one of the following indicating the page rotation:\n//   0 - No rotation.\n//   1 - Rotated 90 degrees clockwise.\n//   2 - Rotated 180 degrees clockwise.\n//   3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page);\n\n// Set rotation for |page|.\n//\n//   page   - handle to a page.\n//   rotate - the rotation value, one of:\n//              0 - No rotation.\n//              1 - Rotated 90 degrees clockwise.\n//              2 - Rotated 180 degrees clockwise.\n//              3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate);\n\n// Insert |page_object| into |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object. The |page_object| will be\n//                 automatically freed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Insert |page_object| into |page| at the specified |index|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object as previously obtained by\n//                 FPDFPageObj_CreateNew{Path|Rect}() or\n//                 FPDFPageObj_New{Text|Image}Obj(). Ownership of the object\n//                 is transferred back to PDFium.\n//   index       - the index position to insert the object at. If index equals\n//                 the current object count, the object will be appended to the\n//                 end. If index is greater than the object count, the function\n//                 will fail and return false.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_InsertObjectAtIndex(FPDF_PAGE page,\n                             FPDF_PAGEOBJECT page_object,\n                             size_t index);\n\n// Experimental API.\n// Remove |page_object| from |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object to be removed.\n//\n// Returns TRUE on success.\n//\n// Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free\n// it.\n// Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all\n// FPDF_TEXTPAGE handles for |page| are no longer valid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Get number of page objects inside |page|.\n//\n//   page - handle to a page.\n//\n// Returns the number of objects in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page);\n\n// Get object in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of a page object.\n//\n// Returns the handle to the page object, or NULL on failed.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,\n                                                             int index);\n\n// Checks if |page| contains transparency.\n//\n//   page - handle to a page.\n//\n// Returns TRUE if |page| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page);\n\n// Generate the content of |page|.\n//\n//   page - handle to a page.\n//\n// Returns TRUE on success.\n//\n// Before you save the page to a file, or reload the page, you must call\n// |FPDFPage_GenerateContent| or any changes to |page| will be lost.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page);\n\n// Destroy |page_object| by releasing its resources. |page_object| must have\n// been created by FPDFPageObj_CreateNew{Path|Rect}() or\n// FPDFPageObj_New{Text|Image}Obj(). This function must be called on\n// newly-created objects if they are not added to a page through\n// FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject().\n//\n//   page_object - handle to a page object.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object);\n\n// Checks if |page_object| contains transparency.\n//\n//   page_object - handle to a page object.\n//\n// Returns TRUE if |page_object| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object);\n\n// Get type of |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on\n// error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Gets active state for |page_object| within page.\n//\n//   page_object - handle to a page object.\n//   active      - pointer to variable that will receive if the page object is\n//                 active. This is a required parameter. Not filled if FALSE\n//                 is returned.\n//\n// For page objects where |active| is filled with FALSE, the |page_object| is\n// treated as if it wasn't in the document even though it is still held\n// internally.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active);\n\n// Experimental API.\n// Sets if |page_object| is active within page.\n//\n//   page_object - handle to a page object.\n//   active      - a boolean specifying if the object is active.\n//\n// Returns TRUE on success.\n//\n// Page objects all start in the active state by default, and remain in that\n// state unless this function is called.\n//\n// When |active| is false, this makes the |page_object| be treated as if it\n// wasn't in the document even though it is still held internally.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active);\n\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   a           - matrix value.\n//   b           - matrix value.\n//   c           - matrix value.\n//   d           - matrix value.\n//   e           - matrix value.\n//   f           - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page_object|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,\n                      double a,\n                      double b,\n                      double c,\n                      double d,\n                      double e,\n                      double f);\n\n// Experimental API.\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   matrix      - the transform matrix.\n//\n// Returns TRUE on success.\n//\n// This can be used to scale, rotate, shear and translate the |page_object|.\n// It is an improved version of FPDFPageObj_Transform() that does not do\n// unnecessary double to float conversions, and only uses 1 parameter for the\n// matrix. It also returns whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Experimental API.\n// Get the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct to receive the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and used to scale, rotate, shear and translate the page object.\n//\n// For page objects outside form objects, the matrix values are relative to the\n// page that contains it.\n// For page objects inside form objects, the matrix values are relative to the\n// form that contains it.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix);\n\n// Experimental API.\n// Set the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct with the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the page object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Transform all annotations in |page|.\n//\n//   page - handle to a page.\n//   a    - matrix value.\n//   b    - matrix value.\n//   c    - matrix value.\n//   d    - matrix value.\n//   e    - matrix value.\n//   f    - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page| annotations.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,\n                                                        double a,\n                                                        double b,\n                                                        double c,\n                                                        double d,\n                                                        double e,\n                                                        double f);\n\n// Create a new image object.\n//\n//   document - handle to a document.\n//\n// Returns a handle to a new image object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewImageObj(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the marked content ID for the object.\n//\n//   page_object - handle to a page object.\n//\n// Returns the page object's marked content ID, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of content marks in |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns the number of content marks in |page_object|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get content mark in |page_object| at |index|.\n//\n//   page_object - handle to a page object.\n//   index       - the index of a page object.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index);\n\n// Experimental API.\n// Add a new content mark to a |page_object|.\n//\n//   page_object - handle to a page object.\n//   name        - the name (tag) of the mark.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name);\n\n// Experimental API.\n// Removes a content |mark| from a |page_object|.\n// The mark handle will be invalid after the removal.\n//\n//   page_object - handle to a page object.\n//   mark        - handle to a content mark in that object to remove.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the name of a content mark.\n//\n//   mark       - handle to a content mark.\n//   buffer     - buffer for holding the returned name in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the name.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen,\n                        unsigned long* out_buflen);\n\n// Experimental API.\n// Get the number of key/value pair parameters in |mark|.\n//\n//   mark   - handle to a content mark.\n//\n// Returns the number of key/value pair parameters |mark|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the key of a property in a content mark.\n//\n//   mark       - handle to a content mark.\n//   index      - index of the property.\n//   buffer     - buffer for holding the returned key in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the key.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,\n                            unsigned long index,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen,\n                            unsigned long* out_buflen);\n\n// Experimental API.\n// Get the type of the value of a property in a content mark by key.\n//\n//   mark   - handle to a content mark.\n//   key    - string key of the property.\n//\n// Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as int.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,\n                                 FPDF_BYTESTRING key,\n                                 int* out_value);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as float.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark,\n                                   FPDF_BYTESTRING key,\n                                   float* out_value);\n\n// Experimental API.\n// Get the value of a string property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value in UTF-16LE. This is\n//                only modified if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,\n                                    FPDF_BYTESTRING key,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen,\n                                    unsigned long* out_buflen);\n\n// Experimental API.\n// Get the value of a blob property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value. This is only modified\n//                if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key,\n                                  unsigned char* buffer,\n                                  unsigned long buflen,\n                                  unsigned long* out_buflen);\n\n// Experimental API.\n// Set the value of an int property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - int value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,\n                            FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key,\n                            int value);\n\n// Experimental API.\n// Set the value of a float property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - float value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document,\n                              FPDF_PAGEOBJECT page_object,\n                              FPDF_PAGEOBJECTMARK mark,\n                              FPDF_BYTESTRING key,\n                              float value);\n\n// Experimental API.\n// Set the value of a string property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - string value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,\n                               FPDF_PAGEOBJECT page_object,\n                               FPDF_PAGEOBJECTMARK mark,\n                               FPDF_BYTESTRING key,\n                               FPDF_BYTESTRING value);\n\n// Experimental API.\n// Set the value of a blob property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - pointer to blob value to set.\n//   value_len   - size in bytes of |value|.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,\n                             FPDF_PAGEOBJECT page_object,\n                             FPDF_PAGEOBJECTMARK mark,\n                             FPDF_BYTESTRING key,\n                             const unsigned char* value,\n                             unsigned long value_len);\n\n// Experimental API.\n// Removes a property from a content mark by key.\n//\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,\n                          int count,\n                          FPDF_PAGEOBJECT image_object,\n                          FPDF_FILEACCESS* file_access);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value. This function loads the JPEG image inline, so the image\n// content is copied to the file. This allows |file_access| and its associated\n// data to be deleted after this function returns.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,\n                                int count,\n                                FPDF_PAGEOBJECT image_object,\n                                FPDF_FILEACCESS* file_access);\n\n// TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable.\n//\n// Set the transform matrix of |image_object|.\n//\n//   image_object - handle to an image object.\n//   a            - matrix value.\n//   b            - matrix value.\n//   c            - matrix value.\n//   d            - matrix value.\n//   e            - matrix value.\n//   f            - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |image_object|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,\n                       double a,\n                       double b,\n                       double c,\n                       double d,\n                       double e,\n                       double f);\n\n// Set |bitmap| to |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   bitmap       - handle of the bitmap.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetBitmap(FPDF_PAGE* pages,\n                       int count,\n                       FPDF_PAGEOBJECT image_object,\n                       FPDF_BITMAP bitmap);\n\n// Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only\n// operates on |image_object| and does not take the associated image mask into\n// account. It also ignores the matrix for |image_object|.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   image_object - handle to an image object.\n//\n// Returns the bitmap.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object);\n\n// Experimental API.\n// Get a bitmap rasterization of |image_object| that takes the image mask and\n// image matrix into account. To render correctly, the caller must provide the\n// |document| associated with |image_object|. If there is a |page| associated\n// with |image_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document     - handle to a document associated with |image_object|.\n//   page         - handle to an optional page associated with |image_object|.\n//   image_object - handle to an image object.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                               FPDF_PAGE page,\n                               FPDF_PAGEOBJECT image_object);\n\n// Get the decoded image data of |image_object|. The decoded data is the\n// uncompressed image data, i.e. the raw image data after having all filters\n// applied. |buffer| is only modified if |buflen| is longer than the length of\n// the decoded image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the decoded image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the decoded image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Get the raw image data of |image_object|. The raw data is the image data as\n// stored in the PDF without applying any filters. |buffer| is only modified if\n// |buflen| is longer than the length of the raw image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the raw image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the raw image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Get the number of filters (i.e. decoders) of the image in |image_object|.\n//\n//   image_object - handle to an image object.\n//\n// Returns the number of |image_object|'s filters.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object);\n\n// Get the filter at |index| of |image_object|'s list of filters. Note that the\n// filters need to be applied in order, i.e. the first filter should be applied\n// first, then the second, etc. |buffer| is only modified if |buflen| is longer\n// than the length of the filter string.\n//\n//   image_object - handle to an image object.\n//   index        - the index of the filter requested.\n//   buffer       - buffer for holding filter string, encoded in UTF-8.\n//   buflen       - length of the buffer.\n//\n// Returns the length of the filter string.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,\n                            int index,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Get the image metadata of |image_object|, including dimension, DPI, bits per\n// pixel, and colorspace. If the |image_object| is not an image object or if it\n// does not have an image, then the return value will be false. Otherwise,\n// failure to retrieve any specific parameter would result in its value being 0.\n//\n//   image_object - handle to an image object.\n//   page         - handle to the page that |image_object| is on. Required for\n//                  retrieving the image's bits per pixel and colorspace.\n//   metadata     - receives the image metadata; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,\n                              FPDF_PAGE page,\n                              FPDF_IMAGEOBJ_METADATA* metadata);\n\n// Experimental API.\n// Get the image size in pixels. Faster method to get only image size.\n//\n//   image_object - handle to an image object.\n//   width        - receives the image width in pixels; must not be NULL.\n//   height       - receives the image height in pixels; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object,\n                               unsigned int* width,\n                               unsigned int* height);\n\n// Experimental API.\n// Get ICC profile decoded data of |image_object|. If the |image_object| is not\n// an image object or if it does not have an image, then the return value will\n// be false. It also returns false if the |image_object| has no ICC profile.\n// |buffer| is only modified if ICC profile exists and |buflen| is longer than\n// the length of the ICC profile decoded data.\n//\n//   image_object - handle to an image object; must not be NULL.\n//   page         - handle to the page containing |image_object|; must not be\n//                  NULL. Required for retrieving the image's colorspace.\n//   buffer       - Buffer to receive ICC profile data; may be NULL if querying\n//                  required size via |out_buflen|.\n//   buflen       - Length of the buffer in bytes. Ignored if |buffer| is NULL.\n//   out_buflen   - Pointer to receive the ICC profile data size in bytes; must\n//                  not be NULL. Will be set if this API returns true.\n//\n// Returns true if |out_buflen| is not null and an ICC profile exists for the\n// given |image_object|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object,\n                                      FPDF_PAGE page,\n                                      uint8_t* buffer,\n                                      size_t buflen,\n                                      size_t* out_buflen);\n\n// Create a new path object at an initial position.\n//\n//   x - initial horizontal position.\n//   y - initial vertical position.\n//\n// Returns a handle to a new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,\n                                                                    float y);\n\n// Create a closed path consisting of a rectangle.\n//\n//   x - horizontal position for the left boundary of the rectangle.\n//   y - vertical position for the bottom boundary of the rectangle.\n//   w - width of the rectangle.\n//   h - height of the rectangle.\n//\n// Returns a handle to the new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,\n                                                                    float y,\n                                                                    float w,\n                                                                    float h);\n\n// Get the bounding box of |page_object|.\n//\n// page_object  - handle to a page object.\n// left         - pointer where the left coordinate will be stored\n// bottom       - pointer where the bottom coordinate will be stored\n// right        - pointer where the right coordinate will be stored\n// top          - pointer where the top coordinate will be stored\n//\n// On success, returns TRUE and fills in the 4 coordinates.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,\n                      float* left,\n                      float* bottom,\n                      float* right,\n                      float* top);\n\n// Experimental API.\n// Get the quad points that bounds |page_object|.\n//\n// page_object  - handle to a page object.\n// quad_points  - pointer where the quadrilateral points will be stored.\n//\n// On success, returns TRUE and fills in |quad_points|.\n//\n// Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page\n// object. When the object is rotated by a non-multiple of 90 degrees, this API\n// returns a tighter bound that cannot be represented with just the 4 sides of\n// a rectangle.\n//\n// Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and\n// FPDF_PAGEOBJ_IMAGE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,\n                             FS_QUADPOINTSF* quad_points);\n\n// Set the blend mode of |page_object|.\n//\n// page_object  - handle to a page object.\n// blend_mode   - string containing the blend mode.\n//\n// Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken,\n// Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal,\n// Overlay, Saturation, Screen, SoftLight\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,\n                         FPDF_BYTESTRING blend_mode);\n\n// Set the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's stroke color.\n// G            - the green component for the object's stroke color.\n// B            - the blue component for the object's stroke color.\n// A            - the stroke alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int R,\n                           unsigned int G,\n                           unsigned int B,\n                           unsigned int A);\n\n// Get the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the path stroke color.\n// G            - the green component of the object's stroke color.\n// B            - the blue component of the object's stroke color.\n// A            - the stroke alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int* R,\n                           unsigned int* G,\n                           unsigned int* B,\n                           unsigned int* A);\n\n// Set the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width);\n\n// Get the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width);\n\n// Get the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n//\n// Returns the line join, or -1 on failure.\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object);\n\n// Set the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n// line_join    - line join\n//\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join);\n\n// Get the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line cap, or -1 on failure.\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object);\n\n// Set the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n// line_cap    - line cap\n//\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap);\n\n// Set the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's fill color.\n// G            - the green component for the object's fill color.\n// B            - the blue component for the object's fill color.\n// A            - the fill alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int R,\n                         unsigned int G,\n                         unsigned int B,\n                         unsigned int A);\n\n// Get the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the object's fill color.\n// G            - the green component of the object's fill color.\n// B            - the blue component of the object's fill color.\n// A            - the fill alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int* R,\n                         unsigned int* G,\n                         unsigned int* B,\n                         unsigned int* A);\n\n// Experimental API.\n// Get the line dash |phase| of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - pointer where the dashing phase will be stored.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase);\n\n// Experimental API.\n// Set the line dash phase of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line dash array size or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - pointer where the dashing array will be stored.\n// dash_count - number of elements in |dash_array|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,\n                         float* dash_array,\n                         size_t dash_count);\n\n// Experimental API.\n// Set the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - the dash array.\n// dash_count - number of elements in |dash_array|.\n// phase - the line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,\n                         const float* dash_array,\n                         size_t dash_count,\n                         float phase);\n\n// Get number of segments inside |path|.\n//\n//   path - handle to a path.\n//\n// A segment is a command, created by e.g. FPDFPath_MoveTo(),\n// FPDFPath_LineTo() or FPDFPath_BezierTo().\n//\n// Returns the number of objects in |path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path);\n\n// Get segment in |path| at |index|.\n//\n//   path  - handle to a path.\n//   index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index);\n\n// Get coordinates of |segment|.\n//\n//   segment  - handle to a segment.\n//   x      - the horizontal position of the segment.\n//   y      - the vertical position of the segment.\n//\n// Returns TRUE on success, otherwise |x| and |y| is not set.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y);\n\n// Get type of |segment|.\n//\n//   segment - handle to a segment.\n//\n// Returns one of the FPDF_SEGMENT_* values on success,\n// FPDF_SEGMENT_UNKNOWN on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment);\n\n// Gets if the |segment| closes the current subpath of a given path.\n//\n//   segment - handle to a segment.\n//\n// Returns close flag for non-NULL segment, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment);\n\n// Move a path's current point.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new current point.\n// y      - the vertical position of the new current point.\n//\n// Note that no line will be created between the previous current point and the\n// new one.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a line between the current point and a new point in the path.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new point.\n// y      - the vertical position of the new point.\n//\n// The path's current point is changed to (x, y).\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a cubic Bezier curve to the given path, starting at the current point.\n//\n// path   - the handle to the path object.\n// x1     - the horizontal position of the first Bezier control point.\n// y1     - the vertical position of the first Bezier control point.\n// x2     - the horizontal position of the second Bezier control point.\n// y2     - the vertical position of the second Bezier control point.\n// x3     - the horizontal position of the ending point of the Bezier curve.\n// y3     - the vertical position of the ending point of the Bezier curve.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,\n                                                      float x1,\n                                                      float y1,\n                                                      float x2,\n                                                      float y2,\n                                                      float x3,\n                                                      float y3);\n\n// Close the current subpath of a given path.\n//\n// path   - the handle to the path object.\n//\n// This will add a line between the current point and the initial point of the\n// subpath, thus terminating the current subpath.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path);\n\n// Set the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path should be stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int fillmode,\n                                                         FPDF_BOOL stroke);\n\n// Get the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path is stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int* fillmode,\n                                                         FPDF_BOOL* stroke);\n\n// Create a new text object using one of the standard PDF fonts.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewTextObj(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING font,\n                       float font_size);\n\n// Set the text for a text object. If it had text, it will be replaced.\n//\n// text_object  - handle to the text object.\n// text         - the UTF-16LE encoded string containing the text to be added.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text);\n\n// Experimental API.\n// Set the text using charcodes for a text object. If it had text, it will be\n// replaced.\n//\n// text_object  - handle to the text object.\n// charcodes    - pointer to an array of charcodes to be added.\n// count        - number of elements in |charcodes|.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,\n                      const uint32_t* charcodes,\n                      size_t count);\n\n// Returns a font object loaded from a stream of data. The font is loaded\n// into the document. Various font data structures, such as the ToUnicode data,\n// are auto-generated based on the inputs.\n//\n// document  - handle to the document.\n// data      - the stream of font data, which will be copied by the font object.\n// size      - the size of the font data, in bytes.\n// font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type.\n// cid       - a boolean specifying if the font is a CID font or not.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,\n                                                      const uint8_t* data,\n                                                      uint32_t size,\n                                                      int font_type,\n                                                      FPDF_BOOL cid);\n\n// Experimental API.\n// Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred\n// way of using font style is using a dash to separate the name from the style,\n// for example 'Helvetica-BoldItalic'.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font);\n\n// Experimental API.\n// Returns a font object loaded from a stream of data for a type 2 CID font. The\n// font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode\n// data and the CIDToGIDMap data are caller provided, instead of auto-generated.\n//\n// document                 - handle to the document.\n// font_data                - the stream of font data, which will be copied by\n//                            the font object.\n// font_data_size           - the size of the font data, in bytes.\n// to_unicode_cmap          - the ToUnicode data.\n// cid_to_gid_map_data      - the stream of CIDToGIDMap data.\n// cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadCidType2Font(FPDF_DOCUMENT document,\n                          const uint8_t* font_data,\n                          uint32_t font_data_size,\n                          FPDF_BYTESTRING to_unicode_cmap,\n                          const uint8_t* cid_to_gid_map_data,\n                          uint32_t cid_to_gid_map_data_size);\n\n// Get the font size of a text object.\n//\n//   text - handle to a text.\n//   size - pointer to the font size of the text object, measured in points\n//   (about 1/72 inch)\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size);\n\n// Close a loaded PDF font.\n//\n// font   - Handle to the loaded font.\nFPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font);\n\n// Create a new text object using a loaded font.\n//\n// document   - handle to the document.\n// font       - handle to the font object.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,\n                          FPDF_FONT font,\n                          float font_size);\n\n// Get the text rendering mode of a text object.\n//\n// text     - the handle to the text object.\n//\n// Returns one of the known FPDF_TEXT_RENDERMODE enum values on success,\n// FPDF_TEXTRENDERMODE_UNKNOWN on error.\nFPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV\nFPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Set the text rendering mode of a text object.\n//\n// text         - the handle to the text object.\n// render_mode  - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to\n//                FPDF_TEXTRENDERMODE_UNKNOWN).\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,\n                              FPDF_TEXT_RENDERMODE render_mode);\n\n// Get the text of a text object.\n//\n// text_object      - the handle to the text object.\n// text_page        - the handle to the text page.\n// buffer           - the address of a buffer that receives the text.\n// length           - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the text (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,\n                    FPDF_TEXTPAGE text_page,\n                    FPDF_WCHAR* buffer,\n                    unsigned long length);\n\n// Experimental API.\n// Get a bitmap rasterization of |text_object|. To render correctly, the caller\n// must provide the |document| associated with |text_object|. If there is a\n// |page| associated with |text_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document    - handle to a document associated with |text_object|.\n//   page        - handle to an optional page associated with |text_object|.\n//   text_object - handle to a text object.\n//   scale       - the scaling factor, which must be greater than 0.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                              FPDF_PAGE page,\n                              FPDF_PAGEOBJECT text_object,\n                              float scale);\n\n// Experimental API.\n// Get the font of a text object.\n//\n// text - the handle to the text object.\n//\n// Returns a handle to the font object held by |text| which retains ownership.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Get the base name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the base font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the base name (including the trailing NUL\n// character) on success, 0 on error. The base name is typically the font's\n// PostScript name. See descriptions of \"BaseFont\" in ISO 32000-1:2008 spec.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font,\n                                                          char* buffer,\n                                                          size_t length);\n\n// Experimental API.\n// Get the family name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the family name (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font,\n                                                        char* buffer,\n                                                        size_t length);\n\n// Experimental API.\n// Get the decoded data from the |font| object.\n//\n// font       - The handle to the font object. (Required)\n// buffer     - The address of a buffer that receives the font data.\n// buflen     - Length of the buffer.\n// out_buflen - Pointer to variable that will receive the minimum buffer size\n//              to contain the font data. Not filled if the return value is\n//              FALSE. (Required)\n//\n// Returns TRUE on success. In which case, |out_buflen| will be filled, and\n// |buffer| will be filled if it is large enough. Returns FALSE if any of the\n// required parameters are null.\n//\n// The decoded data is the uncompressed font data. i.e. the raw font data after\n// having all stream filters applied, when the data is embedded.\n//\n// If the font is not embedded, then this API will instead return the data for\n// the substitution font it is using.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font,\n                                                         uint8_t* buffer,\n                                                         size_t buflen,\n                                                         size_t* out_buflen);\n\n// Experimental API.\n// Get whether |font| is embedded or not.\n//\n// font - the handle to the font object.\n//\n// Returns 1 if the font is embedded, 0 if it not, and -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font);\n\n// Experimental API.\n// Get the descriptor flags of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the bit flags specifying various characteristics of the font as\n// defined in ISO 32000-1:2008, table 123, -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font);\n\n// Experimental API.\n// Get the font weight of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the font weight, -1 on failure.\n// Typical values are 400 (normal) and 700 (bold).\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font);\n\n// Experimental API.\n// Get the italic angle of a font.\n//\n// font  - the handle to the font object.\n// angle - pointer where the italic angle will be stored\n//\n// The italic angle of a |font| is defined as degrees counterclockwise\n// from vertical. For a font that slopes to the right, this will be negative.\n//\n// Returns TRUE on success; |angle| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font,\n                                                            int* angle);\n\n// Experimental API.\n// Get ascent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// ascent     - pointer where the font ascent will be stored\n//\n// Ascent is the maximum distance in points above the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |ascent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font,\n                                                       float font_size,\n                                                       float* ascent);\n\n// Experimental API.\n// Get descent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// descent    - pointer where the font descent will be stored\n//\n// Descent is the maximum distance in points below the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |descent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font,\n                                                        float font_size,\n                                                        float* descent);\n\n// Experimental API.\n// Get the width of a glyph in a font.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph.\n// font_size  - the size of the font.\n// width      - pointer where the glyph width will be stored\n//\n// Glyph width is the distance from the end of the prior glyph to the next\n// glyph. This will be the vertical distance for vertical writing.\n//\n// Returns TRUE on success; |width| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font,\n                                                           uint32_t glyph,\n                                                           float font_size,\n                                                           float* width);\n\n// Experimental API.\n// Get the glyphpath describing how to draw a font glyph.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph being drawn.\n// font_size  - the size of the font.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font,\n                                                               uint32_t glyph,\n                                                               float font_size);\n\n// Experimental API.\n// Get number of segments inside glyphpath.\n//\n// glyphpath - handle to a glyph path.\n//\n// Returns the number of objects in |glyphpath| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath);\n\n// Experimental API.\n// Get segment in glyphpath at index.\n//\n// glyphpath  - handle to a glyph path.\n// index      - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index);\n\n// Get number of page objects inside |form_object|.\n//\n//   form_object - handle to a form object.\n//\n// Returns the number of objects in |form_object| on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object);\n\n// Get page object in |form_object| at |index|.\n//\n//   form_object - handle to a form object.\n//   index       - the 0-based index of a page object.\n//\n// Returns the handle to the page object, or NULL on error.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index);\n\n// Experimental API.\n//\n// Remove |page_object| from |form_object|.\n//\n//   form_object - handle to a form object.\n//   page_object - handle to a page object to be removed from the form.\n//\n// Returns TRUE on success.\n//\n// Ownership of the removed |page_object| is transferred to the caller.\n// Call FPDFPageObj_Destroy() on the removed page_object to free it.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object,\n                         FPDF_PAGEOBJECT page_object);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EDIT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_ext.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EXT_H_\n#define PUBLIC_FPDF_EXT_H_\n\n#include <time.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported XFA form.\n#define FPDF_UNSP_DOC_XFAFORM 1\n// Unsupported portable collection.\n#define FPDF_UNSP_DOC_PORTABLECOLLECTION 2\n// Unsupported attachment.\n#define FPDF_UNSP_DOC_ATTACHMENT 3\n// Unsupported security.\n#define FPDF_UNSP_DOC_SECURITY 4\n// Unsupported shared review.\n#define FPDF_UNSP_DOC_SHAREDREVIEW 5\n// Unsupported shared form, acrobat.\n#define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6\n// Unsupported shared form, filesystem.\n#define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7\n// Unsupported shared form, email.\n#define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8\n// Unsupported 3D annotation.\n#define FPDF_UNSP_ANNOT_3DANNOT 11\n// Unsupported movie annotation.\n#define FPDF_UNSP_ANNOT_MOVIE 12\n// Unsupported sound annotation.\n#define FPDF_UNSP_ANNOT_SOUND 13\n// Unsupported screen media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14\n// Unsupported screen rich media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15\n// Unsupported attachment annotation.\n#define FPDF_UNSP_ANNOT_ATTACHMENT 16\n// Unsupported signature annotation.\n#define FPDF_UNSP_ANNOT_SIG 17\n\n// Interface for unsupported feature notifications.\ntypedef struct _UNSUPPORT_INFO {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Unsupported object notification function.\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis - pointer to the interface structure.\n  //   nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries.\n  void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType);\n} UNSUPPORT_INFO;\n\n// Setup an unsupported object handler.\n//\n//   unsp_info - Pointer to an UNSUPPORT_INFO structure.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info);\n\n// Set replacement function for calls to time().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of time(), or\n//          NULL to restore to actual time() call itself.\nFPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)());\n\n// Set replacement function for calls to localtime().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of localtime(), or\n//          NULL to restore to actual localtime() call itself.\nFPDF_EXPORT void FPDF_CALLCONV\nFSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*));\n\n// Unknown page mode.\n#define PAGEMODE_UNKNOWN -1\n// Document outline, and thumbnails hidden.\n#define PAGEMODE_USENONE 0\n// Document outline visible.\n#define PAGEMODE_USEOUTLINES 1\n// Thumbnail images visible.\n#define PAGEMODE_USETHUMBS 2\n// Full-screen mode, no menu bar, window controls, or other decorations visible.\n#define PAGEMODE_FULLSCREEN 3\n// Optional content group panel visible.\n#define PAGEMODE_USEOC 4\n// Attachments panel visible.\n#define PAGEMODE_USEATTACHMENTS 5\n\n// Get the document's PageMode.\n//\n//   doc - Handle to document.\n//\n// Returns one of the |PAGEMODE_*| flags defined above.\n//\n// The page mode defines how the document should be initially displayed.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EXT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_flatten.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FLATTEN_H_\n#define PUBLIC_FPDF_FLATTEN_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flatten operation failed.\n#define FLATTEN_FAIL 0\n// Flatten operation succeed.\n#define FLATTEN_SUCCESS 1\n// Nothing to be flattened.\n#define FLATTEN_NOTHINGTODO 2\n\n// Flatten for normal display.\n#define FLAT_NORMALDISPLAY 0\n// Flatten for print.\n#define FLAT_PRINT 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Flatten annotations and form fields into the page contents.\n//\n//   page  - handle to the page.\n//   nFlag - One of the |FLAT_*| values denoting the page usage.\n//\n// Returns one of the |FLATTEN_*| values.\n//\n// Currently, all failures return |FLATTEN_FAIL| with no indication of the\n// cause.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FLATTEN_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_formfill.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FORMFILL_H_\n#define PUBLIC_FPDF_FORMFILL_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n// These values are return values for a public API, so should not be changed\n// other than the count when adding new values.\n#define FORMTYPE_NONE 0            // Document contains no forms\n#define FORMTYPE_ACRO_FORM 1       // Forms are specified using AcroForm spec\n#define FORMTYPE_XFA_FULL 2        // Forms are specified using entire XFA spec\n#define FORMTYPE_XFA_FOREGROUND 3  // Forms are specified using the XFAF subset\n                                   // of XFA spec\n#define FORMTYPE_COUNT 4           // The number of form types\n\n#define JSPLATFORM_ALERT_BUTTON_OK 0           // OK button\n#define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1     // OK & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNO 2        // Yes & No buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3  // Yes, No & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK\n\n#define JSPLATFORM_ALERT_ICON_ERROR 0     // Error\n#define JSPLATFORM_ALERT_ICON_WARNING 1   // Warning\n#define JSPLATFORM_ALERT_ICON_QUESTION 2  // Question\n#define JSPLATFORM_ALERT_ICON_STATUS 3    // Status\n#define JSPLATFORM_ALERT_ICON_ASTERISK 4  // Asterisk\n#define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR\n\n#define JSPLATFORM_ALERT_RETURN_OK 1      // OK\n#define JSPLATFORM_ALERT_RETURN_CANCEL 2  // Cancel\n#define JSPLATFORM_ALERT_RETURN_NO 3      // No\n#define JSPLATFORM_ALERT_RETURN_YES 4     // Yes\n\n#define JSPLATFORM_BEEP_ERROR 0           // Error\n#define JSPLATFORM_BEEP_WARNING 1         // Warning\n#define JSPLATFORM_BEEP_QUESTION 2        // Question\n#define JSPLATFORM_BEEP_STATUS 3          // Status\n#define JSPLATFORM_BEEP_DEFAULT 4         // Default\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _IPDF_JsPlatform {\n  // Version number of the interface. Currently must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: app_alert\n  //       Pop up a dialog to show warning or hint.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       Msg         -   A string containing the message to be displayed.\n  //       Title       -   The title of the dialog.\n  //       Type        -   The type of button group, one of the\n  //                       JSPLATFORM_ALERT_BUTTON_* values above.\n  //       nIcon       -   The type of the icon, one of the\n  //                       JSPLATFORM_ALERT_ICON_* above.\n  // Return Value:\n  //       Option selected by user in dialogue, one of the\n  //       JSPLATFORM_ALERT_RETURN_* values above.\n  int (*app_alert)(struct _IPDF_JsPlatform* pThis,\n                   FPDF_WIDESTRING Msg,\n                   FPDF_WIDESTRING Title,\n                   int Type,\n                   int Icon);\n\n  // Method: app_beep\n  //       Causes the system to play a sound.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nType       -   The sound type, see JSPLATFORM_BEEP_TYPE_*\n  //                       above.\n  // Return Value:\n  //       None\n  void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType);\n\n  // Method: app_response\n  //       Displays a dialog box containing a question and an entry field for\n  //       the user to reply to the question.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       Question    -   The question to be posed to the user.\n  //       Title       -   The title of the dialog box.\n  //       Default     -   A default value for the answer to the question. If\n  //                       not specified, no default value is presented.\n  //       cLabel      -   A short string to appear in front of and on the\n  //                       same line as the edit text field.\n  //       bPassword   -   If true, indicates that the user's response should\n  //                       be shown as asterisks (*) or bullets (?) to mask\n  //                       the response, which might be sensitive information.\n  //       response    -   A string buffer allocated by PDFium, to receive the\n  //                       user's response.\n  //       length      -   The length of the buffer in bytes. Currently, it is\n  //                       always 2048.\n  // Return Value:\n  //       Number of bytes the complete user input would actually require, not\n  //       including trailing zeros, regardless of the value of the length\n  //       parameter or the presence of the response buffer.\n  // Comments:\n  //       No matter on what platform, the response buffer should be always\n  //       written using UTF-16LE encoding. If a response buffer is\n  //       present and the size of the user input exceeds the capacity of the\n  //       buffer as specified by the length parameter, only the\n  //       first \"length\" bytes of the user input are to be written to the\n  //       buffer.\n  int (*app_response)(struct _IPDF_JsPlatform* pThis,\n                      FPDF_WIDESTRING Question,\n                      FPDF_WIDESTRING Title,\n                      FPDF_WIDESTRING Default,\n                      FPDF_WIDESTRING cLabel,\n                      FPDF_BOOL bPassword,\n                      void* response,\n                      int length);\n\n  // Method: Doc_getFilePath\n  //       Get the file path of the current document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       filePath    -   The string buffer to receive the file path. Can\n  //                       be NULL.\n  //       length      -   The length of the buffer, number of bytes. Can\n  //                       be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in the local encoding.\n  //       The return value always indicated number of bytes required for\n  //       the buffer, even when there is no buffer specified, or the buffer\n  //       size is less than required. In this case, the buffer will not\n  //       be modified.\n  int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis,\n                         void* filePath,\n                         int length);\n\n  // Method: Doc_mail\n  //       Mails the data buffer as an attachment to all recipients, with or\n  //       without user interaction.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       mailData    -   Pointer to the data buffer to be sent. Can be NULL.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       mailData parameter. Can be 0.\n  //       bUI         -   If true, the rest of the parameters are used in a\n  //                       compose-new-message window that is displayed to the\n  //                       user. If false, the cTo parameter is required and\n  //                       all others are optional.\n  //       To          -   A semicolon-delimited list of recipients for the\n  //                       message.\n  //       Subject     -   The subject of the message. The length limit is\n  //                       64 KB.\n  //       CC          -   A semicolon-delimited list of CC recipients for\n  //                       the message.\n  //       BCC         -   A semicolon-delimited list of BCC recipients for\n  //                       the message.\n  //       Msg         -   The content of the message. The length limit is\n  //                       64 KB.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       If the parameter mailData is NULL or length is 0, the current\n  //       document will be mailed as an attachment to all recipients.\n  void (*Doc_mail)(struct _IPDF_JsPlatform* pThis,\n                   void* mailData,\n                   int length,\n                   FPDF_BOOL bUI,\n                   FPDF_WIDESTRING To,\n                   FPDF_WIDESTRING Subject,\n                   FPDF_WIDESTRING CC,\n                   FPDF_WIDESTRING BCC,\n                   FPDF_WIDESTRING Msg);\n\n  // Method: Doc_print\n  //       Prints all or a specific number of pages of the document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis         -   Pointer to the interface structure itself.\n  //       bUI           -   If true, will cause a UI to be presented to the\n  //                         user to obtain printing information and confirm\n  //                         the action.\n  //       nStart        -   A 0-based index that defines the start of an\n  //                         inclusive range of pages.\n  //       nEnd          -   A 0-based index that defines the end of an\n  //                         inclusive page range.\n  //       bSilent       -   If true, suppresses the cancel dialog box while\n  //                         the document is printing. The default is false.\n  //       bShrinkToFit  -   If true, the page is shrunk (if necessary) to\n  //                         fit within the imageable area of the printed page.\n  //       bPrintAsImage -   If true, print pages as an image.\n  //       bReverse      -   If true, print from nEnd to nStart.\n  //       bAnnotations  -   If true (the default), annotations are\n  //                         printed.\n  // Return Value:\n  //       None.\n  void (*Doc_print)(struct _IPDF_JsPlatform* pThis,\n                    FPDF_BOOL bUI,\n                    int nStart,\n                    int nEnd,\n                    FPDF_BOOL bSilent,\n                    FPDF_BOOL bShrinkToFit,\n                    FPDF_BOOL bPrintAsImage,\n                    FPDF_BOOL bReverse,\n                    FPDF_BOOL bAnnotations);\n\n  // Method: Doc_submitForm\n  //       Send the form data to a specified URL.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       formData    -   Pointer to the data buffer to be sent.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       formData parameter.\n  //       URL         -   The URL to send to.\n  // Return Value:\n  //       None.\n  void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis,\n                         void* formData,\n                         int length,\n                         FPDF_WIDESTRING URL);\n\n  // Method: Doc_gotoPage\n  //       Jump to a specified page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nPageNum    -   The specified page number, zero for the first page.\n  // Return Value:\n  //       None.\n  void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum);\n\n  // Method: Field_browse\n  //       Show a file selection dialog, and return the selected file path.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       filePath    -   Pointer to the data buffer to receive the file\n  //                       path. Can be NULL.\n  //       length      -   The length of the buffer, in bytes. Can be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in local encoding.\n  int (*Field_browse)(struct _IPDF_JsPlatform* pThis,\n                      void* filePath,\n                      int length);\n\n  // Pointer for embedder-specific data. Unused by PDFium, and despite\n  // its name, can be any data the embedder desires, though traditionally\n  // a FPDF_FORMFILLINFO interface.\n  void* m_pFormfillinfo;\n\n  // Version 2.\n\n  void* m_isolate;               // Unused in v3, retain for compatibility.\n  unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility.\n\n  // Version 3.\n  // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG.\n} IPDF_JSPLATFORM;\n\n// Flags for Cursor type\n#define FXCT_ARROW 0\n#define FXCT_NESW 1\n#define FXCT_NWSE 2\n#define FXCT_VBEAM 3\n#define FXCT_HBEAM 4\n#define FXCT_HAND 5\n\n// Function signature for the callback function passed to the FFI_SetTimer\n// method.\n// Parameters:\n//          idEvent     -   Identifier of the timer.\n// Return value:\n//          None.\ntypedef void (*TimerCallback)(int idEvent);\n\n// Declares of a struct type to the local system time.\ntypedef struct _FPDF_SYSTEMTIME {\n  unsigned short wYear;         // years since 1900\n  unsigned short wMonth;        // months since January - [0,11]\n  unsigned short wDayOfWeek;    // days since Sunday - [0,6]\n  unsigned short wDay;          // day of the month - [1,31]\n  unsigned short wHour;         // hours since midnight - [0,23]\n  unsigned short wMinute;       // minutes after the hour - [0,59]\n  unsigned short wSecond;       // seconds after the minute - [0,59]\n  unsigned short wMilliseconds; // milliseconds after the second - [0,999]\n} FPDF_SYSTEMTIME;\n\n#ifdef PDF_ENABLE_XFA\n\n// Pageview event flags\n#define FXFA_PAGEVIEWEVENT_POSTADDED 1    // After a new pageview is added.\n#define FXFA_PAGEVIEWEVENT_POSTREMOVED 3  // After a pageview is removed.\n\n// Definitions for Right Context Menu Features Of XFA Fields\n#define FXFA_MENU_COPY 1\n#define FXFA_MENU_CUT 2\n#define FXFA_MENU_SELECTALL 4\n#define FXFA_MENU_UNDO 8\n#define FXFA_MENU_REDO 16\n#define FXFA_MENU_PASTE 32\n\n// Definitions for File Type.\n#define FXFA_SAVEAS_XML 1\n#define FXFA_SAVEAS_XDP 2\n\n#endif  // PDF_ENABLE_XFA\n\ntypedef struct _FPDF_FORMFILLINFO {\n  // Version number of the interface.\n  // Version 1 contains stable interfaces. Version 2 has additional\n  // experimental interfaces.\n  // When PDFium is built without the XFA module, version can be 1 or 2.\n  // With version 1, only stable interfaces are called. With version 2,\n  // additional experimental interfaces are also called.\n  // When PDFium is built with the XFA module, version must be 2.\n  // All the XFA related interfaces are experimental. If PDFium is built with\n  // the XFA module and version 1 then none of the XFA related interfaces\n  // would be called. When PDFium is built with XFA module then the version\n  // must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: Release\n  //       Give the implementation a chance to release any resources after the\n  //       interface is no longer used.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Comments:\n  //       Called by PDFium during the final cleanup process.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //       None\n  void (*Release)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_Invalidate\n  //       Invalidate the client area within the specified rectangle.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage().\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       All positions are measured in PDF \"user space\".\n  //       Implementation should call FPDF_RenderPageBitmap() for repainting\n  //       the specified page area.\n  void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis,\n                         FPDF_PAGE page,\n                         double left,\n                         double top,\n                         double right,\n                         double bottom);\n\n  // Method: FFI_OutputSelectedRect\n  //       When the user selects text in form fields with the mouse, this\n  //       callback function will be invoked with the selected areas.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage()/\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       This callback function is useful for implementing special text\n  //       selection effects. An implementation should first record the\n  //       returned rectangles, then draw them one by one during the next\n  //       painting period. Lastly, it should remove all the recorded\n  //       rectangles when finished painting.\n  void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_PAGE page,\n                                 double left,\n                                 double top,\n                                 double right,\n                                 double bottom);\n\n  // Method: FFI_SetCursor\n  //       Set the Cursor shape.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nCursorType -   Cursor type, see Flags for Cursor type for details.\n  // Return value:\n  //       None.\n  void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType);\n\n  // Method: FFI_SetTimer\n  //       This method installs a system timer. An interval value is specified,\n  //       and every time that interval elapses, the system must call into the\n  //       callback function with the timer ID as returned by this function.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       uElapse     -   Specifies the time-out value, in milliseconds.\n  //       lpTimerFunc -   A pointer to the callback function-TimerCallback.\n  // Return value:\n  //       The timer identifier of the new timer if the function is successful.\n  //       An application passes this value to the FFI_KillTimer method to kill\n  //       the timer. Nonzero if it is successful; otherwise, it is zero.\n  int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis,\n                      int uElapse,\n                      TimerCallback lpTimerFunc);\n\n  // Method: FFI_KillTimer\n  //       This method uninstalls a system timer, as set by an earlier call to\n  //       FFI_SetTimer.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nTimerID    -   The timer ID returned by FFI_SetTimer function.\n  // Return value:\n  //       None.\n  void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID);\n\n  // Method: FFI_GetLocalTime\n  //       This method receives the current local time on the system.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       The local time. See FPDF_SYSTEMTIME above for details.\n  // Note: Unused.\n  FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_OnChange\n  //       This method will be invoked to notify the implementation when the\n  //       value of any FormField on the document had been changed.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       None.\n  void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_GetPage\n  //       This method receives the page handle associated with a specified\n  //       page index.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  //       nPageIndex  -   Index number of the page. 0 for the first page.\n  // Return value:\n  //       Handle to the page, as previously returned to the implementation by\n  //       FPDF_LoadPage().\n  // Comments:\n  //       The implementation is expected to keep track of the page handles it\n  //       receives from PDFium, and their mappings to page numbers. In some\n  //       cases, the document-level JavaScript action may refer to a page\n  //       which hadn't been loaded yet. To successfully run the Javascript\n  //       action, the implementation needs to load the page.\n  FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_DOCUMENT document,\n                           int nPageIndex);\n\n  // Method: FFI_GetCurrentPage\n  //       This method receives the handle to the current page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       Yes when V8 support is present, otherwise unused.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  // Return value:\n  //       Handle to the page. Returned by FPDF_LoadPage().\n  // Comments:\n  //       PDFium doesn't keep keep track of the \"current page\" (e.g. the one\n  //       that is most visible on screen), so it must ask the embedder for\n  //       this information.\n  FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_DOCUMENT document);\n\n  // Method: FFI_GetRotation\n  //       This method receives currently rotation of the page view.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to page, as returned by FPDF_LoadPage().\n  // Return value:\n  //       A number to indicate the page rotation in 90 degree increments\n  //       in a clockwise direction:\n  //         0 - 0 degrees\n  //         1 - 90 degrees\n  //         2 - 180 degrees\n  //         3 - 270 degrees\n  // Note: Unused.\n  int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page);\n\n  // Method: FFI_ExecuteNamedAction\n  //       This method will execute a named action.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       namedAction     -   A byte string which indicates the named action,\n  //                           terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the\n  //       standard named actions, but note that a document may supply any\n  //       name of its choosing.\n  void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_BYTESTRING namedAction);\n  // Method: FFI_SetTextFieldFocus\n  //       Called when a text field is getting or losing focus.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       value           -   The string value of the form field, in UTF-16LE\n  //                           format.\n  //       valueLen        -   The length of the string value. This is the\n  //                           number of characters, not bytes.\n  //       is_focus        -   True if the form field is getting focus, false\n  //                           if the form field is losing focus.\n  // Return value:\n  //       None.\n  // Comments:\n  //       Only supports text fields and combobox fields.\n  void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis,\n                                FPDF_WIDESTRING value,\n                                FPDF_DWORD valueLen,\n                                FPDF_BOOL is_focus);\n\n  // Method: FFI_DoURIAction\n  //       Ask the implementation to navigate to a uniform resource identifier.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       bsURI           -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder is version 2 or higher and have implementation for\n  //       FFI_DoURIActionWithKeyboardModifier, then\n  //       FFI_DoURIActionWithKeyboardModifier takes precedence over\n  //       FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis,\n                          FPDF_BYTESTRING bsURI);\n\n  // Method: FFI_DoGoToAction\n  //       This action changes the view to a specified destination.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       nPageIndex      -   The index of the PDF page.\n  //       zoomMode        -   The zoom mode for viewing page. See below.\n  //       fPosArray       -   The float array which carries the position info.\n  //       sizeofArray     -   The size of float array.\n  // PDFZoom values:\n  //         - XYZ = 1\n  //         - FITPAGE = 2\n  //         - FITHORZ = 3\n  //         - FITVERT = 4\n  //         - FITRECT = 5\n  //         - FITBBOX = 6\n  //         - FITBHORZ = 7\n  //         - FITBVERT = 8\n  // Return value:\n  //       None.\n  // Comments:\n  //       See the Destinations description of <<PDF Reference, version 1.7>>\n  //       in 8.2.1 for more details.\n  void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis,\n                           int nPageIndex,\n                           int zoomMode,\n                           float* fPosArray,\n                           int sizeofArray);\n\n  // Pointer to IPDF_JSPLATFORM interface.\n  // Unused if PDFium is built without V8 support. Otherwise, if NULL, then\n  // JavaScript will be prevented from executing while rendering the document.\n  IPDF_JSPLATFORM* m_pJsPlatform;\n\n  // Version 2 - Experimental.\n\n  // Whether the XFA module is disabled when built with the XFA module.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  FPDF_BOOL xfa_disabled;\n\n  // Method: FFI_DisplayCaret\n  //       This method will show the caret at specified position.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   Left position of the client area in PDF page\n  //                           coordinates.\n  //       top             -   Top position of the client area in PDF page\n  //                           coordinates.\n  //       right           -   Right position of the client area in PDF page\n  //                           coordinates.\n  //       bottom          -   Bottom position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       None.\n  void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_PAGE page,\n                           FPDF_BOOL bVisible,\n                           double left,\n                           double top,\n                           double right,\n                           double bottom);\n\n  // Method: FFI_GetCurrentPageIndex\n  //       This method will get the current page index.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  // Return value:\n  //       The index of current page.\n  int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_DOCUMENT document);\n\n  // Method: FFI_SetCurrentPage\n  //       This method will set the current page.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  //       iCurPage        -   The index of the PDF page.\n  // Return value:\n  //       None.\n  void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_DOCUMENT document,\n                             int iCurPage);\n\n // Method: FFI_GotoURL\n //       This method will navigate to the specified URL.\n // Interface Version:\n //       Ignored if |version| < 2.\n // Implementation Required:\n //       Required for XFA, otherwise set to NULL.\n // Parameters:\n //       pThis            -   Pointer to the interface structure itself.\n //       document         -   Handle to document from FPDF_LoadDocument().\n //       wsURL            -   The string value of the URL, in UTF-16LE format.\n // Return value:\n //       None.\n  void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_DOCUMENT document,\n                      FPDF_WIDESTRING wsURL);\n\n  // Method: FFI_GetPageViewRect\n  //       This method will get the current page view rectangle.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   The pointer to receive left position of the page\n  //                           view area in PDF page coordinates.\n  //       top             -   The pointer to receive top position of the page\n  //                           view area in PDF page coordinates.\n  //       right           -   The pointer to receive right position of the\n  //                           page view area in PDF page coordinates.\n  //       bottom          -   The pointer to receive bottom position of the\n  //                           page view area in PDF page coordinates.\n  // Return value:\n  //     None.\n  void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis,\n                              FPDF_PAGE page,\n                              double* left,\n                              double* top,\n                              double* right,\n                              double* bottom);\n\n  // Method: FFI_PageEvent\n  //       This method fires when pages have been added to or deleted from\n  //       the XFA document.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page_count      -   The number of pages to be added or deleted.\n  //       event_type      -   See FXFA_PAGEVIEWEVENT_* above.\n  // Return value:\n  //       None.\n  // Comments:\n  //       The pages to be added or deleted always start from the last page\n  //       of document. This means that if parameter page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been\n  //       appended to the tail of document; If page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages\n  //       have been deleted.\n  void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis,\n                        int page_count,\n                        FPDF_DWORD event_type);\n\n  // Method: FFI_PopupMenu\n  //       This method will track the right context menu for XFA fields.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       hWidget         -   Always null, exists for compatibility.\n  //       menuFlag        -   The menu flags. Please refer to macro definition\n  //                           of FXFA_MENU_XXX and this can be one or a\n  //                           combination of these macros.\n  //       x               -   X position of the client area in PDF page\n  //                           coordinates.\n  //       y               -   Y position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       TRUE indicates success; otherwise false.\n  FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_PAGE page,\n                             FPDF_WIDGET hWidget,\n                             int menuFlag,\n                             float x,\n                             float y);\n\n  // Method: FFI_OpenFile\n  //       This method will open the specified file with the specified mode.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       wsURL           -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  //       mode            -   The mode for open file, e.g. \"rb\" or \"wb\".\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis,\n                                    int fileFlag,\n                                    FPDF_WIDESTRING wsURL,\n                                    const char* mode);\n\n  // Method: FFI_EmailTo\n  //       This method will email the specified file stream to the specified\n  //       contact.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       pTo             -   A semicolon-delimited list of recipients for the\n  //                           message,in UTF-16LE format.\n  //       pSubject        -   The subject of the message,in UTF-16LE format.\n  //       pCC             -   A semicolon-delimited list of CC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pBcc            -   A semicolon-delimited list of BCC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pMsg            -   Pointer to the data buffer to be sent.Can be\n  //                           NULL,in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_FILEHANDLER* fileHandler,\n                      FPDF_WIDESTRING pTo,\n                      FPDF_WIDESTRING pSubject,\n                      FPDF_WIDESTRING pCC,\n                      FPDF_WIDESTRING pBcc,\n                      FPDF_WIDESTRING pMsg);\n\n  // Method: FFI_UploadTo\n  //       This method will upload the specified file stream to the\n  //       specified URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       uploadTo        -   Pointer to the URL path, in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis,\n                       FPDF_FILEHANDLER* fileHandler,\n                       int fileFlag,\n                       FPDF_WIDESTRING uploadTo);\n\n  // Method: FFI_GetPlatform\n  //       This method will get the current platform.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       platform        -   Pointer to the data buffer to receive the\n  //                           platform,in UTF-16LE format. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* platform,\n                         int length);\n\n  // Method: FFI_GetLanguage\n  //       This method will get the current language.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       language        -   Pointer to the data buffer to receive the\n  //                           current language. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* language,\n                         int length);\n\n  // Method: FFI_DownloadFromURL\n  //       This method will download the specified file from the URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       URL             -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                           FPDF_WIDESTRING URL);\n  // Method: FFI_PostRequestURL\n  //       This method will post the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The post data,in UTF-16LE format.\n  //       wsContentType   -   The content type of the request data, in\n  //                           UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTF-16LE format.\n  //       wsHeader        -   The request header,in UTF-16LE format.\n  //       response        -   Pointer to the FPDF_BSTR to receive the response\n  //                           data from the server, in UTF-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_WIDESTRING wsURL,\n                                  FPDF_WIDESTRING wsData,\n                                  FPDF_WIDESTRING wsContentType,\n                                  FPDF_WIDESTRING wsEncode,\n                                  FPDF_WIDESTRING wsHeader,\n                                  FPDF_BSTR* response);\n\n  // Method: FFI_PutRequestURL\n  //       This method will put the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The put data, in UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTR-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_WIDESTRING wsURL,\n                                 FPDF_WIDESTRING wsData,\n                                 FPDF_WIDESTRING wsEncode);\n\n  // Method: FFI_OnFocusChange\n  //     Called when the focused annotation is updated.\n  // Interface Version:\n  //     Ignored if |version| < 2.\n  // Implementation Required:\n  //     No\n  // Parameters:\n  //     param           -   Pointer to the interface structure itself.\n  //     annot           -   The focused annotation.\n  //     page_index      -   Index number of the page which contains the\n  //                         focused annotation. 0 for the first page.\n  // Return value:\n  //     None.\n  // Comments:\n  //     This callback function is useful for implementing any view based\n  //     action such as scrolling the annotation rect into view. The\n  //     embedder should not copy and store the annot as its scope is\n  //     limited to this call only.\n  void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param,\n                            FPDF_ANNOTATION annot,\n                            int page_index);\n\n  // Method: FFI_DoURIActionWithKeyboardModifier\n  //       Ask the implementation to navigate to a uniform resource identifier\n  //       with the specified modifiers.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       param           -   Pointer to the interface structure itself.\n  //       uri             -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  //       modifiers       -   Keyboard modifier that indicates which of\n  //                           the virtual keys are down, if any.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder who is version 2 and does not implement this API,\n  //       then a call will be redirected to FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param,\n      FPDF_BYTESTRING uri,\n      int modifiers);\n} FPDF_FORMFILLINFO;\n\n// Function: FPDFDOC_InitFormFillEnvironment\n//       Initialize form fill environment.\n// Parameters:\n//       document        -   Handle to document from FPDF_LoadDocument().\n//       formInfo        -   Pointer to a FPDF_FORMFILLINFO structure.\n// Return Value:\n//       Handle to the form fill module, or NULL on failure.\n// Comments:\n//       This function should be called before any form fill operation.\n//       The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until\n//       the returned FPDF_FORMHANDLE is closed.\nFPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV\nFPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,\n                                FPDF_FORMFILLINFO* formInfo);\n\n// Function: FPDFDOC_ExitFormFillEnvironment\n//       Take ownership of |hHandle| and exit form fill environment.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This function is a no-op when |hHandle| is null.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnAfterLoadPage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked after user successfully loaded a\n//       PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,\n                                                    FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnBeforeClosePage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked before user closes the PDF page.\n// Parameters:\n//        page        -   Handle to the page, as returned by FPDF_LoadPage().\n//        hHandle     -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//        None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page,\n                                                      FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentJSAction\n//       This method is required for performing document-level JavaScript\n//       actions. It should be invoked after the PDF document has been loaded.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       If there is document-level JavaScript action embedded in the\n//       document, this method will execute the JavaScript action. Otherwise,\n//       the method will do nothing.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentOpenAction\n//       This method is required for performing open-action when the document\n//       is opened.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there are no open-actions embedded\n//       in the document.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle);\n\n// Additional actions type of document:\n//   WC, before closing document, JavaScript action.\n//   WS, before saving document, JavaScript action.\n//   DS, after saving document, JavaScript action.\n//   WP, before printing document, JavaScript action.\n//   DP, after printing document, JavaScript action.\n#define FPDFDOC_AACTION_WC 0x10\n#define FPDFDOC_AACTION_WS 0x11\n#define FPDFDOC_AACTION_DS 0x12\n#define FPDFDOC_AACTION_WP 0x13\n#define FPDFDOC_AACTION_DP 0x14\n\n// Function: FORM_DoDocumentAAction\n//       This method is required for performing the document's\n//       additional-action.\n// Parameters:\n//       hHandle     -   Handle to the form fill module. Returned by\n//                       FPDFDOC_InitFormFillEnvironment.\n//       aaType      -   The type of the additional-actions which defined\n//                       above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there is no document\n//       additional-action corresponding to the specified |aaType|.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,\n                                                      int aaType);\n\n// Additional-action types of page object:\n//   OPEN (/O) -- An action to be performed when the page is opened\n//   CLOSE (/C) -- An action to be performed when the page is closed\n#define FPDFPAGE_AACTION_OPEN 0\n#define FPDFPAGE_AACTION_CLOSE 1\n\n// Function: FORM_DoPageAAction\n//       This method is required for performing the page object's\n//       additional-action when opened or closed.\n// Parameters:\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       aaType      -   The type of the page object's additional-actions\n//                       which defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if no additional-action corresponding\n//       to the specified |aaType| exists.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page,\n                                                  FPDF_FORMHANDLE hHandle,\n                                                  int aaType);\n\n// Function: FORM_OnMouseMove\n//       Call this member function when the mouse cursor moves.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Experimental API\n// Function: FORM_OnMouseWheel\n//       Call this member function when the user scrolls the mouse wheel.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_coord  -   Specifies the coordinates of the cursor in PDF user\n//                       space.\n//       delta_x     -   Specifies the amount of wheel movement on the x-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean left.\n//       delta_y     -   Specifies the amount of wheel movement on the y-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean down.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       For |delta_x| and |delta_y|, the caller must normalize\n//       platform-specific wheel deltas. e.g. On Windows, a delta value of 240\n//       for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines\n//       WHEEL_DELTA as 120.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel(\n    FPDF_FORMHANDLE hHandle,\n    FPDF_PAGE page,\n    int modifier,\n    const FS_POINTF* page_coord,\n    int delta_x,\n    int delta_y);\n\n// Function: FORM_OnFocus\n//       This function focuses the form annotation at a given point. If the\n//       annotation at the point already has focus, nothing happens. If there\n//       is no annotation at the point, removes form focus.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True if there is an annotation at the given point and it has focus.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int modifier,\n                                                 double page_x,\n                                                 double page_y);\n\n// Function: FORM_OnLButtonDown\n//       Call this member function when the user presses the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n\n// Function: FORM_OnRButtonDown\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n// Function: FORM_OnLButtonUp\n//       Call this member function when the user releases the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in device.\n//       page_y      -   Specifies the y-coordinate of the cursor in device.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnRButtonUp\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnLButtonDoubleClick\n//       Call this member function when the user double clicks the\n//       left mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle,\n                          FPDF_PAGE page,\n                          int modifier,\n                          double page_x,\n                          double page_y);\n\n// Function: FORM_OnKeyDown\n//       Call this member function when a nonsystem key is pressed.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, aseturned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,\n                                                   FPDF_PAGE page,\n                                                   int nKeyCode,\n                                                   int modifier);\n\n// Function: FORM_OnKeyUp\n//       Call this member function when a nonsystem key is released.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       Currently unimplemented and always returns false. PDFium reserves this\n//       API and may implement it in the future on an as-needed basis.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int nKeyCode,\n                                                 int modifier);\n\n// Function: FORM_OnChar\n//       Call this member function when a keystroke translates to a\n//       nonsystem character.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nChar       -   The character code value itself.\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle,\n                                                FPDF_PAGE page,\n                                                int nChar,\n                                                int modifier);\n\n// Experimental API\n// Function: FORM_GetFocusedText\n//       Call this function to obtain the text within the current focused\n//       field, if any.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the form text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the form text string, |buffer| is\n//                       not modified.\n// Return Value:\n//       Length in bytes for the text in the focused field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetFocusedText(FPDF_FORMHANDLE hHandle,\n                    FPDF_PAGE page,\n                    void* buffer,\n                    unsigned long buflen);\n\n// Function: FORM_GetSelectedText\n//       Call this function to obtain selected text within a form text\n//       field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the selected text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the selected text string,\n//                       |buffer| is not modified.\n// Return Value:\n//       Length in bytes of selected text in form text field or form combobox\n//       text field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetSelectedText(FPDF_FORMHANDLE hHandle,\n                     FPDF_PAGE page,\n                     void* buffer,\n                     unsigned long buflen);\n\n// Experimental API\n// Function: FORM_ReplaceAndKeepSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the inserted text\n//       will be selected.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             FPDF_WIDESTRING wsText);\n\n// Function: FORM_ReplaceSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the selection range\n//       will be set to empty.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     FPDF_WIDESTRING wsText);\n\n// Experimental API\n// Function: FORM_SelectAllText\n//       Call this function to select all the text within the currently focused\n//       form text field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       Whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page);\n\n// Function: FORM_CanUndo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to undo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_CanRedo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to redo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_Undo\n//       Make the current focused widget perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the undo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_Redo\n//       Make the current focused widget perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the redo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_ForceToKillFocus.\n//       Call this member function to force to kill the focus of the form\n//       field which has focus. If it would kill the focus of a form field,\n//       save the value of form field if was changed by theuser.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Function: FORM_GetFocusedAnnot.\n//       Call this member function to get the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page_index  -   Buffer to hold the index number of the page which\n//                       contains the focused annotation. 0 for the first page.\n//                       Can't be NULL.\n//       annot       -   Buffer to hold the focused annotation. Can't be NULL.\n// Return Value:\n//       On success, return true and write to the out parameters. Otherwise\n//       return false and leave the out parameters unmodified.\n// Comments:\n//       Not currently supported for XFA forms - will report no focused\n//       annotation.\n//       Must call FPDFPage_CloseAnnot() when the annotation returned in |annot|\n//       by this function is no longer needed.\n//       This will return true and set |page_index| to -1 and |annot| to NULL,\n//       if there is no focused annotation.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_GetFocusedAnnot(FPDF_FORMHANDLE handle,\n                     int* page_index,\n                     FPDF_ANNOTATION* annot);\n\n// Experimental API.\n// Function: FORM_SetFocusedAnnot.\n//       Call this member function to set the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       annot       -   Handle to an annotation.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus()\n//       instead.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot);\n\n// Form Field Types\n// The names of the defines are stable, but the specific values associated with\n// them are not, so do not hardcode their values.\n#define FPDF_FORMFIELD_UNKNOWN 0      // Unknown.\n#define FPDF_FORMFIELD_PUSHBUTTON 1   // push button type.\n#define FPDF_FORMFIELD_CHECKBOX 2     // check box type.\n#define FPDF_FORMFIELD_RADIOBUTTON 3  // radio button type.\n#define FPDF_FORMFIELD_COMBOBOX 4     // combo box type.\n#define FPDF_FORMFIELD_LISTBOX 5      // list box type.\n#define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.\n#define FPDF_FORMFIELD_SIGNATURE 7    // text field type.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_XFA 8              // Generic XFA type.\n#define FPDF_FORMFIELD_XFA_CHECKBOX 9     // XFA check box type.\n#define FPDF_FORMFIELD_XFA_COMBOBOX 10    // XFA combo box type.\n#define FPDF_FORMFIELD_XFA_IMAGEFIELD 11  // XFA image field type.\n#define FPDF_FORMFIELD_XFA_LISTBOX 12     // XFA list box type.\n#define FPDF_FORMFIELD_XFA_PUSHBUTTON 13  // XFA push button type.\n#define FPDF_FORMFIELD_XFA_SIGNATURE 14   // XFA signture field type.\n#define FPDF_FORMFIELD_XFA_TEXTFIELD 15   // XFA text field type.\n#endif                                    // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 16\n#else  // PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 8\n#endif  // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define IS_XFA_FORMFIELD(type)                  \\\n  (((type) == FPDF_FORMFIELD_XFA) ||            \\\n   ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \\\n   ((type) == FPDF_FORMFIELD_XFA_LISTBOX) ||    \\\n   ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \\\n   ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) ||  \\\n   ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD))\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDFPage_HasFormFieldAtPoint\n//     Get the form field type by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the type of the form field; -1 indicates no field.\n//     See field types above.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             double page_x,\n                             double page_y);\n\n// Function: FPDFPage_FormFieldZOrderAtPoint\n//     Get the form field z-order by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the z-order of the form field; -1 indicates no field.\n//     Higher numbers are closer to the front.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,\n                                FPDF_PAGE page,\n                                double page_x,\n                                double page_y);\n\n// Function: FPDF_SetFormFieldHighlightColor\n//       Set the highlight color of the specified (or all) form fields\n//       in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returned by\n//                       FPDF_LoadDocument().\n//       fieldType   -   A 32-bit integer indicating the type of a form\n//                       field (defined above).\n//       color       -   The highlight color of the form field. Constructed by\n//                       0xxxrrggbb.\n// Return Value:\n//       None.\n// Comments:\n//       When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the\n//       highlight color will be applied to all the form fields in the\n//       document.\n//       Please refresh the client window to show the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,\n                                int fieldType,\n                                unsigned long color);\n\n// Function: FPDF_SetFormFieldHighlightAlpha\n//       Set the transparency of the form field highlight color in the\n//       document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returaned by\n//                       FPDF_LoadDocument().\n//       alpha       -   The transparency of the form field highlight color,\n//                       between 0-255.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha);\n\n// Function: FPDF_RemoveFormFieldHighlight\n//       Remove the form field highlight color in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       Please refresh the client window to remove the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle);\n\n// Function: FPDF_FFLDraw\n//       Render FormFields and popup window on a page to a device independent\n//       bitmap.\n// Parameters:\n//       hHandle      -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n//       bitmap       -   Handle to the device independent bitmap (as the\n//                        output buffer). Bitmap handles can be created by\n//                        FPDFBitmap_Create().\n//       page         -   Handle to the page, as returned by FPDF_LoadPage().\n//       start_x      -   Left pixel position of the display area in the\n//                        device coordinates.\n//       start_y      -   Top pixel position of the display area in the device\n//                        coordinates.\n//       size_x       -   Horizontal size (in pixels) for displaying the page.\n//       size_y       -   Vertical size (in pixels) for displaying the page.\n//       rotate       -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                        clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                        degrees counter-clockwise).\n//       flags        -   0 for normal display, or combination of flags\n//                        defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This function is designed to render annotations that are\n//       user-interactive, which are widget annotations (for FormFields) and\n//       popup annotations.\n//       With the FPDF_ANNOT flag, this function will render a popup annotation\n//       when users mouse-hover on a non-widget annotation. Regardless of\n//       FPDF_ANNOT flag, this function will always render widget annotations\n//       for FormFields.\n//       In order to implement the FormFill functions, implementation should\n//       call this function after rendering functions, such as\n//       FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have\n//       finished rendering the page contents.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,\n                                            FPDF_BITMAP bitmap,\n                                            FPDF_PAGE page,\n                                            int start_x,\n                                            int start_y,\n                                            int size_x,\n                                            int size_y,\n                                            int rotate,\n                                            int flags);\n\n#if defined(PDF_USE_SKIA)\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,\n                                                FPDF_SKIA_CANVAS canvas,\n                                                FPDF_PAGE page,\n                                                int start_x,\n                                                int start_y,\n                                                int size_x,\n                                                int size_y,\n                                                int rotate,\n                                                int flags);\n#endif\n\n// Experimental API\n// Function: FPDF_GetFormType\n//           Returns the type of form contained in the PDF document.\n// Parameters:\n//           document - Handle to document.\n// Return Value:\n//           Integer value representing one of the FORMTYPE_ values.\n// Comments:\n//           If |document| is NULL, then the return value is FORMTYPE_NONE.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document);\n\n// Experimental API\n// Function: FORM_SetIndexSelected\n//           Selects/deselects the value at the given |index| of the focused\n//           annotation.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based index of value to be set as\n//                           selected/unselected\n//           selected    -   true to select, false to deselect\n// Return Value:\n//           TRUE if the operation succeeded.\n//           FALSE if the operation failed or widget is not a supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Comboboxes\n//           have at most a single value selected at a time which cannot be\n//           deselected. Deselect on a combobox is a no-op that returns false.\n//           Default implementation is a no-op that will return false for\n//           other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetIndexSelected(FPDF_FORMHANDLE hHandle,\n                      FPDF_PAGE page,\n                      int index,\n                      FPDF_BOOL selected);\n\n// Experimental API\n// Function: FORM_IsIndexSelected\n//           Returns whether or not the value at |index| of the focused\n//           annotation is currently selected.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based Index of value to check\n// Return Value:\n//           TRUE if value at |index| is currently selected.\n//           FALSE if value at |index| is not selected or widget is not a\n//           supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Default\n//           implementation is a no-op that will return false for other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index);\n\n// Function: FPDF_LoadXFA\n//          If the document consists of XFA fields, call this method to\n//          attempt to load XFA fields.\n// Parameters:\n//          document     -   Handle to document from FPDF_LoadDocument().\n// Return Value:\n//          TRUE upon success, otherwise FALSE. If XFA support is not built\n//          into PDFium, performs no action and always returns FALSE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_FORMFILL_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_fwlevent.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FWLEVENT_H_\n#define PUBLIC_FPDF_FWLEVENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Key flags.\ntypedef enum {\n  FWL_EVENTFLAG_ShiftKey = 1 << 0,\n  FWL_EVENTFLAG_ControlKey = 1 << 1,\n  FWL_EVENTFLAG_AltKey = 1 << 2,\n  FWL_EVENTFLAG_MetaKey = 1 << 3,\n  FWL_EVENTFLAG_KeyPad = 1 << 4,\n  FWL_EVENTFLAG_AutoRepeat = 1 << 5,\n  FWL_EVENTFLAG_LeftButtonDown = 1 << 6,\n  FWL_EVENTFLAG_MiddleButtonDown = 1 << 7,\n  FWL_EVENTFLAG_RightButtonDown = 1 << 8,\n} FWL_EVENTFLAG;\n\n// Virtual keycodes.\ntypedef enum {\n  FWL_VKEY_Back = 0x08,\n  FWL_VKEY_Tab = 0x09,\n  FWL_VKEY_NewLine = 0x0A,\n  FWL_VKEY_Clear = 0x0C,\n  FWL_VKEY_Return = 0x0D,\n  FWL_VKEY_Shift = 0x10,\n  FWL_VKEY_Control = 0x11,\n  FWL_VKEY_Menu = 0x12,\n  FWL_VKEY_Pause = 0x13,\n  FWL_VKEY_Capital = 0x14,\n  FWL_VKEY_Kana = 0x15,\n  FWL_VKEY_Hangul = 0x15,\n  FWL_VKEY_Junja = 0x17,\n  FWL_VKEY_Final = 0x18,\n  FWL_VKEY_Hanja = 0x19,\n  FWL_VKEY_Kanji = 0x19,\n  FWL_VKEY_Escape = 0x1B,\n  FWL_VKEY_Convert = 0x1C,\n  FWL_VKEY_NonConvert = 0x1D,\n  FWL_VKEY_Accept = 0x1E,\n  FWL_VKEY_ModeChange = 0x1F,\n  FWL_VKEY_Space = 0x20,\n  FWL_VKEY_Prior = 0x21,\n  FWL_VKEY_Next = 0x22,\n  FWL_VKEY_End = 0x23,\n  FWL_VKEY_Home = 0x24,\n  FWL_VKEY_Left = 0x25,\n  FWL_VKEY_Up = 0x26,\n  FWL_VKEY_Right = 0x27,\n  FWL_VKEY_Down = 0x28,\n  FWL_VKEY_Select = 0x29,\n  FWL_VKEY_Print = 0x2A,\n  FWL_VKEY_Execute = 0x2B,\n  FWL_VKEY_Snapshot = 0x2C,\n  FWL_VKEY_Insert = 0x2D,\n  FWL_VKEY_Delete = 0x2E,\n  FWL_VKEY_Help = 0x2F,\n  FWL_VKEY_0 = 0x30,\n  FWL_VKEY_1 = 0x31,\n  FWL_VKEY_2 = 0x32,\n  FWL_VKEY_3 = 0x33,\n  FWL_VKEY_4 = 0x34,\n  FWL_VKEY_5 = 0x35,\n  FWL_VKEY_6 = 0x36,\n  FWL_VKEY_7 = 0x37,\n  FWL_VKEY_8 = 0x38,\n  FWL_VKEY_9 = 0x39,\n  FWL_VKEY_A = 0x41,\n  FWL_VKEY_B = 0x42,\n  FWL_VKEY_C = 0x43,\n  FWL_VKEY_D = 0x44,\n  FWL_VKEY_E = 0x45,\n  FWL_VKEY_F = 0x46,\n  FWL_VKEY_G = 0x47,\n  FWL_VKEY_H = 0x48,\n  FWL_VKEY_I = 0x49,\n  FWL_VKEY_J = 0x4A,\n  FWL_VKEY_K = 0x4B,\n  FWL_VKEY_L = 0x4C,\n  FWL_VKEY_M = 0x4D,\n  FWL_VKEY_N = 0x4E,\n  FWL_VKEY_O = 0x4F,\n  FWL_VKEY_P = 0x50,\n  FWL_VKEY_Q = 0x51,\n  FWL_VKEY_R = 0x52,\n  FWL_VKEY_S = 0x53,\n  FWL_VKEY_T = 0x54,\n  FWL_VKEY_U = 0x55,\n  FWL_VKEY_V = 0x56,\n  FWL_VKEY_W = 0x57,\n  FWL_VKEY_X = 0x58,\n  FWL_VKEY_Y = 0x59,\n  FWL_VKEY_Z = 0x5A,\n  FWL_VKEY_LWin = 0x5B,\n  FWL_VKEY_Command = 0x5B,\n  FWL_VKEY_RWin = 0x5C,\n  FWL_VKEY_Apps = 0x5D,\n  FWL_VKEY_Sleep = 0x5F,\n  FWL_VKEY_NumPad0 = 0x60,\n  FWL_VKEY_NumPad1 = 0x61,\n  FWL_VKEY_NumPad2 = 0x62,\n  FWL_VKEY_NumPad3 = 0x63,\n  FWL_VKEY_NumPad4 = 0x64,\n  FWL_VKEY_NumPad5 = 0x65,\n  FWL_VKEY_NumPad6 = 0x66,\n  FWL_VKEY_NumPad7 = 0x67,\n  FWL_VKEY_NumPad8 = 0x68,\n  FWL_VKEY_NumPad9 = 0x69,\n  FWL_VKEY_Multiply = 0x6A,\n  FWL_VKEY_Add = 0x6B,\n  FWL_VKEY_Separator = 0x6C,\n  FWL_VKEY_Subtract = 0x6D,\n  FWL_VKEY_Decimal = 0x6E,\n  FWL_VKEY_Divide = 0x6F,\n  FWL_VKEY_F1 = 0x70,\n  FWL_VKEY_F2 = 0x71,\n  FWL_VKEY_F3 = 0x72,\n  FWL_VKEY_F4 = 0x73,\n  FWL_VKEY_F5 = 0x74,\n  FWL_VKEY_F6 = 0x75,\n  FWL_VKEY_F7 = 0x76,\n  FWL_VKEY_F8 = 0x77,\n  FWL_VKEY_F9 = 0x78,\n  FWL_VKEY_F10 = 0x79,\n  FWL_VKEY_F11 = 0x7A,\n  FWL_VKEY_F12 = 0x7B,\n  FWL_VKEY_F13 = 0x7C,\n  FWL_VKEY_F14 = 0x7D,\n  FWL_VKEY_F15 = 0x7E,\n  FWL_VKEY_F16 = 0x7F,\n  FWL_VKEY_F17 = 0x80,\n  FWL_VKEY_F18 = 0x81,\n  FWL_VKEY_F19 = 0x82,\n  FWL_VKEY_F20 = 0x83,\n  FWL_VKEY_F21 = 0x84,\n  FWL_VKEY_F22 = 0x85,\n  FWL_VKEY_F23 = 0x86,\n  FWL_VKEY_F24 = 0x87,\n  FWL_VKEY_NunLock = 0x90,\n  FWL_VKEY_Scroll = 0x91,\n  FWL_VKEY_LShift = 0xA0,\n  FWL_VKEY_RShift = 0xA1,\n  FWL_VKEY_LControl = 0xA2,\n  FWL_VKEY_RControl = 0xA3,\n  FWL_VKEY_LMenu = 0xA4,\n  FWL_VKEY_RMenu = 0xA5,\n  FWL_VKEY_BROWSER_Back = 0xA6,\n  FWL_VKEY_BROWSER_Forward = 0xA7,\n  FWL_VKEY_BROWSER_Refresh = 0xA8,\n  FWL_VKEY_BROWSER_Stop = 0xA9,\n  FWL_VKEY_BROWSER_Search = 0xAA,\n  FWL_VKEY_BROWSER_Favorites = 0xAB,\n  FWL_VKEY_BROWSER_Home = 0xAC,\n  FWL_VKEY_VOLUME_Mute = 0xAD,\n  FWL_VKEY_VOLUME_Down = 0xAE,\n  FWL_VKEY_VOLUME_Up = 0xAF,\n  FWL_VKEY_MEDIA_NEXT_Track = 0xB0,\n  FWL_VKEY_MEDIA_PREV_Track = 0xB1,\n  FWL_VKEY_MEDIA_Stop = 0xB2,\n  FWL_VKEY_MEDIA_PLAY_Pause = 0xB3,\n  FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4,\n  FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5,\n  FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6,\n  FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7,\n  FWL_VKEY_OEM_1 = 0xBA,\n  FWL_VKEY_OEM_Plus = 0xBB,\n  FWL_VKEY_OEM_Comma = 0xBC,\n  FWL_VKEY_OEM_Minus = 0xBD,\n  FWL_VKEY_OEM_Period = 0xBE,\n  FWL_VKEY_OEM_2 = 0xBF,\n  FWL_VKEY_OEM_3 = 0xC0,\n  FWL_VKEY_OEM_4 = 0xDB,\n  FWL_VKEY_OEM_5 = 0xDC,\n  FWL_VKEY_OEM_6 = 0xDD,\n  FWL_VKEY_OEM_7 = 0xDE,\n  FWL_VKEY_OEM_8 = 0xDF,\n  FWL_VKEY_OEM_102 = 0xE2,\n  FWL_VKEY_ProcessKey = 0xE5,\n  FWL_VKEY_Packet = 0xE7,\n  FWL_VKEY_Attn = 0xF6,\n  FWL_VKEY_Crsel = 0xF7,\n  FWL_VKEY_Exsel = 0xF8,\n  FWL_VKEY_Ereof = 0xF9,\n  FWL_VKEY_Play = 0xFA,\n  FWL_VKEY_Zoom = 0xFB,\n  FWL_VKEY_NoName = 0xFC,\n  FWL_VKEY_PA1 = 0xFD,\n  FWL_VKEY_OEM_Clear = 0xFE,\n  FWL_VKEY_Unknown = 0,\n} FWL_VKEYCODE;\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FWLEVENT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_javascript.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_JAVASCRIPT_H_\n#define PUBLIC_FPDF_JAVASCRIPT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of JavaScript actions in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of JavaScript actions in |document| or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the JavaScript action at |index| in |document|.\n//\n//   document - handle to a document.\n//   index    - the index of the requested JavaScript action.\n//\n// Returns the handle to the JavaScript action, or NULL on failure.\n// Caller owns the returned handle and must close it with\n// FPDFDoc_CloseJavaScriptAction().\nFPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV\nFPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Close a loaded FPDF_JAVASCRIPT_ACTION object.\n\n//   javascript - Handle to a JavaScript action.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript);\n\n// Experimental API.\n// Get the name from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the name. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript,\n                             FPDF_WCHAR* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Get the script from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the script. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript,\n                               FPDF_WCHAR* buffer,\n                               unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_JAVASCRIPT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_ppo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PPO_H_\n#define PUBLIC_FPDF_PPO_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc     - The destination document for the pages.\n//   src_doc      - The document to be imported.\n//   page_indices - An array of page indices to be imported. The first page is\n//                  zero. If |page_indices| is NULL, all pages from |src_doc|\n//                  are imported.\n//   length       - The length of the |page_indices| array.\n//   index        - The page index at which to insert the first imported page\n//                  into |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |page_indices| is\n// invalid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        const int* page_indices,\n                        unsigned long length,\n                        int index);\n\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc  - The destination document for the pages.\n//   src_doc   - The document to be imported.\n//   pagerange - A page range string, Such as \"1,3,5-7\". The first page is one.\n//               If |pagerange| is NULL, all pages from |src_doc| are imported.\n//   index     - The page index at which to insert the first imported page into\n//               |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |pagerange| is\n// invalid or if |pagerange| cannot be read.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,\n                                                     FPDF_DOCUMENT src_doc,\n                                                     FPDF_BYTESTRING pagerange,\n                                                     int index);\n\n// Experimental API.\n// Create a new document from |src_doc|.  The pages of |src_doc| will be\n// combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per\n// |output_doc| page.\n//\n//   src_doc             - The document to be imported.\n//   output_width        - The output page width in PDF \"user space\" units.\n//   output_height       - The output page height in PDF \"user space\" units.\n//   num_pages_on_x_axis - The number of pages on X Axis.\n//   num_pages_on_y_axis - The number of pages on Y Axis.\n//\n// Return value:\n//   A handle to the created document, or NULL on failure.\n//\n// Comments:\n//   number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis\n//\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,\n                       float output_width,\n                       float output_height,\n                       size_t num_pages_on_x_axis,\n                       size_t num_pages_on_y_axis);\n\n// Experimental API.\n// Create a template to generate form xobjects from |src_doc|'s page at\n// |src_page_index|, for use in |dest_doc|.\n//\n// Returns a handle on success, or NULL on failure. Caller owns the newly\n// created object.\nFPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV\nFPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        int src_page_index);\n\n// Experimental API.\n// Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage().\n// FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject);\n\n// Experimental API.\n// Create a new form object from an FPDF_XOBJECT object.\n//\n// Returns a new form object on success, or NULL on failure. Caller owns the\n// newly created object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject);\n\n// Copy the viewer preferences from |src_doc| into |dest_doc|.\n//\n//   dest_doc - Document to write the viewer preferences into.\n//   src_doc  - Document to read the viewer preferences from.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_PPO_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_progressive.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PROGRESSIVE_H_\n#define PUBLIC_FPDF_PROGRESSIVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flags for progressive process status.\n#define FPDF_RENDER_READY 0\n#define FPDF_RENDER_TOBECONTINUED 1\n#define FPDF_RENDER_DONE 2\n#define FPDF_RENDER_FAILED 3\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// IFPDF_RENDERINFO interface.\ntypedef struct _IFSDK_PAUSE {\n  // Version number of the interface. Currently must be 1.\n  int version;\n\n  // Method: NeedToPauseNow\n  //           Check if we need to pause a progressive process now.\n  // Interface Version:\n  //           1\n  // Implementation Required:\n  //           yes\n  // Parameters:\n  //           pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //           Non-zero for pause now, 0 for continue.\n  FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis);\n\n  // A user defined data pointer, used by user's application. Can be NULL.\n  void* user;\n} IFSDK_PAUSE;\n\n// Experimental API.\n// Function: FPDF_RenderPageBitmapWithColorScheme_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively with a specified color scheme for the content.\n// Parameters:\n//          bitmap       -   Handle to the device independent bitmap (as the\n//                           output buffer). Bitmap handle can be created by\n//                           FPDFBitmap_Create function.\n//          page         -   Handle to the page as returned by FPDF_LoadPage\n//                           function.\n//          start_x      -   Left pixel position of the display area in the\n//                           bitmap coordinate.\n//          start_y      -   Top pixel position of the display area in the\n//                           bitmap coordinate.\n//          size_x       -   Horizontal size (in pixels) for displaying the\n//                           page.\n//          size_y       -   Vertical size (in pixels) for displaying the page.\n//          rotate       -   Page orientation: 0 (normal), 1 (rotated 90\n//                           degrees clockwise), 2 (rotated 180 degrees),\n//                           3 (rotated 90 degrees counter-clockwise).\n//          flags        -   0 for normal display, or combination of flags\n//                           defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                           renders all annotations that does not require\n//                           user-interaction, which are all annotations except\n//                           widget and popup annotations.\n//          color_scheme -   Color scheme to be used in rendering the |page|.\n//                           If null, this function will work similar to\n//                           FPDF_RenderPageBitmap_Start().\n//          pause        -   The IFSDK_PAUSE interface. A callback mechanism\n//                           allowing the page rendering process.\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap,\n                                           FPDF_PAGE page,\n                                           int start_x,\n                                           int start_y,\n                                           int size_x,\n                                           int size_y,\n                                           int rotate,\n                                           int flags,\n                                           const FPDF_COLORSCHEME* color_scheme,\n                                           IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPageBitmap_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). Bitmap handle can be created by\n//                          FPDFBitmap_Create().\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          start_x     -   Left pixel position of the display area in the\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in the bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                          clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                          degrees counter-clockwise).\n//          flags       -   0 for normal display, or combination of flags\n//                          defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                          renders all annotations that does not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n//          pause       -   The IFSDK_PAUSE interface.A callback mechanism\n//                          allowing the page rendering process\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,\n                                                          FPDF_PAGE page,\n                                                          int start_x,\n                                                          int start_y,\n                                                          int size_x,\n                                                          int size_y,\n                                                          int rotate,\n                                                          int flags,\n                                                          IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Continue\n//          Continue rendering a PDF page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          pause       -   The IFSDK_PAUSE interface (a callback mechanism\n//                          allowing the page rendering process to be paused\n//                          before it's finished). This can be NULL if you\n//                          don't want to pause.\n// Return value:\n//          The rendering status. See flags for progressive process status for\n//          the details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page,\n                                                       IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Close\n//          Release the resource allocate during page rendering. Need to be\n//          called after finishing rendering or\n//          cancel the rendering.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_PROGRESSIVE_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_save.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SAVE_H_\n#define PUBLIC_FPDF_SAVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Structure for custom file write\ntypedef struct FPDF_FILEWRITE_ {\n  //\n  // Version number of the interface. Currently must be 1.\n  //\n  int version;\n\n  // Method: WriteBlock\n  //          Output a block of data in your custom way.\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          Yes\n  // Comments:\n  //          Called by function FPDF_SaveDocument\n  // Parameters:\n  //          self        -   Pointer to the structure itself\n  //          data        -   Pointer to a buffer to output\n  //          size        -   The size of the buffer.\n  // Return value:\n  //          Should be non-zero if successful, zero for error.\n  int (*WriteBlock)(struct FPDF_FILEWRITE_* self,\n                    const void* data,\n                    unsigned long size);\n} FPDF_FILEWRITE;\n\n// Flags for FPDF_SaveAsCopy().\n// FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together.\n#define FPDF_INCREMENTAL (1 << 0)\n#define FPDF_NO_INCREMENTAL (1 << 1)\n // Deprecated. Use FPDF_REMOVE_SECURITY instead.\n // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED.\n#define FPDF_REMOVE_SECURITY_DEPRECATED 3\n#define FPDF_REMOVE_SECURITY (1 << 2)\n// Experimental. Subsets any embedded font files for new text objects added to\n// the document.\n#define FPDF_SUBSET_NEW_FONTS (1 << 3)\n\n// Function: FPDF_SaveAsCopy\n//          Saves the copy of specified document in custom way.\n// Parameters:\n//          document        -   Handle to document, as returned by\n//                              FPDF_LoadDocument() or FPDF_CreateNewDocument().\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   Flags above that affect how the PDF gets saved.\n//                              Pass in 0 when there are no flags.\n// Return value:\n//          TRUE for succeed, FALSE for failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,\n                                                    FPDF_FILEWRITE* file_write,\n                                                    FPDF_DWORD flags);\n\n// Function: FPDF_SaveWithVersion\n//          Same as FPDF_SaveAsCopy(), except the file version of the\n//          saved document can be specified by the caller.\n// Parameters:\n//          document        -   Handle to document.\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   The creating flags.\n//          file_version    -   The PDF file version. File version: 14 for 1.4,\n//                              15 for 1.5, ...\n// Return value:\n//          TRUE if succeed, FALSE if failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_SaveWithVersion(FPDF_DOCUMENT document,\n                     FPDF_FILEWRITE* file_write,\n                     FPDF_DWORD flags,\n                     int file_version);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SAVE_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_searchex.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SEARCHEX_H_\n#define PUBLIC_FPDF_SEARCHEX_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Get the character index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nTextIndex - index of the text returned from FPDFText_GetText().\n//\n// Returns the index of the character in internal character list. -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex);\n\n// Get the text index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nCharIndex - index of the character in internal character list.\n//\n// Returns the index of the text returned from FPDFText_GetText(). -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SEARCHEX_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_signature.h",
    "content": "// Copyright 2020 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_SIGNATURE_H_\n#define PUBLIC_FPDF_SIGNATURE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Function: FPDF_GetSignatureCount\n//          Get total number of signatures in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n// Return value:\n//          Total number of signatures in the document on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetSignatureObject\n//          Get the Nth signature of the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          index       -   Index into the array of signatures of the document.\n// Return value:\n//          Returns the handle to the signature, or NULL on failure. The caller\n//          does not take ownership of the returned FPDF_SIGNATURE. Instead, it\n//          remains valid until FPDF_CloseDocument() is called for the document.\nFPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV\nFPDF_GetSignatureObject(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetContents\n//          Get the contents of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the contents.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the contents on success, 0 on error.\n//\n// For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or\n// a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetContents(FPDF_SIGNATURE signature,\n                             void* buffer,\n                             unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetByteRange\n//          Get the byte range of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the\n//                          byte range.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the byte range on\n//          success, 0 on error.\n//\n// |buffer| is an array of pairs of integers (starting byte offset,\n// length in bytes) that describes the exact byte range for the digest\n// calculation. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,\n                              int* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetSubFilter\n//          Get the encoding of the value of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the encoding.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature,\n                              char* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetReason\n//          Get the reason (comment) of the signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the reason.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the reason on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetReason(FPDF_SIGNATURE signature,\n                           void* buffer,\n                           unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetTime\n//          Get the time of signing of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the time.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's\n// percision is seconds, with timezone information. This value should be used\n// only when the time of signing is not available in the (PKCS#7 binary)\n// signature.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetTime(FPDF_SIGNATURE signature,\n                         char* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetDocMDPPermission\n//          Get the DocMDP permission of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n// Return value:\n//          Returns the permission (1, 2 or 3) on success, 0 on error.\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SIGNATURE_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_structtree.h",
    "content": "// Copyright 2016 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_STRUCTTREE_H_\n#define PUBLIC_FPDF_STRUCTTREE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDF_StructTree_GetForPage\n//          Get the structure tree for a page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          A handle to the structure tree or NULL on error. The caller owns the\n//          returned handle and must use FPDF_StructTree_Close() to release it.\n//          The handle should be released before |page| gets released.\nFPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV\nFPDF_StructTree_GetForPage(FPDF_PAGE page);\n\n// Function: FPDF_StructTree_Close\n//          Release a resource allocated by FPDF_StructTree_GetForPage().\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_CountChildren\n//          Count the number of children for the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_GetChildAtIndex\n//          Get a child in the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n//          index       -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error. The caller does not\n//          own the handle. The handle remains valid as long as |struct_tree|\n//          remains valid.\n// Comments:\n//          The |index| must be less than the FPDF_StructTree_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index);\n\n// Function: FPDF_StructElement_GetAltText\n//          Get the alt text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the alt text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the alt text, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetActualText\n//          Get the actual text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the actual text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the actual text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetExpansion\n//          Get the expansion of an abbreviation or acronym for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the expansion text. May be\n//                             NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the expansion text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element,\n                                void* buffer,\n                                unsigned long buflen);\n\n// Function: FPDF_StructElement_GetID\n//          Get the ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the ID string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,\n                         void* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetLang\n//          Get the case-insensitive IETF BCP 47 language code for an element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the lang string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetStringAttribute\n//          Get a struct element attribute of type \"name\" or \"string\".\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          attr_name      -   The name of the attribute to retrieve.\n//          buffer         -   A buffer for output. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the attribute value, including the\n//          terminating NUL character. The number of bytes is returned\n//          regardless of the |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,\n                                      FPDF_BYTESTRING attr_name,\n                                      void* buffer,\n                                      unsigned long buflen);\n\n// Function: FPDF_StructElement_GetMarkedContentID\n//          Get the marked content ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to\n//          extract more marked content IDs out of |struct_element|. This API\n//          may be deprecated in the future.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetType\n//           Get the type (/S) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the type, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetObjType\n//           Get the object type (/Type) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the object type, including the terminating\n//           NUL character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Function: FPDF_StructElement_GetTitle\n//           Get the title (/T) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the title, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Function: FPDF_StructElement_CountChildren\n//          Count the number of children for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetChildAtIndex\n//          Get a child in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error.\n// Comments:\n//          If the child exists but is not an element, then this function will\n//          return NULL. This will also return NULL for out of bounds indices.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                   int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetChildMarkedContentID\n//          Get the child's content id\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The marked content ID of the child. If no ID exists, returns -1.\n// Comments:\n//          If the child exists but is not a stream or object, then this\n//          function will return -1. This will also return -1 for out of bounds\n//          indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex,\n//          it is scoped to the current page.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element,\n                                           int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetParent\n//          Get the parent of the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The parent structure element or NULL on error.\n// Comments:\n//          If structure element is StructTreeRoot, then this function will\n//          return NULL.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetAttributeCount\n//          Count the number of attributes for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetAttributeAtIndex\n//          Get an attribute object in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the attribute object, 0-based.\n// Return value:\n//          The attribute object at the n-th index or NULL on error.\n// Comments:\n//          If the attribute object exists but is not a dict, then this\n//          function will return NULL. This will also return NULL for out of\n//          bounds indices. The caller does not own the handle. The handle\n//          remains valid as long as |struct_element| remains valid.\n//          The |index| must be less than the\n//          FPDF_StructElement_GetAttributeCount() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV\nFPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetCount\n//          Count the number of attributes in a structure element attribute map.\n// Parameters:\n//          struct_attribute - Handle to the struct element attribute.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute);\n\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetName\n//          Get the name of an attribute in a structure element attribute map.\n// Parameters:\n//          struct_attribute   - Handle to the struct element attribute.\n//          index              - The index of attribute in the map.\n//          buffer             - A buffer for output. May be NULL. This is only\n//                               modified if |buflen| is longer than the length\n//                               of the key. Optional, pass null to just\n//                               retrieve the size of the buffer needed.\n//          buflen             - The length of the buffer.\n//          out_buflen         - A pointer to variable that will receive the\n//                               minimum buffer size to contain the key. Not\n//                               filled if FALSE is returned.\n// Return value:\n//          TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                int index,\n                                void* buffer,\n                                unsigned long buflen,\n                                unsigned long* out_buflen);\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetValue\n//           Get a handle to a value for an attribute in a structure element\n//           attribute map.\n// Parameters:\n//           struct_attribute   - Handle to the struct element attribute.\n//           name               - The attribute name.\n// Return value:\n//           Returns a handle to the value associated with the input, if any.\n//           Returns NULL on failure. The caller does not own the handle.\n//           The handle remains valid as long as |struct_attribute| remains\n//           valid.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                 FPDF_BYTESTRING name);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetType\n//           Get the type of an attribute in a structure element attribute map.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of\n//           failure. Note that this will never return FPDF_OBJECT_REFERENCE, as\n//           references are always dereferenced.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBooleanValue\n//           Get the value of a boolean attribute in an attribute map as\n//           FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_BOOLEAN for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a boolean value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        FPDF_BOOL* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetNumberValue\n//           Get the value of a number attribute in an attribute map as float.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_NUMBER for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a number value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       float* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetStringValue\n//           Get the value of a string attribute in an attribute map as string.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned key in UTF-16LE.\n//                        This is only modified if |buflen| is longer than the\n//                        length of the key. Optional, pass null to just\n//                        retrieve the size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       void* buffer,\n                                       unsigned long buflen,\n                                       unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBlobValue\n//           Get the value of a blob attribute in an attribute map as string.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned value. This is only\n//                        modified if |buflen| is at least as long as the length\n//                        of the value. Optional, pass null to just retrieve the\n//                        size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                     void* buffer,\n                                     unsigned long buflen,\n                                     unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_CountChildren\n//           Count the number of children values in an attribute.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetChildAtIndex\n//           Get a child from an attribute.\n// Parameters:\n//           value - Handle to the value.\n//           index - The index for the child, 0-based.\n// Return value:\n//           The child at the n-th index or NULL on error.\n// Comments:\n//           The |index| must be less than the\n//           FPDF_StructElement_Attr_CountChildren() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdCount\n//          Get the count of marked content ids for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The count of marked content ids or -1 if none exists.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdAtIndex\n//          Get the marked content id at a given index for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index of the marked content id, 0-based.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          The |index| must be less than the\n//          FPDF_StructElement_GetMarkedContentIdCount() return value.\n//          This will likely supersede FPDF_StructElement_GetMarkedContentID().\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                             int index);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n#endif  // PUBLIC_FPDF_STRUCTTREE_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_sysfontinfo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SYSFONTINFO_H_\n#define PUBLIC_FPDF_SYSFONTINFO_H_\n\n#include <stddef.h>\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Character sets for the font\n#define FXFONT_ANSI_CHARSET 0\n#define FXFONT_DEFAULT_CHARSET 1\n#define FXFONT_SYMBOL_CHARSET 2\n#define FXFONT_SHIFTJIS_CHARSET 128\n#define FXFONT_HANGEUL_CHARSET 129\n#define FXFONT_GB2312_CHARSET 134\n#define FXFONT_CHINESEBIG5_CHARSET 136\n#define FXFONT_GREEK_CHARSET 161\n#define FXFONT_VIETNAMESE_CHARSET 163\n#define FXFONT_HEBREW_CHARSET 177\n#define FXFONT_ARABIC_CHARSET 178\n#define FXFONT_CYRILLIC_CHARSET 204\n#define FXFONT_THAI_CHARSET 222\n#define FXFONT_EASTERNEUROPEAN_CHARSET 238\n\n// Font pitch and family flags\n#define FXFONT_FF_FIXEDPITCH (1 << 0)\n#define FXFONT_FF_ROMAN (1 << 4)\n#define FXFONT_FF_SCRIPT (4 << 4)\n\n// Typical weight values\n#define FXFONT_FW_NORMAL 400\n#define FXFONT_FW_BOLD 700\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Interface: FPDF_SYSFONTINFO\n//          Interface for getting system font information and font mapping\ntypedef struct _FPDF_SYSFONTINFO {\n  // Version number of the interface. Currently must be 1 or 2.\n  // Version 1: Traditional behavior - calls EnumFonts during initialization.\n  // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont.\n  //            Experimental: Subject to change based on feedback.\n  int version;\n\n  // Method: Release\n  //          Give implementation a chance to release any data after the\n  //          interface is no longer used.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //          None\n  // Comments:\n  //          Called by PDFium during the final cleanup process.\n  void (*Release)(struct _FPDF_SYSFONTINFO* pThis);\n\n  // Method: EnumFonts\n  //          Enumerate all fonts installed on the system\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          pMapper     -   An opaque pointer to internal font mapper, used\n  //                          when calling FPDF_AddInstalledFont().\n  // Return Value:\n  //          None\n  // Comments:\n  //          Implementations should call FPDF_AddInstalledFont() function for\n  //          each font found. Only TrueType/OpenType and Type1 fonts are\n  //          accepted by PDFium.\n  //          NOTE: This method will not be called when version is set to 2.\n  //          Version 2 relies entirely on MapFont() for per-request matching.\n  void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper);\n\n  // Method: MapFont\n  //          Use the system font mapper to get a font handle from requested\n  //          parameters.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if GetFont method is not implemented.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          weight      -   Weight of the requested font. 400 is normal and\n  //                          700 is bold.\n  //          bItalic     -   Italic option of the requested font, TRUE or\n  //                          FALSE.\n  //          charset     -   Character set identifier for the requested font.\n  //                          See above defined constants.\n  //          pitch_family -  A combination of flags. See above defined\n  //                          constants.\n  //          face        -   Typeface name. Currently use system local encoding\n  //                          only.\n  //          bExact      -   Obsolete: this parameter is now ignored.\n  // Return Value:\n  //          An opaque pointer for font handle, or NULL if system mapping is\n  //          not supported.\n  // Comments:\n  //          If the system supports native font mapper (like Windows),\n  //          implementation can implement this method to get a font handle.\n  //          Otherwise, PDFium will do the mapping and then call GetFont\n  //          method. Only TrueType/OpenType and Type1 fonts are accepted\n  //          by PDFium.\n  void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis,\n                   int weight,\n                   FPDF_BOOL bItalic,\n                   int charset,\n                   int pitch_family,\n                   const char* face,\n                   FPDF_BOOL* bExact);\n\n  // Method: GetFont\n  //          Get a handle to a particular font by its internal ID\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if MapFont method is not implemented.\n  // Return Value:\n  //          An opaque pointer for font handle.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          face        -   Typeface name in system local encoding.\n  // Comments:\n  //          If the system mapping not supported, PDFium will do the font\n  //          mapping and use this method to get a font handle.\n  void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face);\n\n  // Method: GetFontData\n  //          Get font data from a font\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          table       -   TrueType/OpenType table identifier (refer to\n  //                          TrueType specification), or 0 for the whole file.\n  //          buffer      -   The buffer receiving the font data. Can be NULL if\n  //                          not provided.\n  //          buf_size    -   Buffer size, can be zero if not provided.\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  // Comments:\n  //          Can read either the full font file, or a particular\n  //          TrueType/OpenType table.\n  unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               unsigned int table,\n                               unsigned char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFaceName\n  //          Get face name from a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          buffer      -   The buffer receiving the face name. Can be NULL if\n  //                          not provided\n  //          buf_size    -   Buffer size, can be zero if not provided\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFontCharset\n  //          Get character set information for a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          Character set identifier. See defined constants above.\n  int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n\n  // Method: DeleteFont\n  //          Delete a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          None\n  void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n} FPDF_SYSFONTINFO;\n\n// Struct: FPDF_CharsetFontMap\n//    Provides the name of a font to use for a given charset value.\ntypedef struct FPDF_CharsetFontMap_ {\n  int charset;  // Character Set Enum value, see FXFONT_*_CHARSET above.\n  const char* fontname;  // Name of default font to use with that charset.\n} FPDF_CharsetFontMap;\n\n// Function: FPDF_GetDefaultTTFMap\n//    Returns a pointer to the default character set to TT Font name map. The\n//    map is an array of FPDF_CharsetFontMap structs, with its end indicated\n//    by a { -1, NULL } entry.\n// Parameters:\n//     None.\n// Return Value:\n//     Pointer to the Charset Font Map.\n// Note:\n//     Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no\n//     longer experimental, this API will be marked as deprecated.\n//     See https://crbug.com/348468114\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapCount\n//    Returns the number of entries in the default character set to TT Font name\n//    map.\n// Parameters:\n//    None.\n// Return Value:\n//    The number of entries in the map.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapEntry\n//    Returns an entry in the default character set to TT Font name map.\n// Parameters:\n//    index    -   The index to the entry in the map to retrieve.\n// Return Value:\n//     A pointer to the entry, if it is in the map, or NULL if the index is out\n//     of bounds.\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV\nFPDF_GetDefaultTTFMapEntry(size_t index);\n\n// Function: FPDF_AddInstalledFont\n//          Add a system font to the list in PDFium.\n// Comments:\n//          This function is only called during the system font list building\n//          process.\n// Parameters:\n//          mapper          -   Opaque pointer to Foxit font mapper\n//          face            -   The font face name\n//          charset         -   Font character set. See above defined constants.\n// Return Value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper,\n                                                     const char* face,\n                                                     int charset);\n\n// Function: FPDF_SetSystemFontInfo\n//          Set the system font info interface into PDFium\n// Parameters:\n//          font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//          None\n// Comments:\n//          Platform support implementation should implement required methods of\n//          FFDF_SYSFONTINFO interface, then call this function during PDFium\n//          initialization process.\n//\n//          Call this with NULL to tell PDFium to stop using a previously set\n//          |FPDF_SYSFONTINFO|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n// Function: FPDF_GetDefaultSystemFontInfo\n//          Get default system font info interface for current platform\n// Parameters:\n//          None\n// Return Value:\n//          Pointer to a FPDF_SYSFONTINFO structure describing the default\n//          interface, or NULL if the platform doesn't have a default interface.\n//          Application should call FPDF_FreeDefaultSystemFontInfo to free the\n//          returned pointer.\n// Comments:\n//          For some platforms, PDFium implements a default version of system\n//          font info interface. The default implementation can be passed to\n//          FPDF_SetSystemFontInfo().\nFPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo();\n\n// Function: FPDF_FreeDefaultSystemFontInfo\n//           Free a default system font info interface\n// Parameters:\n//           font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//           None\n// Comments:\n//           This function should be called on the output from\n//           FPDF_GetDefaultSystemFontInfo() once it is no longer needed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SYSFONTINFO_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_text.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TEXT_H_\n#define PUBLIC_FPDF_TEXT_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDFText_LoadPage\n//          Prepare information about all characters in a page.\n// Parameters:\n//          page    -   Handle to the page. Returned by FPDF_LoadPage function\n//                      (in FPDFVIEW module).\n// Return value:\n//          A handle to the text page information structure.\n//          NULL if something goes wrong.\n// Comments:\n//          Application must call FPDFText_ClosePage to release the text page\n//          information.\n//\nFPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page);\n\n// Function: FPDFText_ClosePage\n//          Release all resources allocated for a text page information\n//          structure.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_CountChars\n//          Get number of characters in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return value:\n//          Number of characters in the page. Return -1 for error.\n//          Generated characters, like additional space characters, new line\n//          characters, are also counted.\n// Comments:\n//          Characters in a page form a \"stream\", inside the stream, each\n//          character has an index.\n//          We will use the index parameters in many of FPDFTEXT functions. The\n//          first character in the page\n//          has an index value of zero.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_GetUnicode\n//          Get Unicode of a character in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The Unicode of the particular character.\n//          If a character is not encoded in Unicode and Foxit engine can't\n//          convert to Unicode,\n//          the return value will be zero.\n//\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_GetTextObject\n//          Get the FPDF_PAGEOBJECT associated with a given character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The associated text object for the character at |index|, or NULL on\n//          error. The returned text object, if non-null, is of type\n//          |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object.\n//\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsGenerated\n//          Get if a character in a page is generated by PDFium.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is generated by PDFium.\n//          0 if the character is not generated by PDFium.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsHyphen\n//          Get if a character in a page is a hyphen.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is a hyphen.\n//          0 if the character is not a hyphen.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_HasUnicodeMapError\n//          Get if a character in a page has an invalid unicode mapping.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character has an invalid unicode mapping.\n//          0 if the character has no known unicode mapping issues.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index);\n\n// Function: FPDFText_GetFontSize\n//          Get the font size of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The font size of the particular character, measured in points (about\n//          1/72 inch). This is the typographic size of the font (so called\n//          \"em size\").\n//\nFPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Experimental API.\n// Function: FPDFText_GetFontInfo\n//          Get the font name and flags of a particular character.\n// Parameters:\n//          text_page - Handle to a text page information structure.\n//                      Returned by FPDFText_LoadPage function.\n//          index     - Zero-based index of the character.\n//          buffer    - A buffer receiving the font name.\n//          buflen    - The length of |buffer| in bytes.\n//          flags     - Optional pointer to an int receiving the font flags.\n//                      These flags should be interpreted per PDF spec 1.7\n//                      Section 5.7.1 Font Descriptor Flags.\n// Return value:\n//          On success, return the length of the font name, including the\n//          trailing NUL character, in bytes. If this length is less than or\n//          equal to |length|, |buffer| is set to the font name, |flags| is\n//          set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on\n//          failure.\n//\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,\n                     int index,\n                     void* buffer,\n                     unsigned long buflen,\n                     int* flags);\n\n// Experimental API.\n// Function: FPDFText_GetFontWeight\n//          Get the font weight of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          On success, return the font weight of the particular character. If\n//          |text_page| is invalid, if |index| is out of bounds, or if the\n//          character's text object is undefined, return -1.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,\n                                                     int index);\n\n// Experimental API.\n// Function: FPDFText_GetFillColor\n//          Get the fill color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the fill color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the fill color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the fill color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the fill color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetFillColor(FPDF_TEXTPAGE text_page,\n                      int index,\n                      unsigned int* R,\n                      unsigned int* G,\n                      unsigned int* B,\n                      unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetStrokeColor\n//          Get the stroke color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the stroke color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the stroke color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the stroke color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the stroke color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,\n                        int index,\n                        unsigned int* R,\n                        unsigned int* G,\n                        unsigned int* B,\n                        unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetCharAngle\n//          Get character rotation angle.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return Value:\n//          On success, return the angle value in radian. Value will always be\n//          greater or equal to 0. If |text_page| is invalid, or if |index| is\n//          out of bounds, then return -1.\n//\nFPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Function: FPDFText_GetCharBox\n//          Get bounding box of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          left        -   Pointer to a double number receiving left position\n//                          of the character box.\n//          right       -   Pointer to a double number receiving right position\n//                          of the character box.\n//          bottom      -   Pointer to a double number receiving bottom position\n//                          of the character box.\n//          top         -   Pointer to a double number receiving top position of\n//                          the character box.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |right|, |bottom|, and\n//          |top|. If |text_page| is invalid, or if |index| is out of bounds,\n//          then return FALSE, and the out parameters remain unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,\n                                                        int index,\n                                                        double* left,\n                                                        double* right,\n                                                        double* bottom,\n                                                        double* top);\n\n// Experimental API.\n// Function: FPDFText_GetLooseCharBox\n//          Get a \"loose\" bounding box of a particular character, i.e., covering\n//          the entire glyph bounds, without taking the actual glyph shape into\n//          account.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          rect        -   Pointer to a FS_RECTF receiving the character box.\n// Return Value:\n//          On success, return TRUE and fill in |rect|. If |text_page| is\n//          invalid, or if |index| is out of bounds, then return FALSE, and the\n//          |rect| out parameter remains unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDFText_GetMatrix\n//          Get the effective transformation matrix for a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage().\n//          index       -   Zero-based index of the character.\n//          matrix      -   Pointer to a FS_MATRIX receiving the transformation\n//                          matrix.\n// Return Value:\n//          On success, return TRUE and fill in |matrix|. If |text_page| is\n//          invalid, or if |index| is out of bounds, or if |matrix| is NULL,\n//          then return FALSE, and |matrix| remains unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,\n                                                       int index,\n                                                       FS_MATRIX* matrix);\n\n// Function: FPDFText_GetCharOrigin\n//          Get origin of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          x           -   Pointer to a double number receiving x coordinate of\n//                          the character origin.\n//          y           -   Pointer to a double number receiving y coordinate of\n//                          the character origin.\n// Return Value:\n//          Whether the call succeeded. If false, x and y are unchanged.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,\n                       int index,\n                       double* x,\n                       double* y);\n\n// Function: FPDFText_GetCharIndexAtPos\n//          Get the index of a character at or nearby a certain position on the\n//          page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          x           -   X position in PDF \"user space\".\n//          y           -   Y position in PDF \"user space\".\n//          xTolerance  -   An x-axis tolerance value for character hit\n//                          detection, in point units.\n//          yTolerance  -   A y-axis tolerance value for character hit\n//                          detection, in point units.\n// Return Value:\n//          The zero-based index of the character at, or nearby the point (x,y).\n//          If there is no character at or nearby the point, return value will\n//          be -1. If an error occurs, -3 will be returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,\n                           double x,\n                           double y,\n                           double xTolerance,\n                           double yTolerance);\n\n// Function: FPDFText_GetText\n//          Extract unicode text string from the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start characters.\n//          count       -   Number of UCS-2 values to be extracted.\n//          result      -   A buffer (allocated by application) receiving the\n//                          extracted UCS-2 values. The buffer must be able to\n//                          hold `count` UCS-2 values plus a terminator.\n// Return Value:\n//          Number of characters written into the result buffer, including the\n//          trailing terminator.\n// Comments:\n//          This function ignores characters without UCS-2 representations.\n//          It considers all characters on the page, even those that are not\n//          visible when the page has a cropbox. To filter out the characters\n//          outside of the cropbox, use FPDF_GetPageBoundingBox() and\n//          FPDFText_GetCharBox().\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page,\n                                               int start_index,\n                                               int count,\n                                               unsigned short* result);\n\n// Function: FPDFText_CountRects\n//          Counts number of rectangular areas occupied by a segment of text,\n//          and caches the result for subsequent FPDFText_GetRect() calls.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start character.\n//          count       -   Number of characters, or -1 for all remaining.\n// Return value:\n//          Number of rectangles, 0 if text_page is null, or -1 on bad\n//          start_index.\n// Comments:\n//          This function, along with FPDFText_GetRect can be used by\n//          applications to detect the position on the page for a text segment,\n//          so proper areas can be highlighted. The FPDFText_* functions will\n//          automatically merge small character boxes into bigger one if those\n//          characters are on the same line and use same font settings.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,\n                                                  int start_index,\n                                                  int count);\n\n// Function: FPDFText_GetRect\n//          Get a rectangular area from the result generated by\n//          FPDFText_CountRects.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          rect_index  -   Zero-based index for the rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |text_page| is invalid then return FALSE, and the out\n//          parameters remain unmodified. If |text_page| is valid but\n//          |rect_index| is out of bounds, then return FALSE and set the out\n//          parameters to 0.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Function: FPDFText_GetBoundedText\n//          Extract unicode text within a rectangular boundary on the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          left        -   Left boundary.\n//          top         -   Top boundary.\n//          right       -   Right boundary.\n//          bottom      -   Bottom boundary.\n//          buffer      -   Caller-allocated buffer to receive UTF-16 values.\n//          buflen      -   Number of UTF-16 values (not bytes) that `buffer`\n//                          is capable of holding.\n// Return Value:\n//          If buffer is NULL or buflen is zero, return number of UTF-16\n//          values (not bytes) of text present within the rectangle, excluding\n//          a terminating NUL. Generally you should pass a buffer at least one\n//          larger than this if you want a terminating NUL, which will be\n//          provided if space is available. Otherwise, return number of UTF-16\n//          values copied into the buffer, including the terminating NUL when\n//          space for it is available.\n// Comment:\n//          If the buffer is too small, as much text as will fit is copied into\n//          it. May return a split surrogate in that case.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,\n                                                      double left,\n                                                      double top,\n                                                      double right,\n                                                      double bottom,\n                                                      unsigned short* buffer,\n                                                      int buflen);\n\n// Flags used by FPDFText_FindStart function.\n//\n// If not set, it will not match case by default.\n#define FPDF_MATCHCASE 0x00000001\n// If not set, it will not match the whole word by default.\n#define FPDF_MATCHWHOLEWORD 0x00000002\n// If not set, it will skip past the current match to look for the next match.\n#define FPDF_CONSECUTIVE 0x00000004\n\n// Function: FPDFText_FindStart\n//          Start a search.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          findwhat    -   A unicode match pattern.\n//          flags       -   Option flags.\n//          start_index -   Start from this character. -1 for end of the page.\n// Return Value:\n//          A handle for the search context. FPDFText_FindClose must be called\n//          to release this handle.\n//\nFPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV\nFPDFText_FindStart(FPDF_TEXTPAGE text_page,\n                   FPDF_WIDESTRING findwhat,\n                   unsigned long flags,\n                   int start_index);\n\n// Function: FPDFText_FindNext\n//          Search in the direction from page start to end.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindPrev\n//          Search in the direction from page end to start.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchResultIndex\n//          Get the starting character index of the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Index for the starting character.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchCount\n//          Get the number of matched characters in the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Number of matched characters.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindClose\n//          Release a search context.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle);\n\n// Function: FPDFLink_LoadWebLinks\n//          Prepare information about weblinks in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          A handle to the page's links information structure, or\n//          NULL if something goes wrong.\n// Comments:\n//          Weblinks are those links implicitly embedded in PDF pages. PDF also\n//          has a type of annotation called \"link\" (FPDFTEXT doesn't deal with\n//          that kind of link). FPDFTEXT weblink feature is useful for\n//          automatically detecting links in the page contents. For example,\n//          things like \"https://www.example.com\" will be detected, so\n//          applications can allow user to click on those characters to activate\n//          the link, even the PDF doesn't come with link annotations.\n//\n//          FPDFLink_CloseWebLinks must be called to release resources.\n//\nFPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV\nFPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFLink_CountWebLinks\n//          Count number of detected web links.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          Number of detected web links.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page);\n\n// Function: FPDFLink_GetURL\n//          Fetch the URL information for a detected web link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          buffer      -   A unicode buffer for the result.\n//          buflen      -   Number of 16-bit code units (not bytes) for the\n//                          buffer, including an additional terminator.\n// Return Value:\n//          If |buffer| is NULL or |buflen| is zero, return the number of 16-bit\n//          code units (not bytes) needed to buffer the result (an additional\n//          terminator is included in this count).\n//          Otherwise, copy the result into |buffer|, truncating at |buflen| if\n//          the result is too large to fit, and return the number of 16-bit code\n//          units actually copied into the buffer (the additional terminator is\n//          also included in this count).\n//          If |link_index| does not correspond to a valid link, then the result\n//          is an empty string.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,\n                                              int link_index,\n                                              unsigned short* buffer,\n                                              int buflen);\n\n// Function: FPDFLink_CountRects\n//          Count number of rectangular areas for the link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n// Return Value:\n//          Number of rectangular areas for the link.  If |link_index| does\n//          not correspond to a valid link, then 0 is returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,\n                                                  int link_index);\n\n// Function: FPDFLink_GetRect\n//          Fetch the boundaries of a rectangle for a link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          rect_index  -   Zero-based index for a rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |link_page| is invalid or if |link_index| does not\n//          correspond to a valid link, then return FALSE, and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,\n                                                     int link_index,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Experimental API.\n// Function: FPDFLink_GetTextRange\n//          Fetch the start char index and char count for a link.\n// Parameters:\n//          link_page         -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index        -   Zero-based index for the link.\n//          start_char_index  -   pointer to int receiving the start char index\n//          char_count        -   pointer to int receiving the char count\n// Return Value:\n//          On success, return TRUE and fill in |start_char_index| and\n//          |char_count|. if |link_page| is invalid or if |link_index| does\n//          not correspond to a valid link, then return FALSE and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetTextRange(FPDF_PAGELINK link_page,\n                      int link_index,\n                      int* start_char_index,\n                      int* char_count);\n\n// Function: FPDFLink_CloseWebLinks\n//          Release resources used by weblink feature.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TEXT_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_thumbnail.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_THUMBNAIL_H_\n#define PUBLIC_FPDF_THUMBNAIL_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Gets the decoded data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| less than or equal to the\n// size of the decoded data. Returns the size of the decoded\n// data or 0 if thumbnail DNE. Optional, pass null to just retrieve\n// the size of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the decoded image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetDecodedThumbnailData(FPDF_PAGE page,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Gets the raw data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| is less than or equal to\n// the size of the raw data. Returns the size of the raw data or 0\n// if thumbnail DNE. Optional, pass null to just retrieve the size\n// of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the raw image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetRawThumbnailData(FPDF_PAGE page,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr\n// if unable to access the thumbnail's stream.\n//\n//   page - handle to a page.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_THUMBNAIL_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdf_transformpage.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_\n#define PUBLIC_FPDF_TRANSFORMPAGE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Set \"MediaBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"CropBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"BleedBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"TrimBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"ArtBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page,\n                                                  float left,\n                                                  float bottom,\n                                                  float right,\n                                                  float top);\n\n// Get \"MediaBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"CropBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"BleedBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"TrimBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"ArtBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page,\n                                                       float* left,\n                                                       float* bottom,\n                                                       float* right,\n                                                       float* top);\n\n// Apply transforms to |page|.\n//\n// If |matrix| is provided it will be applied to transform the page.\n// If |clipRect| is provided it will be used to clip the resulting page.\n// If neither |matrix| or |clipRect| are provided this method returns |false|.\n// Returns |true| if transforms are applied.\n//\n// This function will transform the whole page, and would take effect to all the\n// objects in the page.\n//\n// page        - Page handle.\n// matrix      - Transform matrix.\n// clipRect    - Clipping rectangle.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_TransFormWithClip(FPDF_PAGE page,\n                           const FS_MATRIX* matrix,\n                           const FS_RECTF* clipRect);\n\n// Transform (scale, rotate, shear, move) the clip path of page object.\n// page_object - Handle to a page object. Returned by\n// FPDFPageObj_NewImageObj().\n//\n// a  - The coefficient \"a\" of the matrix.\n// b  - The coefficient \"b\" of the matrix.\n// c  - The coefficient \"c\" of the matrix.\n// d  - The coefficient \"d\" of the matrix.\n// e  - The coefficient \"e\" of the matrix.\n// f  - The coefficient \"f\" of the matrix.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,\n                              double a,\n                              double b,\n                              double c,\n                              double d,\n                              double e,\n                              double f);\n\n// Experimental API.\n// Get the clip path of the page object.\n//\n//   page object - Handle to a page object. Returned by e.g.\n//                 FPDFPage_GetObject().\n//\n// Returns the handle to the clip path, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until\n// FPDF_ClosePage() is called for the page containing |page_object|.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV\nFPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of paths inside |clip_path|.\n//\n//   clip_path - handle to a clip_path.\n//\n// Returns the number of objects in |clip_path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path);\n\n// Experimental API.\n// Get number of segments inside one path of |clip_path|.\n//\n//   clip_path  - handle to a clip_path.\n//   path_index - index into the array of paths of the clip path.\n//\n// Returns the number of segments or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index);\n\n// Experimental API.\n// Get segment in one specific path of |clip_path| at index.\n//\n//   clip_path     - handle to a clip_path.\n//   path_index    - the index of a path.\n//   segment_index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid\n// until FPDF_ClosePage() is called for the page containing |clip_path|.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,\n                            int path_index,\n                            int segment_index);\n\n// Create a new clip path, with a rectangle inserted.\n//\n// Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with\n// FPDF_DestroyClipPath().\n//\n// left   - The left of the clip box.\n// bottom - The bottom of the clip box.\n// right  - The right of the clip box.\n// top    - The top of the clip box.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,\n                                                            float bottom,\n                                                            float right,\n                                                            float top);\n\n// Destroy the clip path.\n//\n// clipPath - A handle to the clip path. It will be invalid after this call.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath);\n\n// Clip the page content, the page content that outside the clipping region\n// become invisible.\n//\n// A clip path will be inserted before the page content stream or content array.\n// In this way, the page content will be clipped by this clip path.\n//\n// page        - A page handle.\n// clipPath    - A handle to the clip path. (Does not take ownership.)\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,\n                                                       FPDF_CLIPPATH clipPath);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TRANSFORMPAGE_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdfview.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/include/fpdfview.h.orig",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(COMPONENT_BUILD)\n// FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer\n// template in testing/fuzzers/BUILD.gn.\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n#else\n#define FPDF_EXPORT\n#endif  // defined(COMPONENT_BUILD)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/abseil.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/agg23.txt",
    "content": "//----------------------------------------------------------------------------\n// Anti-Grain Geometry - Version 2.3\n// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)\n//\n// Permission to copy, use, modify, sell and distribute this software\n// is granted provided this copyright notice appears in all copies.\n// This software is provided \"as is\" without express or implied\n// warranty, and with no claim as to its suitability for any purpose.\n//\n//----------------------------------------------------------------------------\n// Contact: mcseem@antigrain.com\n//          mcseemagg@yahoo.com\n//          http://www.antigrain.com\n//----------------------------------------------------------------------------\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/fast_float.txt",
    "content": "MIT License\n\nCopyright (c) 2021 The fast_float authors\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/freetype.txt",
    "content": "                    The FreeType Project LICENSE\n                    ----------------------------\n\n                            2006-Jan-27\n\n                    Copyright 1996-2002, 2006 by\n          David Turner, Robert Wilhelm, and Werner Lemberg\n\n\n\nIntroduction\n============\n\n  The FreeType  Project is distributed in  several archive packages;\n  some of them may contain, in addition to the FreeType font engine,\n  various tools and  contributions which rely on, or  relate to, the\n  FreeType Project.\n\n  This  license applies  to all  files found  in such  packages, and\n  which do not  fall under their own explicit  license.  The license\n  affects  thus  the  FreeType   font  engine,  the  test  programs,\n  documentation and makefiles, at the very least.\n\n  This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG\n  (Independent JPEG  Group) licenses, which  all encourage inclusion\n  and  use of  free  software in  commercial  and freeware  products\n  alike.  As a consequence, its main points are that:\n\n    o We don't promise that this software works. However, we will be\n      interested in any kind of bug reports. (`as is' distribution)\n\n    o You can  use this software for whatever you  want, in parts or\n      full form, without having to pay us. (`royalty-free' usage)\n\n    o You may not pretend that  you wrote this software.  If you use\n      it, or  only parts of it,  in a program,  you must acknowledge\n      somewhere  in  your  documentation  that  you  have  used  the\n      FreeType code. (`credits')\n\n  We  specifically  permit  and  encourage  the  inclusion  of  this\n  software, with  or without modifications,  in commercial products.\n  We  disclaim  all warranties  covering  The  FreeType Project  and\n  assume no liability related to The FreeType Project.\n\n\n  Finally,  many  people  asked  us  for  a  preferred  form  for  a\n  credit/disclaimer to use in compliance with this license.  We thus\n  encourage you to use the following text:\n\n   \"\"\"\n    Portions of this software are copyright  <year> The FreeType\n    Project (www.freetype.org).  All rights reserved.\n   \"\"\"\n\n  Please replace <year> with the value from the FreeType version you\n  actually use.\n\n\nLegal Terms\n===========\n\n0. Definitions\n--------------\n\n  Throughout this license,  the terms `package', `FreeType Project',\n  and  `FreeType  archive' refer  to  the  set  of files  originally\n  distributed  by the  authors  (David Turner,  Robert Wilhelm,  and\n  Werner Lemberg) as the `FreeType Project', be they named as alpha,\n  beta or final release.\n\n  `You' refers to  the licensee, or person using  the project, where\n  `using' is a generic term including compiling the project's source\n  code as  well as linking it  to form a  `program' or `executable'.\n  This  program is  referred to  as  `a program  using the  FreeType\n  engine'.\n\n  This  license applies  to all  files distributed  in  the original\n  FreeType  Project,   including  all  source   code,  binaries  and\n  documentation,  unless  otherwise  stated   in  the  file  in  its\n  original, unmodified form as  distributed in the original archive.\n  If you are  unsure whether or not a particular  file is covered by\n  this license, you must contact us to verify this.\n\n  The FreeType  Project is copyright (C) 1996-2000  by David Turner,\n  Robert Wilhelm, and Werner Lemberg.  All rights reserved except as\n  specified below.\n\n1. No Warranty\n--------------\n\n  THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY\n  KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,\n  WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR\n  PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS\n  BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO\n  USE, OF THE FREETYPE PROJECT.\n\n2. Redistribution\n-----------------\n\n  This  license  grants  a  worldwide, royalty-free,  perpetual  and\n  irrevocable right  and license to use,  execute, perform, compile,\n  display,  copy,   create  derivative  works   of,  distribute  and\n  sublicense the  FreeType Project (in  both source and  object code\n  forms)  and  derivative works  thereof  for  any  purpose; and  to\n  authorize others  to exercise  some or all  of the  rights granted\n  herein, subject to the following conditions:\n\n    o Redistribution of  source code  must retain this  license file\n      (`FTL.TXT') unaltered; any  additions, deletions or changes to\n      the original  files must be clearly  indicated in accompanying\n      documentation.   The  copyright   notices  of  the  unaltered,\n      original  files must  be  preserved in  all  copies of  source\n      files.\n\n    o Redistribution in binary form must provide a  disclaimer  that\n      states  that  the software is based in part of the work of the\n      FreeType Team,  in  the  distribution  documentation.  We also\n      encourage you to put an URL to the FreeType web page  in  your\n      documentation, though this isn't mandatory.\n\n  These conditions  apply to any  software derived from or  based on\n  the FreeType Project,  not just the unmodified files.   If you use\n  our work, you  must acknowledge us.  However, no  fee need be paid\n  to us.\n\n3. Advertising\n--------------\n\n  Neither the  FreeType authors and  contributors nor you  shall use\n  the name of the  other for commercial, advertising, or promotional\n  purposes without specific prior written permission.\n\n  We suggest,  but do not require, that  you use one or  more of the\n  following phrases to refer  to this software in your documentation\n  or advertising  materials: `FreeType Project',  `FreeType Engine',\n  `FreeType library', or `FreeType Distribution'.\n\n  As  you have  not signed  this license,  you are  not  required to\n  accept  it.   However,  as  the FreeType  Project  is  copyrighted\n  material, only  this license, or  another one contracted  with the\n  authors, grants you  the right to use, distribute,  and modify it.\n  Therefore,  by  using,  distributing,  or modifying  the  FreeType\n  Project, you indicate that you understand and accept all the terms\n  of this license.\n\n4. Contacts\n-----------\n\n  There are two mailing lists related to FreeType:\n\n    o freetype@nongnu.org\n\n      Discusses general use and applications of FreeType, as well as\n      future and  wanted additions to the  library and distribution.\n      If  you are looking  for support,  start in  this list  if you\n      haven't found anything to help you in the documentation.\n\n    o freetype-devel@nongnu.org\n\n      Discusses bugs,  as well  as engine internals,  design issues,\n      specific licenses, porting, etc.\n\n  Our home page can be found at\n\n    http://www.freetype.org\n\n\n--- end of FTL.TXT ---\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/icu.txt",
    "content": "UNICODE LICENSE V3\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright © 2016-2025 Unicode, Inc.\n\nNOTICE TO USER: Carefully read the following legal agreement. BY\nDOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\nSOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\nTERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\nDOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of data files and any associated documentation (the \"Data Files\") or\nsoftware and any associated documentation (the \"Software\") to deal in the\nData Files or Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, and/or sell\ncopies of the Data Files or Software, and to permit persons to whom the\nData Files or Software are furnished to do so, provided that either (a)\nthis copyright and permission notice appear with all copies of the Data\nFiles or Software, or (b) this copyright and permission notice appear in\nassociated Documentation.\n\nTHE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\nKIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\nTHIRD PARTY RIGHTS.\n\nIN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\nBE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\nFILES OR SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder shall\nnot be used in advertising or otherwise to promote the sale, use or other\ndealings in these Data Files or Software without prior written\nauthorization of the copyright holder.\n\nSPDX-License-Identifier: Unicode-3.0\n\n----------------------------------------------------------------------\n\nThird-Party Software Licenses\n\nThis section contains third-party software notices and/or additional\nterms for licensed third-party software components included within ICU\nlibraries.\n\n----------------------------------------------------------------------\n\nICU License - ICU 1.8.1 to ICU 57.1\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright (c) 1995-2016 International Business Machines Corporation and others\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, and/or sell copies of the Software, and to permit persons\nto whom the Software is furnished to do so, provided that the above\ncopyright notice(s) and this permission notice appear in all copies of\nthe Software and that both the above copyright notice(s) and this\npermission notice appear in supporting documentation.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\nHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\nSPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\nRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\nCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder\nshall not be used in advertising or otherwise to promote the sale, use\nor other dealings in this Software without prior written authorization\nof the copyright holder.\n\nAll trademarks and registered trademarks mentioned herein are the\nproperty of their respective owners.\n\n----------------------------------------------------------------------\n\nChinese/Japanese Word Break Dictionary Data (cjdict.txt)\n\n #     The Google Chrome software developed by Google is licensed under\n # the BSD license. Other software included in this distribution is\n # provided under other licenses, as set forth below.\n #\n #  The BSD License\n #  http://opensource.org/licenses/bsd-license.php\n #  Copyright (C) 2006-2008, Google Inc.\n #\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice,\n # this list of conditions and the following disclaimer.\n #  Redistributions in binary form must reproduce the above\n # copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided with\n # the distribution.\n #  Neither the name of  Google Inc. nor the names of its\n # contributors may be used to endorse or promote products derived from\n # this software without specific prior written permission.\n #\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #\n #\n #  The word list in cjdict.txt are generated by combining three word lists\n # listed below with further processing for compound word breaking. The\n # frequency is generated with an iterative training against Google web\n # corpora.\n #\n #  * Libtabe (Chinese)\n #    - https://sourceforge.net/project/?group_id=1519\n #    - Its license terms and conditions are shown below.\n #\n #  * IPADIC (Japanese)\n #    - http://chasen.aist-nara.ac.jp/chasen/distribution.html\n #    - Its license terms and conditions are shown below.\n #\n #  ---------COPYING.libtabe ---- BEGIN--------------------\n #\n #  /*\n #   * Copyright (c) 1999 TaBE Project.\n #   * Copyright (c) 1999 Pai-Hsiang Hsiao.\n #   * All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the TaBE Project nor the names of its\n #   *   contributors may be used to endorse or promote products derived\n #   *   from this software without specific prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  /*\n #   * Copyright (c) 1999 Computer Systems and Communication Lab,\n #   *                    Institute of Information Science, Academia\n #       *                    Sinica. All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the Computer Systems and Communication Lab\n #   *   nor the names of its contributors may be used to endorse or\n #   *   promote products derived from this software without specific\n #   *   prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\n #      University of Illinois\n #  c-tsai4@uiuc.edu  http://casper.beckman.uiuc.edu/~c-tsai4\n #\n #  ---------------COPYING.libtabe-----END--------------------------------\n #\n #\n #  ---------------COPYING.ipadic-----BEGIN-------------------------------\n #\n #  Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\n #  and Technology.  All Rights Reserved.\n #\n #  Use, reproduction, and distribution of this software is permitted.\n #  Any copy of this software, whether in its original form or modified,\n #  must include both the above copyright notice and the following\n #  paragraphs.\n #\n #  Nara Institute of Science and Technology (NAIST),\n #  the copyright holders, disclaims all warranties with regard to this\n #  software, including all implied warranties of merchantability and\n #  fitness, in no event shall NAIST be liable for\n #  any special, indirect or consequential damages or any damages\n #  whatsoever resulting from loss of use, data or profits, whether in an\n #  action of contract, negligence or other tortuous action, arising out\n #  of or in connection with the use or performance of this software.\n #\n #  A large portion of the dictionary entries\n #  originate from ICOT Free Software.  The following conditions for ICOT\n #  Free Software applies to the current dictionary as well.\n #\n #  Each User may also freely distribute the Program, whether in its\n #  original form or modified, to any third party or parties, PROVIDED\n #  that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\n #  on, or be attached to, the Program, which is distributed substantially\n #  in the same form as set out herein and that such intended\n #  distribution, if actually made, will neither violate or otherwise\n #  contravene any of the laws and regulations of the countries having\n #  jurisdiction over the User or the intended distribution itself.\n #\n #  NO WARRANTY\n #\n #  The program was produced on an experimental basis in the course of the\n #  research and development conducted during the project and is provided\n #  to users as so produced on an experimental basis.  Accordingly, the\n #  program is provided without any warranty whatsoever, whether express,\n #  implied, statutory or otherwise.  The term \"warranty\" used herein\n #  includes, but is not limited to, any warranty of the quality,\n #  performance, merchantability and fitness for a particular purpose of\n #  the program and the nonexistence of any infringement or violation of\n #  any right of any third party.\n #\n #  Each user of the program will agree and understand, and be deemed to\n #  have agreed and understood, that there is no warranty whatsoever for\n #  the program and, accordingly, the entire risk arising from or\n #  otherwise connected with the program is assumed by the user.\n #\n #  Therefore, neither ICOT, the copyright holder, or any other\n #  organization that participated in or was otherwise related to the\n #  development of the program and their respective officials, directors,\n #  officers and other employees shall be held liable for any and all\n #  damages, including, without limitation, general, special, incidental\n #  and consequential damages, arising out of or otherwise in connection\n #  with the use or inability to use the program or any product, material\n #  or result produced or otherwise obtained by using the program,\n #  regardless of whether they have been advised of, or otherwise had\n #  knowledge of, the possibility of such damages at any time during the\n #  project or thereafter.  Each user will be deemed to have agreed to the\n #  foregoing by his or her commencement of use of the program.  The term\n #  \"use\" as used herein includes, but is not limited to, the use,\n #  modification, copying and distribution of the program and the\n #  production of secondary products from the program.\n #\n #  In the case where the program, whether in its original form or\n #  modified, was distributed or delivered to or received by a user from\n #  any person, organization or entity other than ICOT, unless it makes or\n #  grants independently of ICOT any specific warranty to the user in\n #  writing, such person, organization or entity, will also be exempted\n #  from and not be held liable to the user for any such damages as noted\n #  above as far as the program is concerned.\n #\n #  ---------------COPYING.ipadic-----END----------------------------------\n\n----------------------------------------------------------------------\n\nLao Word Break Dictionary Data (laodict.txt)\n\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\n # License & terms of use: http://www.unicode.org/copyright.html\n # Copyright (c) 2015 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # Project: https://github.com/rober42539/lao-dictionary\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\n #          (copied below)\n #\n #\tThis file is derived from the above dictionary version of Nov 22, 2020\n #  ----------------------------------------------------------------------\n #  Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice, this\n #  list of conditions and the following disclaimer. Redistributions in binary\n #  form must reproduce the above copyright notice, this list of conditions and\n #  the following disclaimer in the documentation and/or other materials\n #  provided with the distribution.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # OF THE POSSIBILITY OF SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nBurmese Word Break Dictionary Data (burmesedict.txt)\n\n #  Copyright (c) 2014 International Business Machines Corporation\n #  and others. All Rights Reserved.\n #\n #  This list is part of a project hosted at:\n #    github.com/kanyawtech/myanmar-karen-word-lists\n #\n #  --------------------------------------------------------------------------\n #  Copyright (c) 2013, LeRoy Benjamin Sharon\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions\n #  are met: Redistributions of source code must retain the above\n #  copyright notice, this list of conditions and the following\n #  disclaimer.  Redistributions in binary form must reproduce the\n #  above copyright notice, this list of conditions and the following\n #  disclaimer in the documentation and/or other materials provided\n #  with the distribution.\n #\n #    Neither the name Myanmar Karen Word Lists, nor the names of its\n #    contributors may be used to endorse or promote products derived\n #    from this software without specific prior written permission.\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n #  CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n #  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n #  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n #  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n #  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n #  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n #  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\n #  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n #  SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nTime Zone Database\n\n  ICU uses the public domain data and code derived from Time Zone\nDatabase for its time zone support. The ownership of the TZ database\nis explained in BCP 175: Procedure for Maintaining the Time Zone\nDatabase section 7.\n\n # 7.  Database Ownership\n #\n #    The TZ database itself is not an IETF Contribution or an IETF\n #    document.  Rather it is a pre-existing and regularly updated work\n #    that is in the public domain, and is intended to remain in the\n #    public domain.  Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\n #    not apply to the TZ Database or contributions that individuals make\n #    to it.  Should any claims be made and substantiated against the TZ\n #    Database, the organization that is providing the IANA\n #    Considerations defined in this RFC, under the memorandum of\n #    understanding with the IETF, currently ICANN, may act in accordance\n #    with all competent court orders.  No ownership claims will be made\n #    by ICANN or the IETF Trust on the database or the code.  Any person\n #    making a contribution to the database or code waives all rights to\n #    future claims in that contribution or in the TZ Database.\n\n----------------------------------------------------------------------\n\nGoogle double-conversion\n\nCopyright 2006-2011, the V8 project authors. All rights reserved.\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials provided\n      with the distribution.\n    * Neither the name of Google Inc. nor the names of its\n      contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n----------------------------------------------------------------------\n\nJSON parsing library (nlohmann/json)\n\nFile: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\n\nMIT License\n\nCopyright (c) 2013-2022 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n----------------------------------------------------------------------\n\nFile: aclocal.m4 (only for ICU4C)\nSection: pkg.m4 - Macros to locate and utilise pkg-config.\n\n\nCopyright © 2004 Scott James Remnant <scott@netsplit.com>.\nCopyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n02111-1307, USA.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: config.guess (only for ICU4C)\n\n\nThis file is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, see <https://www.gnu.org/licenses/>.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.  This Exception is an additional permission under section 7\nof the GNU General Public License, version 3 (\"GPLv3\").\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: install-sh (only for ICU4C)\n\n\nCopyright 1991 by the Massachusetts Institute of Technology\n\nPermission to use, copy, modify, distribute, and sell this software and its\ndocumentation for any purpose is hereby granted without fee, provided that\nthe above copyright notice appear in all copies and that both that\ncopyright notice and this permission notice appear in supporting\ndocumentation, and that the name of M.I.T. not be used in advertising or\npublicity pertaining to distribution of the software without specific,\nwritten prior permission.  M.I.T. makes no representations about the\nsuitability of this software for any purpose.  It is provided \"as is\"\nwithout express or implied warranty.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/lcms.txt",
    "content": "//---------------------------------------------------------------------------------\n//\n//  Little Color Management System\n//  Copyright (c) 1998-2023 Marti Maria Saguer\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the Software\n// is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n//---------------------------------------------------------------------------------\n//\n// Version 2.15 \n//\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/libjpeg_turbo.ijg",
    "content": "libjpeg-turbo note:  This file has been modified by The libjpeg-turbo Project\nto include only information relevant to libjpeg-turbo, to wordsmith certain\nsections, and to remove impolitic language that existed in the libjpeg v8\nREADME.  It is included only for reference.  Please see README.md for\ninformation specific to libjpeg-turbo.\n\n\nThe Independent JPEG Group's JPEG software\n==========================================\n\nThis distribution contains a release of the Independent JPEG Group's free JPEG\nsoftware.  You are welcome to redistribute this software and to use it for any\npurpose, subject to the conditions under LEGAL ISSUES, below.\n\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\nJulian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,\nand other members of the Independent JPEG Group.\n\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\n(also known as JPEG, together with ITU-T SG16).\n\n\nDOCUMENTATION ROADMAP\n=====================\n\nThis file contains the following sections:\n\nOVERVIEW            General description of JPEG and the IJG software.\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\nREFERENCES          Where to learn more about JPEG.\nARCHIVE LOCATIONS   Where to find newer versions of this software.\nFILE FORMAT WARS    Software *not* to get.\nTO DO               Plans for future IJG releases.\n\nOther documentation files in the distribution are:\n\nUser documentation:\n  doc/usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\n                        rdjpgcom, and wrjpgcom.\n  doc/*.1               Unix-style man pages for programs (same info as\n                        usage.txt).\n  doc/wizard.txt        Advanced usage instructions for JPEG wizards only.\n  doc/change.log        Version-to-version change highlights.\nProgrammer and internal documentation:\n  doc/libjpeg.txt       How to use the JPEG library in your own programs.\n  src/example.c         Sample code for calling the JPEG library.\n  doc/structure.txt     Overview of the JPEG library's internal structure.\n  doc/coderules.txt     Coding style rules --- please read if you contribute\n                        code.\n\nPlease read at least usage.txt.  Some information can also be found in the JPEG\nFAQ (Frequently Asked Questions) article.  See ARCHIVE LOCATIONS below to find\nout where to obtain the FAQ article.\n\nIf you want to understand how the JPEG code works, we suggest reading one or\nmore of the REFERENCES, then looking at the documentation files (in roughly\nthe order listed) before diving into the code.\n\n\nOVERVIEW\n========\n\nThis package contains C software to implement JPEG image encoding, decoding,\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\nmethod for full-color and grayscale images.  JPEG's strong suit is compressing\nphotographic images or other types of images that have smooth color and\nbrightness transitions between neighboring pixels.  Images with sharp lines or\nother abrupt features may not compress well with JPEG, and a higher JPEG\nquality may have to be used to avoid visible compression artifacts with such\nimages.\n\nJPEG is normally lossy, meaning that the output pixels are not necessarily\nidentical to the input pixels.  However, on photographic content and other\n\"smooth\" images, very good compression ratios can be obtained with no visible\ncompression artifacts, and extremely high compression ratios are possible if\nyou are willing to sacrifice image quality (by reducing the \"quality\" setting\nin the compressor.)\n\nThis software implements JPEG baseline, extended-sequential, progressive, and\nlossless compression processes.  Provision is made for supporting all variants\nof these processes, although some uncommon parameter settings aren't\nimplemented yet.  We have made no provision for supporting the hierarchical\nprocesses defined in the standard.\n\nWe provide a set of library routines for reading and writing JPEG image files,\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\nperform conversion between JPEG and some other popular image file formats.\nThe library is intended to be reused in other applications.\n\nIn order to support file conversion and viewing software, we have included\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\nfor example, the color quantization modules are not strictly part of JPEG\ndecoding, but they are essential for output to colormapped file formats.  These\nextra functions can be compiled out of the library if not required for a\nparticular application.\n\nWe have also included \"jpegtran\", a utility for lossless transcoding between\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\napplications for inserting and extracting textual comments in JFIF files.\n\nThe emphasis in designing this software has been on achieving portability and\nflexibility, while also making it fast enough to be useful.  In particular,\nthe software is not intended to be read as a tutorial on JPEG.  (See the\nREFERENCES section for introductory material.)  Rather, it is intended to\nbe reliable, portable, industrial-strength code.  We do not claim to have\nachieved that goal in every aspect of the software, but we strive for it.\n\nWe welcome the use of this software as a component of commercial products.\nNo royalty is required, but we do ask for an acknowledgement in product\ndocumentation, as described under LEGAL ISSUES.\n\n\nLEGAL ISSUES\n============\n\nIn plain English:\n\n1. We don't promise that this software works.  (But if you find any bugs,\n   please let us know!)\n2. You can use this software for whatever you want.  You don't have to pay us.\n3. You may not pretend that you wrote this software.  If you use it in a\n   program, you must acknowledge somewhere in your documentation that\n   you've used the IJG code.\n\nIn legalese:\n\nThe authors make NO WARRANTY or representation, either express or implied,\nwith respect to this software, its quality, accuracy, merchantability, or\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\nits user, assume the entire risk as to its quality and accuracy.\n\nThis software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.\nAll Rights Reserved except as specified below.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nPermission is NOT granted for the use of any IJG author's name or company name\nin advertising or publicity relating to this software or products derived from\nit.  This software may be referred to only as \"the Independent JPEG Group's\nsoftware\".\n\nWe specifically permit and encourage the use of this software as the basis of\ncommercial products, provided that all warranty or liability claims are\nassumed by the product vendor.\n\n\nREFERENCES\n==========\n\nWe recommend reading one or more of these references before trying to\nunderstand the innards of the JPEG software.\n\nThe best short technical introduction to the JPEG compression algorithm is\n        Wallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\n        Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\n(Adjacent articles in that issue discuss MPEG motion picture compression,\napplications of JPEG, and related topics.)  If you don't have the CACM issue\nhandy, a PDF file containing a revised version of Wallace's article is\navailable at http://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\nomits the sample images that appeared in CACM, but it includes corrections\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\nand it may not be used for commercial purposes.\n\nA somewhat less technical, more leisurely introduction to JPEG can be found in\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\ngood explanations and example C code for a multitude of compression methods\nincluding JPEG.  It is an excellent source if you are comfortable reading C\ncode but don't know much about data compression in general.  The book's JPEG\nsample code is far from industrial-strength, but when you are ready to look\nat a full implementation, you've got one here...\n\nThe best currently available description of JPEG is the textbook \"JPEG Still\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\nstandards (DIS 10918-1 and draft DIS 10918-2).\n\nThe original JPEG standard is divided into two parts, Part 1 being the actual\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\n\nThe JPEG standard does not specify all details of an interchangeable file\nformat.  For the omitted details, we follow the \"JFIF\" conventions, revision\n1.02.  JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and\nRecommendation ITU-T T.871 (05/2011): Information technology - Digital\ncompression and coding of continuous-tone still images: JPEG File Interchange\nFormat (JFIF).  It is available as a free download in PDF file format from\nhttps://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.\nA PDF file of the older JFIF 1.02 specification is available at\nhttp://www.w3.org/Graphics/JPEG/jfif3.pdf.\n\nThe TIFF 6.0 file format specification can be obtained from\nhttp://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation\nscheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious\nproblems.  IJG does not recommend use of the TIFF 6.0 design (TIFF Compression\ntag 6).  Instead, we recommend the JPEG design proposed by TIFF Technical Note\n#2 (Compression tag 7).  Copies of this Note can be obtained from\nhttp://www.ijg.org/files/.  It is expected that the next revision\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\nuses our library to implement TIFF/JPEG per the Note.\n\n\nARCHIVE LOCATIONS\n=================\n\nThe \"official\" archive site for this software is www.ijg.org.\nThe most recent released version can always be found there in\ndirectory \"files\".\n\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\ngeneral information about JPEG.  It is available at\nhttp://www.faqs.org/faqs/jpeg-faq.\n\n\nFILE FORMAT COMPATIBILITY\n=========================\n\nThis software implements ITU T.81 | ISO/IEC 10918 with some extensions from\nITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).\nInformally, the term \"JPEG image\" or \"JPEG file\" most often refers to JFIF or\na subset thereof, but there are other formats containing the name \"JPEG\" that\nare incompatible with the original JPEG standard or with JFIF (for instance,\nJPEG 2000 and JPEG XR).  This software therefore does not support these\nformats.  Indeed, one of the original reasons for developing this free software\nwas to help force convergence on a common, interoperable format standard for\nJPEG files.\n\nJFIF is a minimal or \"low end\" representation.  TIFF/JPEG (TIFF revision 6.0 as\nmodified by TIFF Technical Note #2) can be used for \"high end\" applications\nthat need to record a lot of additional data about an image.\n\n\nTO DO\n=====\n\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/libjpeg_turbo.md",
    "content": "libjpeg-turbo Licenses\n======================\n\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\n\n- The IJG (Independent JPEG Group) License, which is listed in\n  [README.ijg](README.ijg)\n\n  This license applies to the libjpeg API library and associated programs,\n  including any code inherited from libjpeg and any modifications to that\n  code.  Note that the libjpeg-turbo SIMD source code bears the\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\n  the overall libjpeg API library, the terms of the zlib License are subsumed\n  by the terms of the IJG License.\n\n- The Modified (3-clause) BSD License, which is listed below\n\n  This license applies to the TurboJPEG API library and associated programs, as\n  well as the build system.  Note that the TurboJPEG API library wraps the\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\n  both the terms of the IJG License and the terms of the Modified (3-clause)\n  BSD License apply.\n\n\nComplying with the libjpeg-turbo Licenses\n=========================================\n\nThis section provides a roll-up of the libjpeg-turbo licensing terms, to the\nbest of our understanding.  This is not a license in and of itself.  It is\nintended solely for clarification.\n\n1.  If you are distributing a modified version of the libjpeg-turbo source,\n    then:\n\n    1.  You cannot alter or remove any existing copyright or license notices\n        from the source.\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 1 of the Modified BSD License\n        - Clauses 1 and 3 of the zlib License\n\n    2.  You must add your own copyright notice to the header of each source\n        file you modified, so others can tell that you modified that file.  (If\n        there is not an existing copyright header in that file, then you can\n        simply add a notice stating that you modified the file.)\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 2 of the zlib License\n\n    3.  You must include the IJG README file, and you must not alter any of the\n        copyright or license text in that file.\n\n        **Origin**\n        - Clause 1 of the IJG License\n\n2.  If you are distributing only libjpeg-turbo binaries without the source, or\n    if you are distributing an application that statically links with\n    libjpeg-turbo, then:\n\n    1.  Your product documentation must include a message stating:\n\n        This software is based in part on the work of the Independent JPEG\n        Group.\n\n        **Origin**\n        - Clause 2 of the IJG license\n\n    2.  If your binary distribution includes or uses the TurboJPEG API, then\n        your product documentation must include the text of the Modified BSD\n        License (see below.)\n\n        **Origin**\n        - Clause 2 of the Modified BSD License\n\n3.  You cannot use the name of the IJG or The libjpeg-turbo Project or the\n    contributors thereof in advertising, publicity, etc.\n\n    **Origin**\n    - IJG License\n    - Clause 3 of the Modified BSD License\n\n4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be\n    free of defects, nor do we accept any liability for undesirable\n    consequences resulting from your use of the software.\n\n    **Origin**\n    - IJG License\n    - Modified BSD License\n    - zlib License\n\n\nThe Modified (3-clause) BSD License\n===================================\n\nCopyright (C)2009-2024 D. R. Commander.  All Rights Reserved.<br>\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n- Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n- Neither the name of the libjpeg-turbo Project nor the names of its\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n\nWhy Two Licenses?\n=================\n\nThe zlib License could have been used instead of the Modified (3-clause) BSD\nLicense, and since the IJG License effectively subsumes the distribution\nconditions of the zlib License, this would have effectively placed\nlibjpeg-turbo binary distributions under the IJG License.  However, the IJG\nLicense specifically refers to the Independent JPEG Group and does not extend\nattribution and endorsement protections to other entities.  Thus, it was\ndesirable to choose a license that granted us the same protections for new code\nthat were granted to the IJG for code derived from their software.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/libopenjpeg.txt",
    "content": "/*\n * The copyright in this software is being made available under the 2-clauses\n * BSD License, included below. This software may be subject to other third\n * party and contributor rights, including patent rights, and no such rights\n * are granted under this license.\n *\n * Copyright (c) 2005, Herve Drolon, FreeImage Team\n * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR\n * Copyright (c) 2012, CS Systemes d'Information, France\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/libpng.txt",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n=========================================\n\nPNG Reference Library License version 2\n---------------------------------------\n\n * Copyright (c) 1995-2019 The PNG Reference Library Authors.\n * Copyright (c) 2018-2019 Cosmin Truta.\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n * Copyright (c) 1996-1997 Andreas Dilger.\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nThe software is supplied \"as is\", without warranty of any kind,\nexpress or implied, including, without limitation, the warranties\nof merchantability, fitness for a particular purpose, title, and\nnon-infringement.  In no event shall the Copyright owners, or\nanyone distributing the software, be liable for any damages or\nother liability, whether in contract, tort or otherwise, arising\nfrom, out of, or in connection with the software, or the use or\nother dealings in the software, even if advised of the possibility\nof such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute\nthis software, or portions hereof, for any purpose, without fee,\nsubject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you\n    must not claim that you wrote the original software.  If you\n    use this software in a product, an acknowledgment in the product\n    documentation would be appreciated, but is not required.\n\n 2. Altered source versions must be plainly marked as such, and must\n    not be misrepresented as being the original software.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\n\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n-----------------------------------------------------------------------\n\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\nderived from libpng-1.0.6, and are distributed according to the same\ndisclaimer and license as libpng-1.0.6 with the following individuals\nadded to the list of Contributing Authors:\n\n    Simon-Pierre Cadieux\n    Eric S. Raymond\n    Mans Rullgard\n    Cosmin Truta\n    Gilles Vollant\n    James Yu\n    Mandar Sahastrabuddhe\n    Google Inc.\n    Vadim Barkov\n\nand with the following additions to the disclaimer:\n\n    There is no warranty against interference with your enjoyment of\n    the library or against infringement.  There is no warranty that our\n    efforts or the library will fulfill any of your particular purposes\n    or needs.  This library is provided with all faults, and the entire\n    risk of satisfactory quality, performance, accuracy, and effort is\n    with the user.\n\nSome files in the \"contrib\" directory and some configure-generated\nfiles that are distributed with libpng have other copyright owners, and\nare released under other open source licenses.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\nlibpng-0.96, and are distributed according to the same disclaimer and\nlicense as libpng-0.96, with the following individuals added to the\nlist of Contributing Authors:\n\n    Tom Lane\n    Glenn Randers-Pehrson\n    Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\nand are distributed according to the same disclaimer and license as\nlibpng-0.88, with the following individuals added to the list of\nContributing Authors:\n\n    John Bowler\n    Kevin Bracey\n    Sam Bushell\n    Magnus Holmgren\n    Greg Roelofs\n    Tom Tanner\n\nSome files in the \"scripts\" directory have other copyright owners,\nbut are released under this license.\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n    Andreas Dilger\n    Dave Martindale\n    Guy Eric Schalnat\n    Paul Schmidt\n    Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\nimplied, including, without limitation, the warranties of\nmerchantability and of fitness for any purpose.  The Contributing\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\nincidental, special, exemplary, or consequential damages, which may\nresult from the use of the PNG Reference Library, even if advised of\nthe possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n 1. The origin of this source code must not be misrepresented.\n\n 2. Altered versions must be plainly marked as such and must not\n    be misrepresented as being the original source.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit,\nwithout fee, and encourage the use of this source code as a component\nto supporting the PNG file format in commercial products.  If you use\nthis source code in a product, acknowledgment is not required but would\nbe appreciated.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/libtiff.txt",
    "content": "Copyright (c) 1988-1997 Sam Leffler\nCopyright (c) 1991-1997 Silicon Graphics, Inc.\n\nPermission to use, copy, modify, distribute, and sell this software and\nits documentation for any purpose is hereby granted without fee, provided\nthat (i) the above copyright notices and this permission notice appear in\nall copies of the software and related documentation, and (ii) the names of\nSam Leffler and Silicon Graphics may not be used in any advertising or\npublicity relating to the software without the specific, prior written\npermission of Sam Leffler and Silicon Graphics.\n\nTHE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\nEXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\nWARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n\nIN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR\nANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF\nLIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\nOF THIS SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/llvm-libc.txt",
    "content": "==============================================================================\nThe LLVM Project is under the Apache License v2.0 with LLVM Exceptions:\n==============================================================================\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n    1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n    2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n    3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n    4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n    5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n    6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n    7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n    8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n    9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    END OF TERMS AND CONDITIONS\n\n    APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n    Copyright [yyyy] [name of copyright owner]\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n---- LLVM Exceptions to the Apache 2.0 License ----\n\nAs an exception, if, as a result of your compiling your source code, portions\nof this Software are embedded into an Object form of such source code, you\nmay redistribute such embedded portions in such Object form without complying\nwith the conditions of Sections 4(a), 4(b) and 4(d) of the License.\n\nIn addition, if you combine or link compiled forms of this Software with\nsoftware that is licensed under the GPLv2 (\"Combined Software\") and if a\ncourt of competent jurisdiction determines that the patent provision (Section\n3), the indemnity provision (Section 9) or other Section of the License\nconflicts with the conditions of the GPLv2, you may retroactively and\nprospectively choose to deem waived or otherwise exclude such Section(s) of\nthe License, but only in their entirety and only with respect to the Combined\nSoftware.\n\n==============================================================================\nSoftware from third parties included in the LLVM Project:\n==============================================================================\nThe LLVM Project contains third party software which is under different license\nterms. All such code will be identified clearly using at least one of two\nmechanisms:\n1) It will be in a separate directory tree with its own `LICENSE.txt` or\n   `LICENSE` file at the top containing the specific license and restrictions\n   which apply to that software, or\n2) It will contain specific license and restriction terms at the top of every\n   file.\n\n==============================================================================\nLegacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):\n==============================================================================\nUniversity of Illinois/NCSA\nOpen Source License\n\nCopyright (c) 2007-2019 University of Illinois at Urbana-Champaign.\nAll rights reserved.\n\nDeveloped by:\n\n    LLVM Team\n\n    University of Illinois at Urbana-Champaign\n\n    http://llvm.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal with\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimers.\n\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimers in the\n      documentation and/or other materials provided with the distribution.\n\n    * Neither the names of the LLVM Team, University of Illinois at\n      Urbana-Champaign, nor the names of its contributors may be used to\n      endorse or promote products derived from this Software without specific\n      prior written permission.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nCONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE\nSOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/pdfium.txt",
    "content": "// Copyright 2014 The PDFium Authors\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/simdutf.txt",
    "content": "Copyright 2021 The simdutf authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-arm64/licenses/zlib.txt",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.3.1, January 22nd, 2024\n\n  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n"
  },
  {
    "path": "external/pdfium/macos-x64/LICENSE",
    "content": "Copyright 2014-2025 Benoit Blanchon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nThis package also includes third-party software. See the licenses/ directory for their respective licenses.\n"
  },
  {
    "path": "external/pdfium/macos-x64/PDFiumConfig.cmake",
    "content": "# PDFium Package Configuration for CMake\n#\n# To use PDFium in your CMake project:\n#\n#   1. set the environment variable PDFium_DIR to the folder containing this file.\n#   2. in your CMakeLists.txt, add\n#       find_package(PDFium)\n#   3. then link your executable with PDFium\n#       target_link_libraries(my_exe pdfium)\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_path(PDFium_INCLUDE_DIR\n    NAMES \"fpdfview.h\"\n    PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n    PATH_SUFFIXES \"include\"\n)\n\nset(PDFium_VERSION \"147.0.7713.0\")\n\nif(WIN32)\n  find_file(PDFium_LIBRARY\n        NAMES \"pdfium.dll\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"bin\")\n\n  find_file(PDFium_IMPLIB\n        NAMES \"pdfium.dll.lib\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    IMPORTED_IMPLIB               \"${PDFium_IMPLIB}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nelse()\n  find_library(PDFium_LIBRARY\n        NAMES \"pdfium\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nendif()\n"
  },
  {
    "path": "external/pdfium/macos-x64/VERSION",
    "content": "MAJOR=147\nMINOR=0\nBUILD=7713\nPATCH=0\n"
  },
  {
    "path": "external/pdfium/macos-x64/args.gn",
    "content": "clang_use_chrome_plugins = false\nis_component_build = false\nis_debug = false\npdf_enable_v8 = false\npdf_enable_xfa = false\npdf_is_standalone = true\npdf_use_partition_alloc = false\ntarget_cpu = \"x64\"\ntarget_os = \"mac\"\ntreat_warnings_as_errors = false\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/cpp/fpdf_deleters.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_DELETERS_H_\n#define PUBLIC_CPP_FPDF_DELETERS_H_\n\n#include \"../fpdf_annot.h\"\n#include \"../fpdf_dataavail.h\"\n#include \"../fpdf_edit.h\"\n#include \"../fpdf_formfill.h\"\n#include \"../fpdf_javascript.h\"\n#include \"../fpdf_structtree.h\"\n#include \"../fpdf_text.h\"\n#include \"../fpdf_transformpage.h\"\n#include \"../fpdfview.h\"\n\n// Custom deleters for using FPDF_* types with std::unique_ptr<>.\n\nstruct FPDFAnnotationDeleter {\n  inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); }\n};\n\nstruct FPDFAvailDeleter {\n  inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); }\n};\n\nstruct FPDFBitmapDeleter {\n  inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); }\n};\n\nstruct FPDFClipPathDeleter {\n  inline void operator()(FPDF_CLIPPATH clip_path) {\n    FPDF_DestroyClipPath(clip_path);\n  }\n};\n\nstruct FPDFDocumentDeleter {\n  inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); }\n};\n\nstruct FPDFFontDeleter {\n  inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); }\n};\n\nstruct FPDFFormHandleDeleter {\n  inline void operator()(FPDF_FORMHANDLE form) {\n    FPDFDOC_ExitFormFillEnvironment(form);\n  }\n};\n\nstruct FPDFJavaScriptActionDeleter {\n  inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) {\n    FPDFDoc_CloseJavaScriptAction(javascript);\n  }\n};\n\nstruct FPDFPageDeleter {\n  inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); }\n};\n\nstruct FPDFPageLinkDeleter {\n  inline void operator()(FPDF_PAGELINK pagelink) {\n    FPDFLink_CloseWebLinks(pagelink);\n  }\n};\n\nstruct FPDFPageObjectDeleter {\n  inline void operator()(FPDF_PAGEOBJECT object) {\n    FPDFPageObj_Destroy(object);\n  }\n};\n\nstruct FPDFStructTreeDeleter {\n  inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); }\n};\n\nstruct FPDFTextFindDeleter {\n  inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); }\n};\n\nstruct FPDFTextPageDeleter {\n  inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); }\n};\n\n#endif  // PUBLIC_CPP_FPDF_DELETERS_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/cpp/fpdf_scopers.h",
    "content": "// Copyright 2018 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_SCOPERS_H_\n#define PUBLIC_CPP_FPDF_SCOPERS_H_\n\n#include <memory>\n#include <type_traits>\n\n#include \"fpdf_deleters.h\"\n\n// Versions of FPDF types that clean up the object at scope exit.\n\nusing ScopedFPDFAnnotation =\n    std::unique_ptr<std::remove_pointer<FPDF_ANNOTATION>::type,\n                    FPDFAnnotationDeleter>;\n\nusing ScopedFPDFAvail =\n    std::unique_ptr<std::remove_pointer<FPDF_AVAIL>::type, FPDFAvailDeleter>;\n\nusing ScopedFPDFBitmap =\n    std::unique_ptr<std::remove_pointer<FPDF_BITMAP>::type, FPDFBitmapDeleter>;\n\nusing ScopedFPDFClipPath =\n    std::unique_ptr<std::remove_pointer<FPDF_CLIPPATH>::type,\n                    FPDFClipPathDeleter>;\n\nusing ScopedFPDFDocument =\n    std::unique_ptr<std::remove_pointer<FPDF_DOCUMENT>::type,\n                    FPDFDocumentDeleter>;\n\nusing ScopedFPDFFont =\n    std::unique_ptr<std::remove_pointer<FPDF_FONT>::type, FPDFFontDeleter>;\n\nusing ScopedFPDFFormHandle =\n    std::unique_ptr<std::remove_pointer<FPDF_FORMHANDLE>::type,\n                    FPDFFormHandleDeleter>;\n\nusing ScopedFPDFJavaScriptAction =\n    std::unique_ptr<std::remove_pointer<FPDF_JAVASCRIPT_ACTION>::type,\n                    FPDFJavaScriptActionDeleter>;\n\nusing ScopedFPDFPage =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGE>::type, FPDFPageDeleter>;\n\nusing ScopedFPDFPageLink =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGELINK>::type,\n                    FPDFPageLinkDeleter>;\n\nusing ScopedFPDFPageObject =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGEOBJECT>::type,\n                    FPDFPageObjectDeleter>;\n\nusing ScopedFPDFStructTree =\n    std::unique_ptr<std::remove_pointer<FPDF_STRUCTTREE>::type,\n                    FPDFStructTreeDeleter>;\n\nusing ScopedFPDFTextFind =\n    std::unique_ptr<std::remove_pointer<FPDF_SCHHANDLE>::type,\n                    FPDFTextFindDeleter>;\n\nusing ScopedFPDFTextPage =\n    std::unique_ptr<std::remove_pointer<FPDF_TEXTPAGE>::type,\n                    FPDFTextPageDeleter>;\n\n#endif  // PUBLIC_CPP_FPDF_SCOPERS_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_annot.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ANNOT_H_\n#define PUBLIC_FPDF_ANNOT_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdf_formfill.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n#define FPDF_ANNOT_UNKNOWN 0\n#define FPDF_ANNOT_TEXT 1\n#define FPDF_ANNOT_LINK 2\n#define FPDF_ANNOT_FREETEXT 3\n#define FPDF_ANNOT_LINE 4\n#define FPDF_ANNOT_SQUARE 5\n#define FPDF_ANNOT_CIRCLE 6\n#define FPDF_ANNOT_POLYGON 7\n#define FPDF_ANNOT_POLYLINE 8\n#define FPDF_ANNOT_HIGHLIGHT 9\n#define FPDF_ANNOT_UNDERLINE 10\n#define FPDF_ANNOT_SQUIGGLY 11\n#define FPDF_ANNOT_STRIKEOUT 12\n#define FPDF_ANNOT_STAMP 13\n#define FPDF_ANNOT_CARET 14\n#define FPDF_ANNOT_INK 15\n#define FPDF_ANNOT_POPUP 16\n#define FPDF_ANNOT_FILEATTACHMENT 17\n#define FPDF_ANNOT_SOUND 18\n#define FPDF_ANNOT_MOVIE 19\n#define FPDF_ANNOT_WIDGET 20\n#define FPDF_ANNOT_SCREEN 21\n#define FPDF_ANNOT_PRINTERMARK 22\n#define FPDF_ANNOT_TRAPNET 23\n#define FPDF_ANNOT_WATERMARK 24\n#define FPDF_ANNOT_THREED 25\n#define FPDF_ANNOT_RICHMEDIA 26\n#define FPDF_ANNOT_XFAWIDGET 27\n#define FPDF_ANNOT_REDACT 28\n\n// Refer to PDF Reference (6th edition) table 8.16 for all annotation flags.\n#define FPDF_ANNOT_FLAG_NONE 0\n#define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0)\n#define FPDF_ANNOT_FLAG_HIDDEN (1 << 1)\n#define FPDF_ANNOT_FLAG_PRINT (1 << 2)\n#define FPDF_ANNOT_FLAG_NOZOOM (1 << 3)\n#define FPDF_ANNOT_FLAG_NOROTATE (1 << 4)\n#define FPDF_ANNOT_FLAG_NOVIEW (1 << 5)\n#define FPDF_ANNOT_FLAG_READONLY (1 << 6)\n#define FPDF_ANNOT_FLAG_LOCKED (1 << 7)\n#define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8)\n\n#define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0\n#define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1\n#define FPDF_ANNOT_APPEARANCEMODE_DOWN 2\n#define FPDF_ANNOT_APPEARANCEMODE_COUNT 3\n\n// Refer to PDF Reference version 1.7 table 8.70 for field flags common to all\n// interactive form field types.\n#define FPDF_FORMFLAG_NONE 0\n#define FPDF_FORMFLAG_READONLY (1 << 0)\n#define FPDF_FORMFLAG_REQUIRED (1 << 1)\n#define FPDF_FORMFLAG_NOEXPORT (1 << 2)\n\n// Refer to PDF Reference version 1.7 table 8.77 for field flags specific to\n// interactive form text fields.\n#define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12)\n#define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13)\n\n// Refer to PDF Reference version 1.7 table 8.79 for field flags specific to\n// interactive form choice fields.\n#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17)\n#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18)\n#define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21)\n\n// Additional actions type of form field:\n//   K, on key stroke, JavaScript action.\n//   F, on format, JavaScript action.\n//   V, on validate, JavaScript action.\n//   C, on calculate, JavaScript action.\n#define FPDF_ANNOT_AACTION_KEY_STROKE 12\n#define FPDF_ANNOT_AACTION_FORMAT 13\n#define FPDF_ANNOT_AACTION_VALIDATE 14\n#define FPDF_ANNOT_AACTION_CALCULATE 15\n\ntypedef enum FPDFANNOT_COLORTYPE {\n  FPDFANNOT_COLORTYPE_Color = 0,\n  FPDFANNOT_COLORTYPE_InteriorColor\n} FPDFANNOT_COLORTYPE;\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for creation.\n// Currently supported subtypes:\n//    - circle\n//    - fileattachment\n//    - freetext\n//    - highlight\n//    - ink\n//    - link\n//    - popup\n//    - square,\n//    - squiggly\n//    - stamp\n//    - strikeout\n//    - text\n//    - underline\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Create an annotation in |page| of the subtype |subtype|. If the specified\n// subtype is illegal or unsupported, then a new annotation will not be created.\n// Must call FPDFPage_CloseAnnot() when the annotation returned by this\n// function is no longer needed.\n//\n//   page      - handle to a page.\n//   subtype   - the subtype of the new annotation.\n//\n// Returns a handle to the new annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Get the number of annotations in |page|.\n//\n//   page   - handle to a page.\n//\n// Returns the number of annotations in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page);\n\n// Experimental API.\n// Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the\n// annotation returned by this function is no longer needed.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns a handle to the annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,\n                                                            int index);\n\n// Experimental API.\n// Get the index of |annot| in |page|. This is the opposite of\n// FPDFPage_GetAnnot().\n//\n//   page  - handle to the page that the annotation is on.\n//   annot - handle to an annotation.\n//\n// Returns the index of |annot|, or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,\n                                                     FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Close an annotation. Must be called when the annotation returned by\n// FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This\n// function does not remove the annotation from the document.\n//\n//   annot  - handle to an annotation.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Remove the annotation in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,\n                                                         int index);\n\n// Experimental API.\n// Get the subtype of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the annotation subtype.\nFPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV\nFPDFAnnot_GetSubtype(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for object extraction,\n// update, and removal.\n// Currently supported subtypes: ink and stamp.\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Update |obj| in |annot|. |obj| must be in |annot| already and must have\n// been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp\n// annotations are supported by this API. Also note that only path, image, and\n// text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and\n// FPDFImageObj_*().\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that |annot| needs to update.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Add a new InkStroke, represented by an array of points, to the InkList of\n// |annot|. The API creates an InkList if one doesn't already exist in |annot|.\n// This API works only for ink annotations. Please refer to ISO 32000-1:2008\n// spec, section 12.5.6.13.\n//\n//   annot       - handle to an annotation.\n//   points      - pointer to a FS_POINTF array representing input points.\n//   point_count - number of elements in |points| array. This should not exceed\n//                 the maximum value that can be represented by an int32_t).\n//\n// Returns the 0-based index at which the new InkStroke is added in the InkList\n// of the |annot|. Returns -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot,\n                                                     const FS_POINTF* points,\n                                                     size_t point_count);\n\n// Experimental API.\n// Removes an InkList in |annot|.\n// This API works only for ink annotations.\n//\n//   annot  - handle to an annotation.\n//\n// Return true on successful removal of /InkList entry from context of the\n// non-null ink |annot|. Returns false on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add |obj| to |annot|. |obj| must have been created by\n// FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and\n// will be owned by |annot|. Note that an |obj| cannot belong to more than one\n// |annot|. Currently, only ink and stamp annotations are supported by this API.\n// Also note that only path, image, and text objects have APIs for creation.\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that is to be added to |annot|.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Get the total number of objects in |annot|, including path objects, text\n// objects, external objects, image objects, and shading objects.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of objects in |annot|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object.\n//\n// Return a handle to the object, or NULL on failure.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Remove the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object to be removed.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Set the color of an annotation. Fails when called on annotations with\n// appearance streams already defined; instead use\n// FPDFPageObj_Set{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color to be set.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int R,\n                                                       unsigned int G,\n                                                       unsigned int B,\n                                                       unsigned int A);\n\n// Experimental API.\n// Get the color of an annotation. If no color is specified, default to yellow\n// for highlight annotation, black for all else. Fails when called on\n// annotations with appearance streams already defined; instead use\n// FPDFPageObj_Get{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color requested.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int* R,\n                                                       unsigned int* G,\n                                                       unsigned int* B,\n                                                       unsigned int* A);\n\n// Experimental API.\n// Check if the annotation is of a type that has attachment points\n// (i.e. quadpoints). Quadpoints are the vertices of the rectangle that\n// encompasses the texts affected by the annotation. They provide the\n// coordinates in the page where the annotation is attached. Only text markup\n// annotations (i.e. highlight, strikeout, squiggly, and underline) and link\n// annotations have quadpoints.\n//\n//   annot  - handle to an annotation.\n//\n// Returns true if the annotation is of a type that has quadpoints, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Replace the attachment points (i.e. quadpoints) set of an annotation at\n// |quad_index|. This index needs to be within the result of\n// FPDFAnnot_CountAttachmentPoints().\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Append to the list of attachment points (i.e. quadpoints) of an annotation.\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,\n                                 const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Get the number of sets of quadpoints of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of sets of quadpoints, or 0 on failure.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the attachment points (i.e. quadpoints) of an annotation.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - receives the quadpoints; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Set the annotation rectangle defining the location of the annotation. If the\n// annotation's appearance stream is defined and this annotation is of a type\n// without quadpoints, then update the bounding box too if the new rectangle\n// defines a bigger one.\n//\n//   annot  - handle to an annotation.\n//   rect   - the annotation rectangle to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,\n                                                      const FS_RECTF* rect);\n\n// Experimental API.\n// Get the annotation rectangle defining the location of the annotation.\n//\n//   annot  - handle to an annotation.\n//   rect   - receives the rectangle; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,\n                                                      FS_RECTF* rect);\n\n// Experimental API.\n// Get the vertices of a polygon or polyline annotation. |buffer| is an array of\n// points of the annotation. If |length| is less than the returned length, or\n// |annot| or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points if the annotation is of type polygon or\n// polyline, 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetVertices(FPDF_ANNOTATION annot,\n                      FS_POINTF* buffer,\n                      unsigned long length);\n\n// Experimental API.\n// Get the number of paths in the ink list of an ink annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//\n// Returns the number of paths in the ink list if the annotation is of type ink,\n// 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get a path in the ink list of an ink annotation. |buffer| is an array of\n// points of the path. If |length| is less than the returned length, or |annot|\n// or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   path_index - index of the path\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points of the path if the annotation is of type ink, 0\n// otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot,\n                         unsigned long path_index,\n                         FS_POINTF* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Get the starting and ending coordinates of a line annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   start - starting point\n//   end - ending point\n//\n// Returns true if the annotation is of type line, |start| and |end| are not\n// NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,\n                                                      FS_POINTF* start,\n                                                      FS_POINTF* end);\n\n// Experimental API.\n// Set the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if setting the border for |annot| succeeds, false otherwise.\n//\n// If |annot| contains an appearance stream that overrides the border values,\n// then the appearance stream will be removed on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot,\n                                                        float horizontal_radius,\n                                                        float vertical_radius,\n                                                        float border_width);\n\n// Experimental API.\n// Get the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are\n// not NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetBorder(FPDF_ANNOTATION annot,\n                    float* horizontal_radius,\n                    float* vertical_radius,\n                    float* border_width);\n\n// Experimental API.\n// Get the JavaScript of an event of the annotation's additional actions.\n// |buffer| is only modified if |buflen| is large enough to hold the whole\n// JavaScript string. If |buflen| is smaller, the total size of the JavaScript\n// is still returned, but nothing is copied.  If there is no JavaScript for\n// |event| in |annot|, an empty string is written to |buf| and 2 is returned,\n// denoting the size of the null terminator in the buffer.  On other errors,\n// nothing is written to |buffer| and 0 is returned.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    event       -   event type, one of the FPDF_ANNOT_AACTION_* values.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes, including the 2-byte\n// null terminator.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle,\n                                            FPDF_ANNOTATION annot,\n                                            int event,\n                                            FPDF_WCHAR* buffer,\n                                            unsigned long buflen);\n\n// Experimental API.\n// Check if |annot|'s dictionary has |key| as a key.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,\n                                                     FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in |annot|'s dictionary.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in |annot|'s dictionary,\n// overwriting the existing value if any. The value type would be\n// FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the dictionary entry to be set, encoded in UTF-8.\n//   value  - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in |annot|'s dictionary. |buffer|\n// is only modified if |buflen| is longer than the length of contents. Note that\n// if |key| does not exist in the dictionary or if |key|'s corresponding value\n// in the dictionary is not a string (i.e. the value is not of type\n// FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied\n// to |buffer| and the return value would be 2. On other errors, nothing would\n// be added to |buffer| and the return value would be 0.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   buffer - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Get the float value corresponding to |key| in |annot|'s dictionary. Writes\n// value to |value| and returns True if |key| exists in the dictionary and\n// |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False\n// otherwise.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   value  - receives the value, must not be NULL.\n//\n// Returns True if value found, False otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         float* value);\n\n// Experimental API.\n// Set the AP (appearance string) in |annot|'s dictionary for a given\n// |appearanceMode|.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   value          - the string value to be set, encoded in UTF-16LE. If\n//                    nullptr is passed, the AP is cleared for that mode. If the\n//                    mode is Normal, APs for all modes are cleared.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the AP (appearance string) from |annot|'s dictionary for a given\n// |appearanceMode|.\n// |buffer| is only modified if |buflen| is large enough to hold the whole AP\n// string. If |buflen| is smaller, the total size of the AP is still returned,\n// but nothing is copied.\n// If there is no appearance stream for |annot| in |appearanceMode|, an empty\n// string is written to |buf| and 2 is returned.\n// On other errors, nothing is written to |buffer| and 0 is returned.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   buffer         - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen         - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WCHAR* buffer,\n                unsigned long buflen);\n\n// Experimental API.\n// Get the annotation corresponding to |key| in |annot|'s dictionary. Common\n// keys for linking annotations include \"IRT\" and \"Popup\". Must call\n// FPDFPage_CloseAnnot() when the annotation returned by this function is no\n// longer needed.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//\n// Returns a handle to the linked annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//   annot    - handle to an annotation.\n//\n// Returns the annotation flags.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the |annot|'s flags to be of the value |flags|.\n//\n//   annot      - handle to an annotation.\n//   flags      - the flag values to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,\n                                                       int flags);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the annotation flags specific to interactive forms.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Sets the form field flags for an interactive form annotation.\n//\n//   handle       -   the handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//   annot        -   handle to an interactive form annotation.\n//   flags        -   the form field flags to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot,\n                            int flags);\n\n// Experimental API.\n// Retrieves an interactive form annotation whose rectangle contains a given\n// point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned\n// is no longer needed.\n//\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    page        -   handle to the page, returned by FPDF_LoadPage function.\n//    point       -   position in PDF \"user space\".\n//\n// Returns the interactive form annotation whose rectangle contains the given\n// coordinates on the page. If there is no such annotation, return NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                              FPDF_PAGE page,\n                              const FS_POINTF* point);\n\n// Experimental API.\n// Gets the name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the name string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,\n                           FPDF_ANNOTATION annot,\n                           FPDF_WCHAR* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Gets the alternate name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the alternate name string, encoded in\n//                    UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle,\n                                    FPDF_ANNOTATION annot,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen);\n\n// Experimental API.\n// Gets the form field type of |annot|, which is an interactive form annotation.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on\n// success. Returns -1 on error.\n// See field types in fpdf_formfill.h.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the value of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,\n                            FPDF_ANNOTATION annot,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen);\n\n// Experimental API.\n// Get the number of options in the |annot|'s \"Opt\" dictionary. Intended for\n// use with listbox and combobox widget annotations.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns the number of options in \"Opt\" dictionary on success. Return value\n// will be -1 if annotation does not have an \"Opt\" dictionary or other error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the string value for the label of the option at |index| in |annot|'s\n// \"Opt\" dictionary. Intended for use with listbox and combobox widget\n// annotations. |buffer| is only modified if |buflen| is longer than the length\n// of contents. If index is out of range or in case of other error, nothing\n// will be added to |buffer| and the return value will be 0. Note that\n// return value of empty string is 2 for \"\\0\\0\".\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array\n//   buffer  - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen  - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\n// If |annot| does not have an \"Opt\" array, |index| is out of range or if any\n// other error occurs, returns 0.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,\n                         FPDF_ANNOTATION annot,\n                         int index,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Determine whether or not the option at |index| in |annot|'s \"Opt\" dictionary\n// is selected. Intended for use with listbox and combobox widget annotations.\n//\n//   handle  - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array.\n//\n// Returns true if the option at |index| in |annot|'s \"Opt\" dictionary is\n// selected, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,\n                           FPDF_ANNOTATION annot,\n                           int index);\n\n// Experimental API.\n// Get the float value of the font size for an |annot| with variable text.\n// If 0, the font is to be auto-sized: its size is computed as a function of\n// the height of the annotation rectangle.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   value   - Required. Float which will be set to font size on success.\n//\n// Returns true if the font size was set in |value|, false on error or if\n// |value| not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,\n                      FPDF_ANNOTATION annot,\n                      float* value);\n\n// Experimental API.\n// Set the text color of an annotation.\n//\n//   handle   - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R        - the red component for the text color.\n//   G        - the green component for the text color.\n//   B        - the blue component for the text color.\n//\n// Returns true if successful.\n//\n// Currently supported subtypes: freetext.\n// The range for the color components is 0 to 255.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int R,\n                       unsigned int G,\n                       unsigned int B);\n\n// Experimental API.\n// Get the RGB value of the font color for an |annot| with variable text.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//\n// Returns true if the font color was set, false on error or if the font\n// color was not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int* R,\n                       unsigned int* G,\n                       unsigned int* B);\n\n// Experimental API.\n// Determine if |annot| is a form widget that is checked. Intended for use with\n// checkbox and radio button widgets.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns true if |annot| is a form widget and is checked, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,\n                                                        FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the list of focusable annotation subtypes. Annotations of subtype\n// FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API\n// will override the existing subtypes.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - list of annotation subtype which can be tabbed over.\n//   count    - total number of annotation subtype in list.\n// Returns true if list of annotation subtype is set successfully, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               const FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Get the count of focusable annotation subtypes as set by host\n// for a |hHandle|.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n// Returns the count of focusable annotation subtypes or -1 on error.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Get the list of focusable annotation subtype as set by host.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - receives the list of annotation subtype which can be tabbed\n//              over. Caller must have allocated |subtypes| more than or\n//              equal to the count obtained from\n//              FPDFAnnot_GetFocusableSubtypesCount() API.\n//   count    - size of |subtypes|.\n// Returns true on success and set list of annotation subtype to |subtypes|,\n// false otherwise.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Gets FPDF_LINK object for |annot|. Intended to use for link annotations.\n//\n//   annot   - handle to an annotation.\n//\n// Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure,\n// if the input annot is NULL or input annot's subtype is not link.\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the count of annotations in the |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns number of controls in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the index of |annot| in |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns index of a given |annot| in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the export value of |annot| which is an interactive form annotation.\n// Intended for use with radio button and checkbox widget annotations.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value\n// will be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle,\n                                  FPDF_ANNOTATION annot,\n                                  FPDF_WCHAR* buffer,\n                                  unsigned long buflen);\n\n// Experimental API.\n// Add a URI action to |annot|, overwriting the existing action, if any.\n//\n//   annot  - handle to a link annotation.\n//   uri    - the URI to be set, encoded in 7-bit ASCII.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot,\n                                                     const char* uri);\n\n// Experimental API.\n// Get the attachment from |annot|.\n//\n//   annot - handle to a file annotation.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add an embedded file with |name| to |annot|.\n//\n//   annot    - handle to a file annotation.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ANNOT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_attachment.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ATTACHMENT_H_\n#define PUBLIC_FPDF_ATTACHMENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of embedded files in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of embedded files in |document|.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Add an embedded file with |name| in |document|. If |name| is empty, or if\n// |name| is the name of a existing embedded file in |document|, or if\n// |document|'s embedded file name tree is too deep (i.e. |document| has too\n// many embedded files already), then a new attachment will not be added.\n//\n//   document - handle to a document.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name);\n\n// Experimental API.\n// Get the embedded attachment at |index| in |document|. Note that the returned\n// attachment handle is only valid while |document| is open.\n//\n//   document - handle to a document.\n//   index    - the index of the requested embedded file.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Delete the embedded attachment at |index| in |document|. Note that this does\n// not remove the attachment data from the PDF file; it simply removes the\n// file's entry in the embedded files name tree so that it does not appear in\n// the attachment list. This behavior may change in the future.\n//\n//   document - handle to a document.\n//   index    - the index of the embedded file to be deleted.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Get the name of the |attachment| file. |buffer| is only modified if |buflen|\n// is longer than the length of the file name. On errors, |buffer| is unmodified\n// and the returned length is 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the file name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetName(FPDF_ATTACHMENT attachment,\n                       FPDF_WCHAR* buffer,\n                       unsigned long buflen);\n\n// Experimental API.\n// Check if the params dictionary of |attachment| has |key| as a key.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in the params dictionary of\n// the embedded |attachment|.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|, overwriting the existing value if any. The value\n// type should be FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the dictionary entry, encoded in UTF-8.\n//   value      - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|. |buffer| is only modified if |buflen| is longer\n// than the length of the string value. Note that if |key| does not exist in the\n// dictionary or if |key|'s corresponding value in the dictionary is not a\n// string (i.e. the value is not of type FPDF_OBJECT_STRING or\n// FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the\n// return value would be 2. On other errors, nothing would be added to |buffer|\n// and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the requested string value, encoded in UTF-8.\n//   buffer     - buffer for holding the string value encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the dictionary value string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WCHAR* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Set the file data of |attachment|, overwriting the existing file data if any.\n// The creation date and checksum will be updated, while all other dictionary\n// entries will be deleted. Note that only contents with |len| smaller than\n// INT_MAX is supported.\n//\n//   attachment - handle to an attachment.\n//   contents   - buffer holding the file data to write to |attachment|.\n//   len        - length of file data in bytes.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,\n                       FPDF_DOCUMENT document,\n                       const void* contents,\n                       unsigned long len);\n\n// Experimental API.\n// Get the file data of |attachment|.\n// When the attachment file data is readable, true is returned, and |out_buflen|\n// is updated to indicate the file data size. |buffer| is only modified if\n// |buflen| is non-null and long enough to contain the entire file data. Callers\n// must check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data.\n//\n// Otherwise, when the attachment file data is unreadable or when |out_buflen|\n// is null, false is returned and |buffer| and |out_buflen| remain unmodified.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file data from |attachment|.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to the variable that will receive the minimum buffer\n//                size to contain the file data of |attachment|.\n//\n// Returns true on success, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,\n                       void* buffer,\n                       unsigned long buflen,\n                       unsigned long* out_buflen);\n\n// Experimental API.\n// Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is\n// only modified if |buflen| is longer than the length of the MIME type string.\n// If the Subtype is not found or if there is no file stream, an empty string\n// would be copied to |buffer| and the return value would be 2. On other errors,\n// nothing would be added to |buffer| and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the MIME type string encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the MIME type string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment,\n                          FPDF_WCHAR* buffer,\n                          unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ATTACHMENT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_catalog.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_CATALOG_H_\n#define PUBLIC_FPDF_CATALOG_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n//\n// Determine if |document| represents a tagged PDF.\n//\n// For the definition of tagged PDF, See (see 10.7 \"Tagged PDF\" in PDF\n// Reference 1.7).\n//\n//   document - handle to a document.\n//\n// Returns |true| iff |document| is a tagged PDF.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_IsTagged(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Gets the language of |document| from the catalog's /Lang entry.\n//\n//   document - handle to a document.\n//   buffer   - a buffer for the language string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the language string, including the\n// trailing NUL character. The number of bytes is returned regardless of the\n// |buffer| and |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE\n// encoding. The string is terminated by a UTF16 NUL character. If\n// |buflen| is less than the required length, or |buffer| is NULL,\n// |buffer| will not be modified.\n//\n// If |document| has no /Lang entry, an empty string is written to |buffer| and\n// 2 is returned. On error, nothing is written to |buffer| and 0 is returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFCatalog_GetLanguage(FPDF_DOCUMENT document,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen);\n\n// Experimental API.\n// Sets the language of |document| to |language|.\n//\n// document - handle to a document.\n// language - the language to set to.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_CATALOG_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_dataavail.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DATAAVAIL_H_\n#define PUBLIC_FPDF_DATAAVAIL_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#define PDF_LINEARIZATION_UNKNOWN -1\n#define PDF_NOT_LINEARIZED 0\n#define PDF_LINEARIZED 1\n\n#define PDF_DATA_ERROR -1\n#define PDF_DATA_NOTAVAIL 0\n#define PDF_DATA_AVAIL 1\n\n#define PDF_FORM_ERROR -1\n#define PDF_FORM_NOTAVAIL 0\n#define PDF_FORM_AVAIL 1\n#define PDF_FORM_NOTEXIST 2\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Interface for checking whether sections of the file are available.\ntypedef struct _FX_FILEAVAIL {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Reports if the specified data section is currently available. A section is\n  // available if all bytes in the section are available.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the data section in the file.\n  //   size   - the size of the data section.\n  //\n  // Returns true if the specified data section at |offset| of |size|\n  // is available.\n  FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis,\n                           size_t offset,\n                           size_t size);\n} FX_FILEAVAIL;\n\n// Create a document availability provider.\n//\n//   file_avail - pointer to file availability interface.\n//   file       - pointer to a file access interface.\n//\n// Returns a handle to the document availability provider, or NULL on error.\n//\n// FPDFAvail_Destroy() must be called when done with the availability provider.\nFPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,\n                                                      FPDF_FILEACCESS* file);\n\n// Destroy the |avail| document availability provider.\n//\n//   avail - handle to document availability provider to be destroyed.\nFPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail);\n\n// Download hints interface. Used to receive hints for further downloading.\ntypedef struct _FX_DOWNLOADHINTS {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Add a section to be downloaded.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the hint reported to be downloaded.\n  //   size   - the size of the hint reported to be downloaded.\n  //\n  // The |offset| and |size| of the section may not be unique. Part of the\n  // section might be already available. The download manager must deal with\n  // overlapping sections.\n  void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis,\n                     size_t offset,\n                     size_t size);\n} FX_DOWNLOADHINTS;\n\n// Checks if the document is ready for loading, if not, gets download hints.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// Applications should call this function whenever new data arrives, and process\n// all the generated download hints, if any, until the function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|.\n// if hints is nullptr, the function just check current document availability.\n//\n// Once all data is available, call FPDFAvail_GetDocument() to get a document\n// handle.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,\n                                                   FX_DOWNLOADHINTS* hints);\n\n// Get document from the availability provider.\n//\n//   avail    - handle to document availability provider.\n//   password - password for decrypting the PDF file. Optional.\n//\n// Returns a handle to the document.\n//\n// When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to\n// retrieve the document handle.\n// See the comments for FPDF_LoadDocument() regarding the encoding for\n// |password|.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password);\n\n// Get the page number for the first available page in a linearized PDF.\n//\n//   doc - document handle.\n//\n// Returns the zero-based index for the first available page.\n//\n// For most linearized PDFs, the first available page will be the first page,\n// however, some PDFs might make another page the first available page.\n// For non-linearized PDFs, this function will always return zero.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc);\n\n// Check if |page_index| is ready for loading, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail      - handle to document availability provider.\n//   page_index - index number of the page. Zero for the first page.\n//   hints      - pointer to a download hints interface. Populated if\n//                |page_index| is not available.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// Applications should call this function whenever new data arrives and process\n// all the generated download |hints|, if any, until this function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page\n// loading.\n// if hints is nullptr, the function just check current availability of\n// specified page.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,\n                                                    int page_index,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check if form data is ready for initialization, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface. Populated if form is not\n//           ready for initialization.\n//\n// Returns one of:\n//   PDF_FORM_ERROR: A common eror, in general incorrect parameters.\n//   PDF_FORM_NOTAVAIL: Data not available.\n//   PDF_FORM_AVAIL: Data available.\n//   PDF_FORM_NOTEXIST: No form data.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// The application should call this function whenever new data arrives and\n// process all the generated download |hints|, if any, until the function\n// |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|.\n// if hints is nullptr, the function just check current form availability.\n//\n// Applications can then perform page loading. It is recommend to call\n// FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check whether a document is a linearized PDF.\n//\n//   avail - handle to document availability provider.\n//\n// Returns one of:\n//   PDF_LINEARIZED\n//   PDF_NOT_LINEARIZED\n//   PDF_LINEARIZATION_UNKNOWN\n//\n// FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED|\n// when we have 1k  of data. If the files size less than 1k, it returns\n// |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine\n// if the PDF is linearlized.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DATAAVAIL_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_doc.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DOC_H_\n#define PUBLIC_FPDF_DOC_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported action type.\n#define PDFACTION_UNSUPPORTED 0\n// Go to a destination within current document.\n#define PDFACTION_GOTO 1\n// Go to a destination within another document.\n#define PDFACTION_REMOTEGOTO 2\n// URI, including web pages and other Internet resources.\n#define PDFACTION_URI 3\n// Launch an application or open a file.\n#define PDFACTION_LAUNCH 4\n// Go to a destination in an embedded file.\n#define PDFACTION_EMBEDDEDGOTO 5\n\n// View destination fit types. See pdfmark reference v9, page 48.\n#define PDFDEST_VIEW_UNKNOWN_MODE 0\n#define PDFDEST_VIEW_XYZ 1\n#define PDFDEST_VIEW_FIT 2\n#define PDFDEST_VIEW_FITH 3\n#define PDFDEST_VIEW_FITV 4\n#define PDFDEST_VIEW_FITR 5\n#define PDFDEST_VIEW_FITB 6\n#define PDFDEST_VIEW_FITBH 7\n#define PDFDEST_VIEW_FITBV 8\n\n// The file identifier entry type. See section 14.4 \"File Identifiers\" of the\n// ISO 32000-1:2008 spec.\ntypedef enum {\n  FILEIDTYPE_PERMANENT = 0,\n  FILEIDTYPE_CHANGING = 1\n} FPDF_FILEIDTYPE;\n\n// Get the first child of |bookmark|, or the first top-level bookmark item.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark. Pass NULL for the first top\n//              level item.\n//\n// Returns a handle to the first child of |bookmark| or the first top-level\n// bookmark item. NULL if no child or top-level bookmark found.\n// Note that another name for the bookmarks is the document outline, as\n// described in ISO 32000-1:2008, section 12.3.3.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the next sibling of |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark.\n//\n// Returns a handle to the next sibling of |bookmark|, or NULL if this is the\n// last bookmark at this level.\n//\n// Note that the caller is responsible for handling circular bookmark\n// references, as may arise from malformed documents.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the title of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//   buffer   - buffer for the title. May be NULL.\n//   buflen   - the length of the buffer in bytes. May be 0.\n//\n// Returns the number of bytes in the title, including the terminating NUL\n// character. The number of bytes is returned regardless of the |buffer| and\n// |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |buflen| is less than the\n// required length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Experimental API.\n// Get the number of chlidren of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns a signed integer that represents the number of sub-items the given\n// bookmark has. If the value is positive, child items shall be shown by default\n// (open state). If the value is negative, child items shall be hidden by\n// default (closed state). Please refer to PDF 32000-1:2008, Table 153.\n// Returns 0 if the bookmark has no children or is invalid.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark);\n\n// Find the bookmark with |title| in |document|.\n//\n//   document - handle to the document.\n//   title    - the UTF-16LE encoded Unicode title for which to search.\n//\n// Returns the handle to the bookmark, or NULL if |title| can't be found.\n//\n// FPDFBookmark_Find() will always return the first bookmark found even if\n// multiple bookmarks have the same |title|.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title);\n\n// Get the destination associated with |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the destination data, or NULL if no destination is\n// associated with |bookmark|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the action associated with |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the action data, or NULL if no action is associated\n// with |bookmark|.\n// If this function returns a valid handle, it is valid as long as |bookmark| is\n// valid.\n// If this function returns NULL, FPDFBookmark_GetDest() should be called to get\n// the |bookmark| destination data.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV\nFPDFBookmark_GetAction(FPDF_BOOKMARK bookmark);\n\n// Get the type of |action|.\n//\n//   action - handle to the action.\n//\n// Returns one of:\n//   PDFACTION_UNSUPPORTED\n//   PDFACTION_GOTO\n//   PDFACTION_REMOTEGOTO\n//   PDFACTION_URI\n//   PDFACTION_LAUNCH\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action);\n\n// Get the destination of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. |action| must be a |PDFACTION_GOTO| or\n//              |PDFACTION_REMOTEGOTO|.\n//\n// Returns a handle to the destination data, or NULL on error, typically\n// because the arguments were bad or the action was of the wrong type.\n//\n// In the case of |PDFACTION_REMOTEGOTO|, you must first call\n// FPDFAction_GetFilePath(), then load the document at that path, then pass\n// the document handle from that document as |document| to FPDFAction_GetDest().\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document,\n                                                       FPDF_ACTION action);\n\n// Get the file path of |action|.\n//\n//   action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or\n//            |PDFACTION_REMOTEGOTO|.\n//   buffer - a buffer for output the path string. May be NULL.\n//   buflen - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen);\n\n// Get the URI path of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. Must be a |PDFACTION_URI|.\n//   buffer   - a buffer for the path string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the URI path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// The |buffer| may contain badly encoded data. The caller should validate the\n// output. e.g. Check to see if it is UTF-8.\n//\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\n//\n// Historically, the documentation for this API claimed |buffer| is always\n// encoded in 7-bit ASCII, but did not actually enforce it.\n// https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592\n// added that enforcement, but that did not work well for real world PDFs that\n// used UTF-8. As of this writing, this API reverted back to its original\n// behavior prior to commit d609e84cee.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetURIPath(FPDF_DOCUMENT document,\n                      FPDF_ACTION action,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Get the page index of |dest|.\n//\n//   document - handle to the document.\n//   dest     - handle to the destination.\n//\n// Returns the 0-based page index containing |dest|. Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document,\n                                                        FPDF_DEST dest);\n\n// Experimental API.\n// Get the view (fit type) specified by |dest|.\n//\n//   dest         - handle to the destination.\n//   pNumParams   - receives the number of view parameters, which is at most 4.\n//   pParams      - buffer to write the view parameters. Must be at least 4\n//                  FS_FLOATs long.\n// Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if\n// |dest| does not specify a view.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams);\n\n// Get the (x, y, zoom) location of |dest| in the destination page, if the\n// destination is in [page /XYZ x y zoom] syntax.\n//\n//   dest       - handle to the destination.\n//   hasXVal    - out parameter; true if the x value is not null\n//   hasYVal    - out parameter; true if the y value is not null\n//   hasZoomVal - out parameter; true if the zoom value is not null\n//   x          - out parameter; the x coordinate, in page coordinates.\n//   y          - out parameter; the y coordinate, in page coordinates.\n//   zoom       - out parameter; the zoom value.\n// Returns TRUE on successfully reading the /XYZ value.\n//\n// Note the [x, y, zoom] values are only set if the corresponding hasXVal,\n// hasYVal or hasZoomVal flags are true.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDest_GetLocationInPage(FPDF_DEST dest,\n                           FPDF_BOOL* hasXVal,\n                           FPDF_BOOL* hasYVal,\n                           FPDF_BOOL* hasZoomVal,\n                           FS_FLOAT* x,\n                           FS_FLOAT* y,\n                           FS_FLOAT* zoom);\n\n// Find a link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns a handle to the link, or NULL if no link found at the given point.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Find the Z-order of link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns the Z-order of the link, or -1 if no link found at the given point.\n// Larger Z-order numbers are closer to the front.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Get destination info for |link|.\n//\n//   document - handle to the document.\n//   link     - handle to the link.\n//\n// Returns a handle to the destination, or NULL if there is no destination\n// associated with the link. In this case, you should call FPDFLink_GetAction()\n// to retrieve the action associated with |link|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document,\n                                                     FPDF_LINK link);\n\n// Get action info for |link|.\n//\n//   link - handle to the link.\n//\n// Returns a handle to the action associated to |link|, or NULL if no action.\n// If this function returns a valid handle, it is valid as long as |link| is\n// valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link);\n\n// Enumerates all the link annotations in |page|.\n//\n//   page       - handle to the page.\n//   start_pos  - the start position, should initially be 0 and is updated with\n//                the next start position on return.\n//   link_annot - the link handle for |startPos|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page,\n                                                       int* start_pos,\n                                                       FPDF_LINK* link_annot);\n\n// Experimental API.\n// Gets FPDF_ANNOTATION object for |link_annot|.\n//\n//   page       - handle to the page in which FPDF_LINK object is present.\n//   link_annot - handle to link annotation.\n//\n// Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure,\n// if the input link annot or page is NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot);\n\n// Get the rectangle for |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//   rect       - the annotation rectangle.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot,\n                                                          FS_RECTF* rect);\n\n// Get the count of quadrilateral points to the |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//\n// Returns the count of quadrilateral points.\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot);\n\n// Get the quadrilateral points for the specified |quad_index| in |link_annot|.\n//\n//   link_annot  - handle to the link annotation.\n//   quad_index  - the specified quad point index.\n//   quad_points - receives the quadrilateral points.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetQuadPoints(FPDF_LINK link_annot,\n                       int quad_index,\n                       FS_QUADPOINTSF* quad_points);\n\n// Experimental API\n// Gets an additional-action from |page|.\n//\n//   page      - handle to the page, as returned by FPDF_LoadPage().\n//   aa_type   - the type of the page object's addtional-action, defined\n//               in public/fpdf_formfill.h\n//\n//   Returns the handle to the action data, or NULL if there is no\n//   additional-action of type |aa_type|.\n//   If this function returns a valid handle, it is valid as long as |page| is\n//   valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page,\n                                                          int aa_type);\n\n// Experimental API.\n// Get the file identifer defined in the trailer of |document|.\n//\n//   document - handle to the document.\n//   id_type  - the file identifier type to retrieve.\n//   buffer   - a buffer for the file identifier. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file identifier, including the NUL\n// terminator.\n//\n// The |buffer| is always a byte string. The |buffer| is followed by a NUL\n// terminator.  If |buflen| is less than the returned length, or |buffer| is\n// NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetFileIdentifier(FPDF_DOCUMENT document,\n                       FPDF_FILEIDTYPE id_type,\n                       void* buffer,\n                       unsigned long buflen);\n\n// Get meta-data |tag| content from |document|.\n//\n//   document - handle to the document.\n//   tag      - the tag to retrieve. The tag can be one of:\n//                Title, Author, Subject, Keywords, Creator, Producer,\n//                CreationDate, or ModDate.\n//              For detailed explanations of these tags and their respective\n//              values, please refer to PDF Reference 1.6, section 10.2.1,\n//              'Document Information Dictionary'.\n//   buffer   - a buffer for the tag. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the tag, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// For linearized files, FPDFAvail_IsFormAvail must be called before this, and\n// it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there\n// is no guarantee the metadata has been loaded.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document,\n                                                         FPDF_BYTESTRING tag,\n                                                         void* buffer,\n                                                         unsigned long buflen);\n\n// Get the page label for |page_index| from |document|.\n//\n//   document    - handle to the document.\n//   page_index  - the 0-based index of the page.\n//   buffer      - a buffer for the page label. May be NULL.\n//   buflen      - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the page label, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetPageLabel(FPDF_DOCUMENT document,\n                  int page_index,\n                  void* buffer,\n                  unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DOC_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_edit.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EDIT_H_\n#define PUBLIC_FPDF_EDIT_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n#define FPDF_ARGB(a, r, g, b)                                      \\\n  ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \\\n              (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24)))\n#define FPDF_GetBValue(argb) ((uint8_t)(argb))\n#define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8))\n#define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16))\n#define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24))\n\n// Refer to PDF Reference version 1.7 table 4.12 for all color space families.\n#define FPDF_COLORSPACE_UNKNOWN 0\n#define FPDF_COLORSPACE_DEVICEGRAY 1\n#define FPDF_COLORSPACE_DEVICERGB 2\n#define FPDF_COLORSPACE_DEVICECMYK 3\n#define FPDF_COLORSPACE_CALGRAY 4\n#define FPDF_COLORSPACE_CALRGB 5\n#define FPDF_COLORSPACE_LAB 6\n#define FPDF_COLORSPACE_ICCBASED 7\n#define FPDF_COLORSPACE_SEPARATION 8\n#define FPDF_COLORSPACE_DEVICEN 9\n#define FPDF_COLORSPACE_INDEXED 10\n#define FPDF_COLORSPACE_PATTERN 11\n\n// The page object constants.\n#define FPDF_PAGEOBJ_UNKNOWN 0\n#define FPDF_PAGEOBJ_TEXT 1\n#define FPDF_PAGEOBJ_PATH 2\n#define FPDF_PAGEOBJ_IMAGE 3\n#define FPDF_PAGEOBJ_SHADING 4\n#define FPDF_PAGEOBJ_FORM 5\n\n// The path segment constants.\n#define FPDF_SEGMENT_UNKNOWN -1\n#define FPDF_SEGMENT_LINETO 0\n#define FPDF_SEGMENT_BEZIERTO 1\n#define FPDF_SEGMENT_MOVETO 2\n\n#define FPDF_FILLMODE_NONE 0\n#define FPDF_FILLMODE_ALTERNATE 1\n#define FPDF_FILLMODE_WINDING 2\n\n#define FPDF_FONT_TYPE1 1\n#define FPDF_FONT_TRUETYPE 2\n\n#define FPDF_LINECAP_BUTT 0\n#define FPDF_LINECAP_ROUND 1\n#define FPDF_LINECAP_PROJECTING_SQUARE 2\n\n#define FPDF_LINEJOIN_MITER 0\n#define FPDF_LINEJOIN_ROUND 1\n#define FPDF_LINEJOIN_BEVEL 2\n\n// See FPDF_SetPrintMode() for descriptions.\n#define FPDF_PRINTMODE_EMF 0\n#define FPDF_PRINTMODE_TEXTONLY 1\n#define FPDF_PRINTMODE_POSTSCRIPT2 2\n#define FPDF_PRINTMODE_POSTSCRIPT3 3\n#define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4\n#define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5\n#define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8\n\ntypedef struct FPDF_IMAGEOBJ_METADATA {\n  // The image width in pixels.\n  unsigned int width;\n  // The image height in pixels.\n  unsigned int height;\n  // The image's horizontal pixel-per-inch.\n  float horizontal_dpi;\n  // The image's vertical pixel-per-inch.\n  float vertical_dpi;\n  // The number of bits used to represent each pixel.\n  unsigned int bits_per_pixel;\n  // The image's colorspace. See above for the list of FPDF_COLORSPACE_*.\n  int colorspace;\n  // The image's marked content ID. Useful for pairing with associated alt-text.\n  // A value of -1 indicates no ID.\n  int marked_content_id;\n} FPDF_IMAGEOBJ_METADATA;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Create a new PDF document.\n//\n// Returns a handle to a new document, or NULL on failure.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument();\n\n// Create a new PDF page.\n//\n//   document   - handle to document.\n//   page_index - suggested 0-based index of the page to create. If it is larger\n//                than document's current last index(L), the created page index\n//                is the next available index -- L+1.\n//   width      - the page width in points.\n//   height     - the page height in points.\n//\n// Returns the handle to the new page or NULL on failure.\n//\n// The page should be closed with FPDF_ClosePage() when finished as\n// with any other page in the document.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,\n                                                 int page_index,\n                                                 double width,\n                                                 double height);\n\n// Delete the page at |page_index|.\n//\n//   document   - handle to document.\n//   page_index - the index of the page to delete.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,\n                                               int page_index);\n\n// Experimental API.\n// Move the given pages to a new index position.\n//\n//  page_indices     - the ordered list of pages to move. No duplicates allowed.\n//  page_indices_len - the number of elements in |page_indices|\n//  dest_page_index  - the new index position to which the pages in\n//                     |page_indices| are moved.\n//\n// Returns TRUE on success. If it returns FALSE, the document may be left in an\n// indeterminate state.\n//\n// Example: The PDF document starts out with pages [A, B, C, D], with indices\n// [0, 1, 2, 3].\n//\n// >  Move(doc, [3, 2], 2, 1); // returns true\n// >  // The document has pages [A, D, C, B].\n// >\n// >  Move(doc, [0, 4, 3], 3, 1); // returns false\n// >  // Returned false because index 4 is out of range.\n// >\n// >  Move(doc, [0, 3, 1], 3, 2); // returns false\n// >  // Returned false because index 2 is out of range for 3 page indices.\n// >\n// >  Move(doc, [2, 2], 2, 0); // returns false\n// >  // Returned false because [2, 2] contains duplicates.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_MovePages(FPDF_DOCUMENT document,\n               const int* page_indices,\n               unsigned long page_indices_len,\n               int dest_page_index);\n\n// Get the rotation of |page|.\n//\n//   page - handle to a page\n//\n// Returns one of the following indicating the page rotation:\n//   0 - No rotation.\n//   1 - Rotated 90 degrees clockwise.\n//   2 - Rotated 180 degrees clockwise.\n//   3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page);\n\n// Set rotation for |page|.\n//\n//   page   - handle to a page.\n//   rotate - the rotation value, one of:\n//              0 - No rotation.\n//              1 - Rotated 90 degrees clockwise.\n//              2 - Rotated 180 degrees clockwise.\n//              3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate);\n\n// Insert |page_object| into |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object. The |page_object| will be\n//                 automatically freed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Insert |page_object| into |page| at the specified |index|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object as previously obtained by\n//                 FPDFPageObj_CreateNew{Path|Rect}() or\n//                 FPDFPageObj_New{Text|Image}Obj(). Ownership of the object\n//                 is transferred back to PDFium.\n//   index       - the index position to insert the object at. If index equals\n//                 the current object count, the object will be appended to the\n//                 end. If index is greater than the object count, the function\n//                 will fail and return false.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_InsertObjectAtIndex(FPDF_PAGE page,\n                             FPDF_PAGEOBJECT page_object,\n                             size_t index);\n\n// Experimental API.\n// Remove |page_object| from |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object to be removed.\n//\n// Returns TRUE on success.\n//\n// Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free\n// it.\n// Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all\n// FPDF_TEXTPAGE handles for |page| are no longer valid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Get number of page objects inside |page|.\n//\n//   page - handle to a page.\n//\n// Returns the number of objects in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page);\n\n// Get object in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of a page object.\n//\n// Returns the handle to the page object, or NULL on failed.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,\n                                                             int index);\n\n// Checks if |page| contains transparency.\n//\n//   page - handle to a page.\n//\n// Returns TRUE if |page| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page);\n\n// Generate the content of |page|.\n//\n//   page - handle to a page.\n//\n// Returns TRUE on success.\n//\n// Before you save the page to a file, or reload the page, you must call\n// |FPDFPage_GenerateContent| or any changes to |page| will be lost.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page);\n\n// Destroy |page_object| by releasing its resources. |page_object| must have\n// been created by FPDFPageObj_CreateNew{Path|Rect}() or\n// FPDFPageObj_New{Text|Image}Obj(). This function must be called on\n// newly-created objects if they are not added to a page through\n// FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject().\n//\n//   page_object - handle to a page object.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object);\n\n// Checks if |page_object| contains transparency.\n//\n//   page_object - handle to a page object.\n//\n// Returns TRUE if |page_object| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object);\n\n// Get type of |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on\n// error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Gets active state for |page_object| within page.\n//\n//   page_object - handle to a page object.\n//   active      - pointer to variable that will receive if the page object is\n//                 active. This is a required parameter. Not filled if FALSE\n//                 is returned.\n//\n// For page objects where |active| is filled with FALSE, the |page_object| is\n// treated as if it wasn't in the document even though it is still held\n// internally.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active);\n\n// Experimental API.\n// Sets if |page_object| is active within page.\n//\n//   page_object - handle to a page object.\n//   active      - a boolean specifying if the object is active.\n//\n// Returns TRUE on success.\n//\n// Page objects all start in the active state by default, and remain in that\n// state unless this function is called.\n//\n// When |active| is false, this makes the |page_object| be treated as if it\n// wasn't in the document even though it is still held internally.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active);\n\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   a           - matrix value.\n//   b           - matrix value.\n//   c           - matrix value.\n//   d           - matrix value.\n//   e           - matrix value.\n//   f           - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page_object|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,\n                      double a,\n                      double b,\n                      double c,\n                      double d,\n                      double e,\n                      double f);\n\n// Experimental API.\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   matrix      - the transform matrix.\n//\n// Returns TRUE on success.\n//\n// This can be used to scale, rotate, shear and translate the |page_object|.\n// It is an improved version of FPDFPageObj_Transform() that does not do\n// unnecessary double to float conversions, and only uses 1 parameter for the\n// matrix. It also returns whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Experimental API.\n// Get the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct to receive the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and used to scale, rotate, shear and translate the page object.\n//\n// For page objects outside form objects, the matrix values are relative to the\n// page that contains it.\n// For page objects inside form objects, the matrix values are relative to the\n// form that contains it.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix);\n\n// Experimental API.\n// Set the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct with the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the page object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Transform all annotations in |page|.\n//\n//   page - handle to a page.\n//   a    - matrix value.\n//   b    - matrix value.\n//   c    - matrix value.\n//   d    - matrix value.\n//   e    - matrix value.\n//   f    - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page| annotations.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,\n                                                        double a,\n                                                        double b,\n                                                        double c,\n                                                        double d,\n                                                        double e,\n                                                        double f);\n\n// Create a new image object.\n//\n//   document - handle to a document.\n//\n// Returns a handle to a new image object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewImageObj(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the marked content ID for the object.\n//\n//   page_object - handle to a page object.\n//\n// Returns the page object's marked content ID, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of content marks in |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns the number of content marks in |page_object|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get content mark in |page_object| at |index|.\n//\n//   page_object - handle to a page object.\n//   index       - the index of a page object.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index);\n\n// Experimental API.\n// Add a new content mark to a |page_object|.\n//\n//   page_object - handle to a page object.\n//   name        - the name (tag) of the mark.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name);\n\n// Experimental API.\n// Removes a content |mark| from a |page_object|.\n// The mark handle will be invalid after the removal.\n//\n//   page_object - handle to a page object.\n//   mark        - handle to a content mark in that object to remove.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the name of a content mark.\n//\n//   mark       - handle to a content mark.\n//   buffer     - buffer for holding the returned name in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the name.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen,\n                        unsigned long* out_buflen);\n\n// Experimental API.\n// Get the number of key/value pair parameters in |mark|.\n//\n//   mark   - handle to a content mark.\n//\n// Returns the number of key/value pair parameters |mark|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the key of a property in a content mark.\n//\n//   mark       - handle to a content mark.\n//   index      - index of the property.\n//   buffer     - buffer for holding the returned key in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the key.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,\n                            unsigned long index,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen,\n                            unsigned long* out_buflen);\n\n// Experimental API.\n// Get the type of the value of a property in a content mark by key.\n//\n//   mark   - handle to a content mark.\n//   key    - string key of the property.\n//\n// Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as int.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,\n                                 FPDF_BYTESTRING key,\n                                 int* out_value);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as float.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark,\n                                   FPDF_BYTESTRING key,\n                                   float* out_value);\n\n// Experimental API.\n// Get the value of a string property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value in UTF-16LE. This is\n//                only modified if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,\n                                    FPDF_BYTESTRING key,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen,\n                                    unsigned long* out_buflen);\n\n// Experimental API.\n// Get the value of a blob property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value. This is only modified\n//                if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key,\n                                  unsigned char* buffer,\n                                  unsigned long buflen,\n                                  unsigned long* out_buflen);\n\n// Experimental API.\n// Set the value of an int property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - int value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,\n                            FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key,\n                            int value);\n\n// Experimental API.\n// Set the value of a float property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - float value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document,\n                              FPDF_PAGEOBJECT page_object,\n                              FPDF_PAGEOBJECTMARK mark,\n                              FPDF_BYTESTRING key,\n                              float value);\n\n// Experimental API.\n// Set the value of a string property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - string value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,\n                               FPDF_PAGEOBJECT page_object,\n                               FPDF_PAGEOBJECTMARK mark,\n                               FPDF_BYTESTRING key,\n                               FPDF_BYTESTRING value);\n\n// Experimental API.\n// Set the value of a blob property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - pointer to blob value to set.\n//   value_len   - size in bytes of |value|.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,\n                             FPDF_PAGEOBJECT page_object,\n                             FPDF_PAGEOBJECTMARK mark,\n                             FPDF_BYTESTRING key,\n                             const unsigned char* value,\n                             unsigned long value_len);\n\n// Experimental API.\n// Removes a property from a content mark by key.\n//\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,\n                          int count,\n                          FPDF_PAGEOBJECT image_object,\n                          FPDF_FILEACCESS* file_access);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value. This function loads the JPEG image inline, so the image\n// content is copied to the file. This allows |file_access| and its associated\n// data to be deleted after this function returns.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,\n                                int count,\n                                FPDF_PAGEOBJECT image_object,\n                                FPDF_FILEACCESS* file_access);\n\n// TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable.\n//\n// Set the transform matrix of |image_object|.\n//\n//   image_object - handle to an image object.\n//   a            - matrix value.\n//   b            - matrix value.\n//   c            - matrix value.\n//   d            - matrix value.\n//   e            - matrix value.\n//   f            - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |image_object|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,\n                       double a,\n                       double b,\n                       double c,\n                       double d,\n                       double e,\n                       double f);\n\n// Set |bitmap| to |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   bitmap       - handle of the bitmap.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetBitmap(FPDF_PAGE* pages,\n                       int count,\n                       FPDF_PAGEOBJECT image_object,\n                       FPDF_BITMAP bitmap);\n\n// Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only\n// operates on |image_object| and does not take the associated image mask into\n// account. It also ignores the matrix for |image_object|.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   image_object - handle to an image object.\n//\n// Returns the bitmap.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object);\n\n// Experimental API.\n// Get a bitmap rasterization of |image_object| that takes the image mask and\n// image matrix into account. To render correctly, the caller must provide the\n// |document| associated with |image_object|. If there is a |page| associated\n// with |image_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document     - handle to a document associated with |image_object|.\n//   page         - handle to an optional page associated with |image_object|.\n//   image_object - handle to an image object.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                               FPDF_PAGE page,\n                               FPDF_PAGEOBJECT image_object);\n\n// Get the decoded image data of |image_object|. The decoded data is the\n// uncompressed image data, i.e. the raw image data after having all filters\n// applied. |buffer| is only modified if |buflen| is longer than the length of\n// the decoded image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the decoded image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the decoded image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Get the raw image data of |image_object|. The raw data is the image data as\n// stored in the PDF without applying any filters. |buffer| is only modified if\n// |buflen| is longer than the length of the raw image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the raw image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the raw image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Get the number of filters (i.e. decoders) of the image in |image_object|.\n//\n//   image_object - handle to an image object.\n//\n// Returns the number of |image_object|'s filters.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object);\n\n// Get the filter at |index| of |image_object|'s list of filters. Note that the\n// filters need to be applied in order, i.e. the first filter should be applied\n// first, then the second, etc. |buffer| is only modified if |buflen| is longer\n// than the length of the filter string.\n//\n//   image_object - handle to an image object.\n//   index        - the index of the filter requested.\n//   buffer       - buffer for holding filter string, encoded in UTF-8.\n//   buflen       - length of the buffer.\n//\n// Returns the length of the filter string.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,\n                            int index,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Get the image metadata of |image_object|, including dimension, DPI, bits per\n// pixel, and colorspace. If the |image_object| is not an image object or if it\n// does not have an image, then the return value will be false. Otherwise,\n// failure to retrieve any specific parameter would result in its value being 0.\n//\n//   image_object - handle to an image object.\n//   page         - handle to the page that |image_object| is on. Required for\n//                  retrieving the image's bits per pixel and colorspace.\n//   metadata     - receives the image metadata; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,\n                              FPDF_PAGE page,\n                              FPDF_IMAGEOBJ_METADATA* metadata);\n\n// Experimental API.\n// Get the image size in pixels. Faster method to get only image size.\n//\n//   image_object - handle to an image object.\n//   width        - receives the image width in pixels; must not be NULL.\n//   height       - receives the image height in pixels; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object,\n                               unsigned int* width,\n                               unsigned int* height);\n\n// Experimental API.\n// Get ICC profile decoded data of |image_object|. If the |image_object| is not\n// an image object or if it does not have an image, then the return value will\n// be false. It also returns false if the |image_object| has no ICC profile.\n// |buffer| is only modified if ICC profile exists and |buflen| is longer than\n// the length of the ICC profile decoded data.\n//\n//   image_object - handle to an image object; must not be NULL.\n//   page         - handle to the page containing |image_object|; must not be\n//                  NULL. Required for retrieving the image's colorspace.\n//   buffer       - Buffer to receive ICC profile data; may be NULL if querying\n//                  required size via |out_buflen|.\n//   buflen       - Length of the buffer in bytes. Ignored if |buffer| is NULL.\n//   out_buflen   - Pointer to receive the ICC profile data size in bytes; must\n//                  not be NULL. Will be set if this API returns true.\n//\n// Returns true if |out_buflen| is not null and an ICC profile exists for the\n// given |image_object|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object,\n                                      FPDF_PAGE page,\n                                      uint8_t* buffer,\n                                      size_t buflen,\n                                      size_t* out_buflen);\n\n// Create a new path object at an initial position.\n//\n//   x - initial horizontal position.\n//   y - initial vertical position.\n//\n// Returns a handle to a new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,\n                                                                    float y);\n\n// Create a closed path consisting of a rectangle.\n//\n//   x - horizontal position for the left boundary of the rectangle.\n//   y - vertical position for the bottom boundary of the rectangle.\n//   w - width of the rectangle.\n//   h - height of the rectangle.\n//\n// Returns a handle to the new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,\n                                                                    float y,\n                                                                    float w,\n                                                                    float h);\n\n// Get the bounding box of |page_object|.\n//\n// page_object  - handle to a page object.\n// left         - pointer where the left coordinate will be stored\n// bottom       - pointer where the bottom coordinate will be stored\n// right        - pointer where the right coordinate will be stored\n// top          - pointer where the top coordinate will be stored\n//\n// On success, returns TRUE and fills in the 4 coordinates.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,\n                      float* left,\n                      float* bottom,\n                      float* right,\n                      float* top);\n\n// Experimental API.\n// Get the quad points that bounds |page_object|.\n//\n// page_object  - handle to a page object.\n// quad_points  - pointer where the quadrilateral points will be stored.\n//\n// On success, returns TRUE and fills in |quad_points|.\n//\n// Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page\n// object. When the object is rotated by a non-multiple of 90 degrees, this API\n// returns a tighter bound that cannot be represented with just the 4 sides of\n// a rectangle.\n//\n// Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and\n// FPDF_PAGEOBJ_IMAGE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,\n                             FS_QUADPOINTSF* quad_points);\n\n// Set the blend mode of |page_object|.\n//\n// page_object  - handle to a page object.\n// blend_mode   - string containing the blend mode.\n//\n// Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken,\n// Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal,\n// Overlay, Saturation, Screen, SoftLight\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,\n                         FPDF_BYTESTRING blend_mode);\n\n// Set the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's stroke color.\n// G            - the green component for the object's stroke color.\n// B            - the blue component for the object's stroke color.\n// A            - the stroke alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int R,\n                           unsigned int G,\n                           unsigned int B,\n                           unsigned int A);\n\n// Get the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the path stroke color.\n// G            - the green component of the object's stroke color.\n// B            - the blue component of the object's stroke color.\n// A            - the stroke alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int* R,\n                           unsigned int* G,\n                           unsigned int* B,\n                           unsigned int* A);\n\n// Set the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width);\n\n// Get the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width);\n\n// Get the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n//\n// Returns the line join, or -1 on failure.\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object);\n\n// Set the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n// line_join    - line join\n//\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join);\n\n// Get the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line cap, or -1 on failure.\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object);\n\n// Set the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n// line_cap    - line cap\n//\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap);\n\n// Set the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's fill color.\n// G            - the green component for the object's fill color.\n// B            - the blue component for the object's fill color.\n// A            - the fill alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int R,\n                         unsigned int G,\n                         unsigned int B,\n                         unsigned int A);\n\n// Get the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the object's fill color.\n// G            - the green component of the object's fill color.\n// B            - the blue component of the object's fill color.\n// A            - the fill alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int* R,\n                         unsigned int* G,\n                         unsigned int* B,\n                         unsigned int* A);\n\n// Experimental API.\n// Get the line dash |phase| of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - pointer where the dashing phase will be stored.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase);\n\n// Experimental API.\n// Set the line dash phase of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line dash array size or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - pointer where the dashing array will be stored.\n// dash_count - number of elements in |dash_array|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,\n                         float* dash_array,\n                         size_t dash_count);\n\n// Experimental API.\n// Set the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - the dash array.\n// dash_count - number of elements in |dash_array|.\n// phase - the line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,\n                         const float* dash_array,\n                         size_t dash_count,\n                         float phase);\n\n// Get number of segments inside |path|.\n//\n//   path - handle to a path.\n//\n// A segment is a command, created by e.g. FPDFPath_MoveTo(),\n// FPDFPath_LineTo() or FPDFPath_BezierTo().\n//\n// Returns the number of objects in |path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path);\n\n// Get segment in |path| at |index|.\n//\n//   path  - handle to a path.\n//   index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index);\n\n// Get coordinates of |segment|.\n//\n//   segment  - handle to a segment.\n//   x      - the horizontal position of the segment.\n//   y      - the vertical position of the segment.\n//\n// Returns TRUE on success, otherwise |x| and |y| is not set.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y);\n\n// Get type of |segment|.\n//\n//   segment - handle to a segment.\n//\n// Returns one of the FPDF_SEGMENT_* values on success,\n// FPDF_SEGMENT_UNKNOWN on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment);\n\n// Gets if the |segment| closes the current subpath of a given path.\n//\n//   segment - handle to a segment.\n//\n// Returns close flag for non-NULL segment, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment);\n\n// Move a path's current point.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new current point.\n// y      - the vertical position of the new current point.\n//\n// Note that no line will be created between the previous current point and the\n// new one.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a line between the current point and a new point in the path.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new point.\n// y      - the vertical position of the new point.\n//\n// The path's current point is changed to (x, y).\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a cubic Bezier curve to the given path, starting at the current point.\n//\n// path   - the handle to the path object.\n// x1     - the horizontal position of the first Bezier control point.\n// y1     - the vertical position of the first Bezier control point.\n// x2     - the horizontal position of the second Bezier control point.\n// y2     - the vertical position of the second Bezier control point.\n// x3     - the horizontal position of the ending point of the Bezier curve.\n// y3     - the vertical position of the ending point of the Bezier curve.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,\n                                                      float x1,\n                                                      float y1,\n                                                      float x2,\n                                                      float y2,\n                                                      float x3,\n                                                      float y3);\n\n// Close the current subpath of a given path.\n//\n// path   - the handle to the path object.\n//\n// This will add a line between the current point and the initial point of the\n// subpath, thus terminating the current subpath.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path);\n\n// Set the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path should be stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int fillmode,\n                                                         FPDF_BOOL stroke);\n\n// Get the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path is stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int* fillmode,\n                                                         FPDF_BOOL* stroke);\n\n// Create a new text object using one of the standard PDF fonts.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewTextObj(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING font,\n                       float font_size);\n\n// Set the text for a text object. If it had text, it will be replaced.\n//\n// text_object  - handle to the text object.\n// text         - the UTF-16LE encoded string containing the text to be added.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text);\n\n// Experimental API.\n// Set the text using charcodes for a text object. If it had text, it will be\n// replaced.\n//\n// text_object  - handle to the text object.\n// charcodes    - pointer to an array of charcodes to be added.\n// count        - number of elements in |charcodes|.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,\n                      const uint32_t* charcodes,\n                      size_t count);\n\n// Returns a font object loaded from a stream of data. The font is loaded\n// into the document. Various font data structures, such as the ToUnicode data,\n// are auto-generated based on the inputs.\n//\n// document  - handle to the document.\n// data      - the stream of font data, which will be copied by the font object.\n// size      - the size of the font data, in bytes.\n// font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type.\n// cid       - a boolean specifying if the font is a CID font or not.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,\n                                                      const uint8_t* data,\n                                                      uint32_t size,\n                                                      int font_type,\n                                                      FPDF_BOOL cid);\n\n// Experimental API.\n// Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred\n// way of using font style is using a dash to separate the name from the style,\n// for example 'Helvetica-BoldItalic'.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font);\n\n// Experimental API.\n// Returns a font object loaded from a stream of data for a type 2 CID font. The\n// font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode\n// data and the CIDToGIDMap data are caller provided, instead of auto-generated.\n//\n// document                 - handle to the document.\n// font_data                - the stream of font data, which will be copied by\n//                            the font object.\n// font_data_size           - the size of the font data, in bytes.\n// to_unicode_cmap          - the ToUnicode data.\n// cid_to_gid_map_data      - the stream of CIDToGIDMap data.\n// cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadCidType2Font(FPDF_DOCUMENT document,\n                          const uint8_t* font_data,\n                          uint32_t font_data_size,\n                          FPDF_BYTESTRING to_unicode_cmap,\n                          const uint8_t* cid_to_gid_map_data,\n                          uint32_t cid_to_gid_map_data_size);\n\n// Get the font size of a text object.\n//\n//   text - handle to a text.\n//   size - pointer to the font size of the text object, measured in points\n//   (about 1/72 inch)\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size);\n\n// Close a loaded PDF font.\n//\n// font   - Handle to the loaded font.\nFPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font);\n\n// Create a new text object using a loaded font.\n//\n// document   - handle to the document.\n// font       - handle to the font object.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,\n                          FPDF_FONT font,\n                          float font_size);\n\n// Get the text rendering mode of a text object.\n//\n// text     - the handle to the text object.\n//\n// Returns one of the known FPDF_TEXT_RENDERMODE enum values on success,\n// FPDF_TEXTRENDERMODE_UNKNOWN on error.\nFPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV\nFPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Set the text rendering mode of a text object.\n//\n// text         - the handle to the text object.\n// render_mode  - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to\n//                FPDF_TEXTRENDERMODE_UNKNOWN).\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,\n                              FPDF_TEXT_RENDERMODE render_mode);\n\n// Get the text of a text object.\n//\n// text_object      - the handle to the text object.\n// text_page        - the handle to the text page.\n// buffer           - the address of a buffer that receives the text.\n// length           - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the text (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,\n                    FPDF_TEXTPAGE text_page,\n                    FPDF_WCHAR* buffer,\n                    unsigned long length);\n\n// Experimental API.\n// Get a bitmap rasterization of |text_object|. To render correctly, the caller\n// must provide the |document| associated with |text_object|. If there is a\n// |page| associated with |text_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document    - handle to a document associated with |text_object|.\n//   page        - handle to an optional page associated with |text_object|.\n//   text_object - handle to a text object.\n//   scale       - the scaling factor, which must be greater than 0.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                              FPDF_PAGE page,\n                              FPDF_PAGEOBJECT text_object,\n                              float scale);\n\n// Experimental API.\n// Get the font of a text object.\n//\n// text - the handle to the text object.\n//\n// Returns a handle to the font object held by |text| which retains ownership.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Get the base name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the base font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the base name (including the trailing NUL\n// character) on success, 0 on error. The base name is typically the font's\n// PostScript name. See descriptions of \"BaseFont\" in ISO 32000-1:2008 spec.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font,\n                                                          char* buffer,\n                                                          size_t length);\n\n// Experimental API.\n// Get the family name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the family name (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font,\n                                                        char* buffer,\n                                                        size_t length);\n\n// Experimental API.\n// Get the decoded data from the |font| object.\n//\n// font       - The handle to the font object. (Required)\n// buffer     - The address of a buffer that receives the font data.\n// buflen     - Length of the buffer.\n// out_buflen - Pointer to variable that will receive the minimum buffer size\n//              to contain the font data. Not filled if the return value is\n//              FALSE. (Required)\n//\n// Returns TRUE on success. In which case, |out_buflen| will be filled, and\n// |buffer| will be filled if it is large enough. Returns FALSE if any of the\n// required parameters are null.\n//\n// The decoded data is the uncompressed font data. i.e. the raw font data after\n// having all stream filters applied, when the data is embedded.\n//\n// If the font is not embedded, then this API will instead return the data for\n// the substitution font it is using.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font,\n                                                         uint8_t* buffer,\n                                                         size_t buflen,\n                                                         size_t* out_buflen);\n\n// Experimental API.\n// Get whether |font| is embedded or not.\n//\n// font - the handle to the font object.\n//\n// Returns 1 if the font is embedded, 0 if it not, and -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font);\n\n// Experimental API.\n// Get the descriptor flags of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the bit flags specifying various characteristics of the font as\n// defined in ISO 32000-1:2008, table 123, -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font);\n\n// Experimental API.\n// Get the font weight of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the font weight, -1 on failure.\n// Typical values are 400 (normal) and 700 (bold).\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font);\n\n// Experimental API.\n// Get the italic angle of a font.\n//\n// font  - the handle to the font object.\n// angle - pointer where the italic angle will be stored\n//\n// The italic angle of a |font| is defined as degrees counterclockwise\n// from vertical. For a font that slopes to the right, this will be negative.\n//\n// Returns TRUE on success; |angle| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font,\n                                                            int* angle);\n\n// Experimental API.\n// Get ascent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// ascent     - pointer where the font ascent will be stored\n//\n// Ascent is the maximum distance in points above the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |ascent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font,\n                                                       float font_size,\n                                                       float* ascent);\n\n// Experimental API.\n// Get descent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// descent    - pointer where the font descent will be stored\n//\n// Descent is the maximum distance in points below the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |descent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font,\n                                                        float font_size,\n                                                        float* descent);\n\n// Experimental API.\n// Get the width of a glyph in a font.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph.\n// font_size  - the size of the font.\n// width      - pointer where the glyph width will be stored\n//\n// Glyph width is the distance from the end of the prior glyph to the next\n// glyph. This will be the vertical distance for vertical writing.\n//\n// Returns TRUE on success; |width| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font,\n                                                           uint32_t glyph,\n                                                           float font_size,\n                                                           float* width);\n\n// Experimental API.\n// Get the glyphpath describing how to draw a font glyph.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph being drawn.\n// font_size  - the size of the font.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font,\n                                                               uint32_t glyph,\n                                                               float font_size);\n\n// Experimental API.\n// Get number of segments inside glyphpath.\n//\n// glyphpath - handle to a glyph path.\n//\n// Returns the number of objects in |glyphpath| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath);\n\n// Experimental API.\n// Get segment in glyphpath at index.\n//\n// glyphpath  - handle to a glyph path.\n// index      - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index);\n\n// Get number of page objects inside |form_object|.\n//\n//   form_object - handle to a form object.\n//\n// Returns the number of objects in |form_object| on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object);\n\n// Get page object in |form_object| at |index|.\n//\n//   form_object - handle to a form object.\n//   index       - the 0-based index of a page object.\n//\n// Returns the handle to the page object, or NULL on error.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index);\n\n// Experimental API.\n//\n// Remove |page_object| from |form_object|.\n//\n//   form_object - handle to a form object.\n//   page_object - handle to a page object to be removed from the form.\n//\n// Returns TRUE on success.\n//\n// Ownership of the removed |page_object| is transferred to the caller.\n// Call FPDFPageObj_Destroy() on the removed page_object to free it.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object,\n                         FPDF_PAGEOBJECT page_object);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EDIT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_ext.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EXT_H_\n#define PUBLIC_FPDF_EXT_H_\n\n#include <time.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported XFA form.\n#define FPDF_UNSP_DOC_XFAFORM 1\n// Unsupported portable collection.\n#define FPDF_UNSP_DOC_PORTABLECOLLECTION 2\n// Unsupported attachment.\n#define FPDF_UNSP_DOC_ATTACHMENT 3\n// Unsupported security.\n#define FPDF_UNSP_DOC_SECURITY 4\n// Unsupported shared review.\n#define FPDF_UNSP_DOC_SHAREDREVIEW 5\n// Unsupported shared form, acrobat.\n#define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6\n// Unsupported shared form, filesystem.\n#define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7\n// Unsupported shared form, email.\n#define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8\n// Unsupported 3D annotation.\n#define FPDF_UNSP_ANNOT_3DANNOT 11\n// Unsupported movie annotation.\n#define FPDF_UNSP_ANNOT_MOVIE 12\n// Unsupported sound annotation.\n#define FPDF_UNSP_ANNOT_SOUND 13\n// Unsupported screen media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14\n// Unsupported screen rich media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15\n// Unsupported attachment annotation.\n#define FPDF_UNSP_ANNOT_ATTACHMENT 16\n// Unsupported signature annotation.\n#define FPDF_UNSP_ANNOT_SIG 17\n\n// Interface for unsupported feature notifications.\ntypedef struct _UNSUPPORT_INFO {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Unsupported object notification function.\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis - pointer to the interface structure.\n  //   nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries.\n  void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType);\n} UNSUPPORT_INFO;\n\n// Setup an unsupported object handler.\n//\n//   unsp_info - Pointer to an UNSUPPORT_INFO structure.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info);\n\n// Set replacement function for calls to time().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of time(), or\n//          NULL to restore to actual time() call itself.\nFPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)());\n\n// Set replacement function for calls to localtime().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of localtime(), or\n//          NULL to restore to actual localtime() call itself.\nFPDF_EXPORT void FPDF_CALLCONV\nFSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*));\n\n// Unknown page mode.\n#define PAGEMODE_UNKNOWN -1\n// Document outline, and thumbnails hidden.\n#define PAGEMODE_USENONE 0\n// Document outline visible.\n#define PAGEMODE_USEOUTLINES 1\n// Thumbnail images visible.\n#define PAGEMODE_USETHUMBS 2\n// Full-screen mode, no menu bar, window controls, or other decorations visible.\n#define PAGEMODE_FULLSCREEN 3\n// Optional content group panel visible.\n#define PAGEMODE_USEOC 4\n// Attachments panel visible.\n#define PAGEMODE_USEATTACHMENTS 5\n\n// Get the document's PageMode.\n//\n//   doc - Handle to document.\n//\n// Returns one of the |PAGEMODE_*| flags defined above.\n//\n// The page mode defines how the document should be initially displayed.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EXT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_flatten.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FLATTEN_H_\n#define PUBLIC_FPDF_FLATTEN_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flatten operation failed.\n#define FLATTEN_FAIL 0\n// Flatten operation succeed.\n#define FLATTEN_SUCCESS 1\n// Nothing to be flattened.\n#define FLATTEN_NOTHINGTODO 2\n\n// Flatten for normal display.\n#define FLAT_NORMALDISPLAY 0\n// Flatten for print.\n#define FLAT_PRINT 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Flatten annotations and form fields into the page contents.\n//\n//   page  - handle to the page.\n//   nFlag - One of the |FLAT_*| values denoting the page usage.\n//\n// Returns one of the |FLATTEN_*| values.\n//\n// Currently, all failures return |FLATTEN_FAIL| with no indication of the\n// cause.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FLATTEN_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_formfill.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FORMFILL_H_\n#define PUBLIC_FPDF_FORMFILL_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n// These values are return values for a public API, so should not be changed\n// other than the count when adding new values.\n#define FORMTYPE_NONE 0            // Document contains no forms\n#define FORMTYPE_ACRO_FORM 1       // Forms are specified using AcroForm spec\n#define FORMTYPE_XFA_FULL 2        // Forms are specified using entire XFA spec\n#define FORMTYPE_XFA_FOREGROUND 3  // Forms are specified using the XFAF subset\n                                   // of XFA spec\n#define FORMTYPE_COUNT 4           // The number of form types\n\n#define JSPLATFORM_ALERT_BUTTON_OK 0           // OK button\n#define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1     // OK & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNO 2        // Yes & No buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3  // Yes, No & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK\n\n#define JSPLATFORM_ALERT_ICON_ERROR 0     // Error\n#define JSPLATFORM_ALERT_ICON_WARNING 1   // Warning\n#define JSPLATFORM_ALERT_ICON_QUESTION 2  // Question\n#define JSPLATFORM_ALERT_ICON_STATUS 3    // Status\n#define JSPLATFORM_ALERT_ICON_ASTERISK 4  // Asterisk\n#define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR\n\n#define JSPLATFORM_ALERT_RETURN_OK 1      // OK\n#define JSPLATFORM_ALERT_RETURN_CANCEL 2  // Cancel\n#define JSPLATFORM_ALERT_RETURN_NO 3      // No\n#define JSPLATFORM_ALERT_RETURN_YES 4     // Yes\n\n#define JSPLATFORM_BEEP_ERROR 0           // Error\n#define JSPLATFORM_BEEP_WARNING 1         // Warning\n#define JSPLATFORM_BEEP_QUESTION 2        // Question\n#define JSPLATFORM_BEEP_STATUS 3          // Status\n#define JSPLATFORM_BEEP_DEFAULT 4         // Default\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _IPDF_JsPlatform {\n  // Version number of the interface. Currently must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: app_alert\n  //       Pop up a dialog to show warning or hint.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       Msg         -   A string containing the message to be displayed.\n  //       Title       -   The title of the dialog.\n  //       Type        -   The type of button group, one of the\n  //                       JSPLATFORM_ALERT_BUTTON_* values above.\n  //       nIcon       -   The type of the icon, one of the\n  //                       JSPLATFORM_ALERT_ICON_* above.\n  // Return Value:\n  //       Option selected by user in dialogue, one of the\n  //       JSPLATFORM_ALERT_RETURN_* values above.\n  int (*app_alert)(struct _IPDF_JsPlatform* pThis,\n                   FPDF_WIDESTRING Msg,\n                   FPDF_WIDESTRING Title,\n                   int Type,\n                   int Icon);\n\n  // Method: app_beep\n  //       Causes the system to play a sound.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nType       -   The sound type, see JSPLATFORM_BEEP_TYPE_*\n  //                       above.\n  // Return Value:\n  //       None\n  void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType);\n\n  // Method: app_response\n  //       Displays a dialog box containing a question and an entry field for\n  //       the user to reply to the question.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       Question    -   The question to be posed to the user.\n  //       Title       -   The title of the dialog box.\n  //       Default     -   A default value for the answer to the question. If\n  //                       not specified, no default value is presented.\n  //       cLabel      -   A short string to appear in front of and on the\n  //                       same line as the edit text field.\n  //       bPassword   -   If true, indicates that the user's response should\n  //                       be shown as asterisks (*) or bullets (?) to mask\n  //                       the response, which might be sensitive information.\n  //       response    -   A string buffer allocated by PDFium, to receive the\n  //                       user's response.\n  //       length      -   The length of the buffer in bytes. Currently, it is\n  //                       always 2048.\n  // Return Value:\n  //       Number of bytes the complete user input would actually require, not\n  //       including trailing zeros, regardless of the value of the length\n  //       parameter or the presence of the response buffer.\n  // Comments:\n  //       No matter on what platform, the response buffer should be always\n  //       written using UTF-16LE encoding. If a response buffer is\n  //       present and the size of the user input exceeds the capacity of the\n  //       buffer as specified by the length parameter, only the\n  //       first \"length\" bytes of the user input are to be written to the\n  //       buffer.\n  int (*app_response)(struct _IPDF_JsPlatform* pThis,\n                      FPDF_WIDESTRING Question,\n                      FPDF_WIDESTRING Title,\n                      FPDF_WIDESTRING Default,\n                      FPDF_WIDESTRING cLabel,\n                      FPDF_BOOL bPassword,\n                      void* response,\n                      int length);\n\n  // Method: Doc_getFilePath\n  //       Get the file path of the current document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       filePath    -   The string buffer to receive the file path. Can\n  //                       be NULL.\n  //       length      -   The length of the buffer, number of bytes. Can\n  //                       be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in the local encoding.\n  //       The return value always indicated number of bytes required for\n  //       the buffer, even when there is no buffer specified, or the buffer\n  //       size is less than required. In this case, the buffer will not\n  //       be modified.\n  int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis,\n                         void* filePath,\n                         int length);\n\n  // Method: Doc_mail\n  //       Mails the data buffer as an attachment to all recipients, with or\n  //       without user interaction.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       mailData    -   Pointer to the data buffer to be sent. Can be NULL.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       mailData parameter. Can be 0.\n  //       bUI         -   If true, the rest of the parameters are used in a\n  //                       compose-new-message window that is displayed to the\n  //                       user. If false, the cTo parameter is required and\n  //                       all others are optional.\n  //       To          -   A semicolon-delimited list of recipients for the\n  //                       message.\n  //       Subject     -   The subject of the message. The length limit is\n  //                       64 KB.\n  //       CC          -   A semicolon-delimited list of CC recipients for\n  //                       the message.\n  //       BCC         -   A semicolon-delimited list of BCC recipients for\n  //                       the message.\n  //       Msg         -   The content of the message. The length limit is\n  //                       64 KB.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       If the parameter mailData is NULL or length is 0, the current\n  //       document will be mailed as an attachment to all recipients.\n  void (*Doc_mail)(struct _IPDF_JsPlatform* pThis,\n                   void* mailData,\n                   int length,\n                   FPDF_BOOL bUI,\n                   FPDF_WIDESTRING To,\n                   FPDF_WIDESTRING Subject,\n                   FPDF_WIDESTRING CC,\n                   FPDF_WIDESTRING BCC,\n                   FPDF_WIDESTRING Msg);\n\n  // Method: Doc_print\n  //       Prints all or a specific number of pages of the document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis         -   Pointer to the interface structure itself.\n  //       bUI           -   If true, will cause a UI to be presented to the\n  //                         user to obtain printing information and confirm\n  //                         the action.\n  //       nStart        -   A 0-based index that defines the start of an\n  //                         inclusive range of pages.\n  //       nEnd          -   A 0-based index that defines the end of an\n  //                         inclusive page range.\n  //       bSilent       -   If true, suppresses the cancel dialog box while\n  //                         the document is printing. The default is false.\n  //       bShrinkToFit  -   If true, the page is shrunk (if necessary) to\n  //                         fit within the imageable area of the printed page.\n  //       bPrintAsImage -   If true, print pages as an image.\n  //       bReverse      -   If true, print from nEnd to nStart.\n  //       bAnnotations  -   If true (the default), annotations are\n  //                         printed.\n  // Return Value:\n  //       None.\n  void (*Doc_print)(struct _IPDF_JsPlatform* pThis,\n                    FPDF_BOOL bUI,\n                    int nStart,\n                    int nEnd,\n                    FPDF_BOOL bSilent,\n                    FPDF_BOOL bShrinkToFit,\n                    FPDF_BOOL bPrintAsImage,\n                    FPDF_BOOL bReverse,\n                    FPDF_BOOL bAnnotations);\n\n  // Method: Doc_submitForm\n  //       Send the form data to a specified URL.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       formData    -   Pointer to the data buffer to be sent.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       formData parameter.\n  //       URL         -   The URL to send to.\n  // Return Value:\n  //       None.\n  void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis,\n                         void* formData,\n                         int length,\n                         FPDF_WIDESTRING URL);\n\n  // Method: Doc_gotoPage\n  //       Jump to a specified page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nPageNum    -   The specified page number, zero for the first page.\n  // Return Value:\n  //       None.\n  void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum);\n\n  // Method: Field_browse\n  //       Show a file selection dialog, and return the selected file path.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       filePath    -   Pointer to the data buffer to receive the file\n  //                       path. Can be NULL.\n  //       length      -   The length of the buffer, in bytes. Can be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in local encoding.\n  int (*Field_browse)(struct _IPDF_JsPlatform* pThis,\n                      void* filePath,\n                      int length);\n\n  // Pointer for embedder-specific data. Unused by PDFium, and despite\n  // its name, can be any data the embedder desires, though traditionally\n  // a FPDF_FORMFILLINFO interface.\n  void* m_pFormfillinfo;\n\n  // Version 2.\n\n  void* m_isolate;               // Unused in v3, retain for compatibility.\n  unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility.\n\n  // Version 3.\n  // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG.\n} IPDF_JSPLATFORM;\n\n// Flags for Cursor type\n#define FXCT_ARROW 0\n#define FXCT_NESW 1\n#define FXCT_NWSE 2\n#define FXCT_VBEAM 3\n#define FXCT_HBEAM 4\n#define FXCT_HAND 5\n\n// Function signature for the callback function passed to the FFI_SetTimer\n// method.\n// Parameters:\n//          idEvent     -   Identifier of the timer.\n// Return value:\n//          None.\ntypedef void (*TimerCallback)(int idEvent);\n\n// Declares of a struct type to the local system time.\ntypedef struct _FPDF_SYSTEMTIME {\n  unsigned short wYear;         // years since 1900\n  unsigned short wMonth;        // months since January - [0,11]\n  unsigned short wDayOfWeek;    // days since Sunday - [0,6]\n  unsigned short wDay;          // day of the month - [1,31]\n  unsigned short wHour;         // hours since midnight - [0,23]\n  unsigned short wMinute;       // minutes after the hour - [0,59]\n  unsigned short wSecond;       // seconds after the minute - [0,59]\n  unsigned short wMilliseconds; // milliseconds after the second - [0,999]\n} FPDF_SYSTEMTIME;\n\n#ifdef PDF_ENABLE_XFA\n\n// Pageview event flags\n#define FXFA_PAGEVIEWEVENT_POSTADDED 1    // After a new pageview is added.\n#define FXFA_PAGEVIEWEVENT_POSTREMOVED 3  // After a pageview is removed.\n\n// Definitions for Right Context Menu Features Of XFA Fields\n#define FXFA_MENU_COPY 1\n#define FXFA_MENU_CUT 2\n#define FXFA_MENU_SELECTALL 4\n#define FXFA_MENU_UNDO 8\n#define FXFA_MENU_REDO 16\n#define FXFA_MENU_PASTE 32\n\n// Definitions for File Type.\n#define FXFA_SAVEAS_XML 1\n#define FXFA_SAVEAS_XDP 2\n\n#endif  // PDF_ENABLE_XFA\n\ntypedef struct _FPDF_FORMFILLINFO {\n  // Version number of the interface.\n  // Version 1 contains stable interfaces. Version 2 has additional\n  // experimental interfaces.\n  // When PDFium is built without the XFA module, version can be 1 or 2.\n  // With version 1, only stable interfaces are called. With version 2,\n  // additional experimental interfaces are also called.\n  // When PDFium is built with the XFA module, version must be 2.\n  // All the XFA related interfaces are experimental. If PDFium is built with\n  // the XFA module and version 1 then none of the XFA related interfaces\n  // would be called. When PDFium is built with XFA module then the version\n  // must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: Release\n  //       Give the implementation a chance to release any resources after the\n  //       interface is no longer used.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Comments:\n  //       Called by PDFium during the final cleanup process.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //       None\n  void (*Release)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_Invalidate\n  //       Invalidate the client area within the specified rectangle.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage().\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       All positions are measured in PDF \"user space\".\n  //       Implementation should call FPDF_RenderPageBitmap() for repainting\n  //       the specified page area.\n  void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis,\n                         FPDF_PAGE page,\n                         double left,\n                         double top,\n                         double right,\n                         double bottom);\n\n  // Method: FFI_OutputSelectedRect\n  //       When the user selects text in form fields with the mouse, this\n  //       callback function will be invoked with the selected areas.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage()/\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       This callback function is useful for implementing special text\n  //       selection effects. An implementation should first record the\n  //       returned rectangles, then draw them one by one during the next\n  //       painting period. Lastly, it should remove all the recorded\n  //       rectangles when finished painting.\n  void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_PAGE page,\n                                 double left,\n                                 double top,\n                                 double right,\n                                 double bottom);\n\n  // Method: FFI_SetCursor\n  //       Set the Cursor shape.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nCursorType -   Cursor type, see Flags for Cursor type for details.\n  // Return value:\n  //       None.\n  void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType);\n\n  // Method: FFI_SetTimer\n  //       This method installs a system timer. An interval value is specified,\n  //       and every time that interval elapses, the system must call into the\n  //       callback function with the timer ID as returned by this function.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       uElapse     -   Specifies the time-out value, in milliseconds.\n  //       lpTimerFunc -   A pointer to the callback function-TimerCallback.\n  // Return value:\n  //       The timer identifier of the new timer if the function is successful.\n  //       An application passes this value to the FFI_KillTimer method to kill\n  //       the timer. Nonzero if it is successful; otherwise, it is zero.\n  int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis,\n                      int uElapse,\n                      TimerCallback lpTimerFunc);\n\n  // Method: FFI_KillTimer\n  //       This method uninstalls a system timer, as set by an earlier call to\n  //       FFI_SetTimer.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nTimerID    -   The timer ID returned by FFI_SetTimer function.\n  // Return value:\n  //       None.\n  void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID);\n\n  // Method: FFI_GetLocalTime\n  //       This method receives the current local time on the system.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       The local time. See FPDF_SYSTEMTIME above for details.\n  // Note: Unused.\n  FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_OnChange\n  //       This method will be invoked to notify the implementation when the\n  //       value of any FormField on the document had been changed.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       None.\n  void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_GetPage\n  //       This method receives the page handle associated with a specified\n  //       page index.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  //       nPageIndex  -   Index number of the page. 0 for the first page.\n  // Return value:\n  //       Handle to the page, as previously returned to the implementation by\n  //       FPDF_LoadPage().\n  // Comments:\n  //       The implementation is expected to keep track of the page handles it\n  //       receives from PDFium, and their mappings to page numbers. In some\n  //       cases, the document-level JavaScript action may refer to a page\n  //       which hadn't been loaded yet. To successfully run the Javascript\n  //       action, the implementation needs to load the page.\n  FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_DOCUMENT document,\n                           int nPageIndex);\n\n  // Method: FFI_GetCurrentPage\n  //       This method receives the handle to the current page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       Yes when V8 support is present, otherwise unused.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  // Return value:\n  //       Handle to the page. Returned by FPDF_LoadPage().\n  // Comments:\n  //       PDFium doesn't keep keep track of the \"current page\" (e.g. the one\n  //       that is most visible on screen), so it must ask the embedder for\n  //       this information.\n  FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_DOCUMENT document);\n\n  // Method: FFI_GetRotation\n  //       This method receives currently rotation of the page view.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to page, as returned by FPDF_LoadPage().\n  // Return value:\n  //       A number to indicate the page rotation in 90 degree increments\n  //       in a clockwise direction:\n  //         0 - 0 degrees\n  //         1 - 90 degrees\n  //         2 - 180 degrees\n  //         3 - 270 degrees\n  // Note: Unused.\n  int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page);\n\n  // Method: FFI_ExecuteNamedAction\n  //       This method will execute a named action.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       namedAction     -   A byte string which indicates the named action,\n  //                           terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the\n  //       standard named actions, but note that a document may supply any\n  //       name of its choosing.\n  void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_BYTESTRING namedAction);\n  // Method: FFI_SetTextFieldFocus\n  //       Called when a text field is getting or losing focus.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       value           -   The string value of the form field, in UTF-16LE\n  //                           format.\n  //       valueLen        -   The length of the string value. This is the\n  //                           number of characters, not bytes.\n  //       is_focus        -   True if the form field is getting focus, false\n  //                           if the form field is losing focus.\n  // Return value:\n  //       None.\n  // Comments:\n  //       Only supports text fields and combobox fields.\n  void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis,\n                                FPDF_WIDESTRING value,\n                                FPDF_DWORD valueLen,\n                                FPDF_BOOL is_focus);\n\n  // Method: FFI_DoURIAction\n  //       Ask the implementation to navigate to a uniform resource identifier.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       bsURI           -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder is version 2 or higher and have implementation for\n  //       FFI_DoURIActionWithKeyboardModifier, then\n  //       FFI_DoURIActionWithKeyboardModifier takes precedence over\n  //       FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis,\n                          FPDF_BYTESTRING bsURI);\n\n  // Method: FFI_DoGoToAction\n  //       This action changes the view to a specified destination.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       nPageIndex      -   The index of the PDF page.\n  //       zoomMode        -   The zoom mode for viewing page. See below.\n  //       fPosArray       -   The float array which carries the position info.\n  //       sizeofArray     -   The size of float array.\n  // PDFZoom values:\n  //         - XYZ = 1\n  //         - FITPAGE = 2\n  //         - FITHORZ = 3\n  //         - FITVERT = 4\n  //         - FITRECT = 5\n  //         - FITBBOX = 6\n  //         - FITBHORZ = 7\n  //         - FITBVERT = 8\n  // Return value:\n  //       None.\n  // Comments:\n  //       See the Destinations description of <<PDF Reference, version 1.7>>\n  //       in 8.2.1 for more details.\n  void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis,\n                           int nPageIndex,\n                           int zoomMode,\n                           float* fPosArray,\n                           int sizeofArray);\n\n  // Pointer to IPDF_JSPLATFORM interface.\n  // Unused if PDFium is built without V8 support. Otherwise, if NULL, then\n  // JavaScript will be prevented from executing while rendering the document.\n  IPDF_JSPLATFORM* m_pJsPlatform;\n\n  // Version 2 - Experimental.\n\n  // Whether the XFA module is disabled when built with the XFA module.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  FPDF_BOOL xfa_disabled;\n\n  // Method: FFI_DisplayCaret\n  //       This method will show the caret at specified position.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   Left position of the client area in PDF page\n  //                           coordinates.\n  //       top             -   Top position of the client area in PDF page\n  //                           coordinates.\n  //       right           -   Right position of the client area in PDF page\n  //                           coordinates.\n  //       bottom          -   Bottom position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       None.\n  void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_PAGE page,\n                           FPDF_BOOL bVisible,\n                           double left,\n                           double top,\n                           double right,\n                           double bottom);\n\n  // Method: FFI_GetCurrentPageIndex\n  //       This method will get the current page index.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  // Return value:\n  //       The index of current page.\n  int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_DOCUMENT document);\n\n  // Method: FFI_SetCurrentPage\n  //       This method will set the current page.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  //       iCurPage        -   The index of the PDF page.\n  // Return value:\n  //       None.\n  void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_DOCUMENT document,\n                             int iCurPage);\n\n // Method: FFI_GotoURL\n //       This method will navigate to the specified URL.\n // Interface Version:\n //       Ignored if |version| < 2.\n // Implementation Required:\n //       Required for XFA, otherwise set to NULL.\n // Parameters:\n //       pThis            -   Pointer to the interface structure itself.\n //       document         -   Handle to document from FPDF_LoadDocument().\n //       wsURL            -   The string value of the URL, in UTF-16LE format.\n // Return value:\n //       None.\n  void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_DOCUMENT document,\n                      FPDF_WIDESTRING wsURL);\n\n  // Method: FFI_GetPageViewRect\n  //       This method will get the current page view rectangle.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   The pointer to receive left position of the page\n  //                           view area in PDF page coordinates.\n  //       top             -   The pointer to receive top position of the page\n  //                           view area in PDF page coordinates.\n  //       right           -   The pointer to receive right position of the\n  //                           page view area in PDF page coordinates.\n  //       bottom          -   The pointer to receive bottom position of the\n  //                           page view area in PDF page coordinates.\n  // Return value:\n  //     None.\n  void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis,\n                              FPDF_PAGE page,\n                              double* left,\n                              double* top,\n                              double* right,\n                              double* bottom);\n\n  // Method: FFI_PageEvent\n  //       This method fires when pages have been added to or deleted from\n  //       the XFA document.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page_count      -   The number of pages to be added or deleted.\n  //       event_type      -   See FXFA_PAGEVIEWEVENT_* above.\n  // Return value:\n  //       None.\n  // Comments:\n  //       The pages to be added or deleted always start from the last page\n  //       of document. This means that if parameter page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been\n  //       appended to the tail of document; If page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages\n  //       have been deleted.\n  void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis,\n                        int page_count,\n                        FPDF_DWORD event_type);\n\n  // Method: FFI_PopupMenu\n  //       This method will track the right context menu for XFA fields.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       hWidget         -   Always null, exists for compatibility.\n  //       menuFlag        -   The menu flags. Please refer to macro definition\n  //                           of FXFA_MENU_XXX and this can be one or a\n  //                           combination of these macros.\n  //       x               -   X position of the client area in PDF page\n  //                           coordinates.\n  //       y               -   Y position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       TRUE indicates success; otherwise false.\n  FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_PAGE page,\n                             FPDF_WIDGET hWidget,\n                             int menuFlag,\n                             float x,\n                             float y);\n\n  // Method: FFI_OpenFile\n  //       This method will open the specified file with the specified mode.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       wsURL           -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  //       mode            -   The mode for open file, e.g. \"rb\" or \"wb\".\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis,\n                                    int fileFlag,\n                                    FPDF_WIDESTRING wsURL,\n                                    const char* mode);\n\n  // Method: FFI_EmailTo\n  //       This method will email the specified file stream to the specified\n  //       contact.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       pTo             -   A semicolon-delimited list of recipients for the\n  //                           message,in UTF-16LE format.\n  //       pSubject        -   The subject of the message,in UTF-16LE format.\n  //       pCC             -   A semicolon-delimited list of CC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pBcc            -   A semicolon-delimited list of BCC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pMsg            -   Pointer to the data buffer to be sent.Can be\n  //                           NULL,in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_FILEHANDLER* fileHandler,\n                      FPDF_WIDESTRING pTo,\n                      FPDF_WIDESTRING pSubject,\n                      FPDF_WIDESTRING pCC,\n                      FPDF_WIDESTRING pBcc,\n                      FPDF_WIDESTRING pMsg);\n\n  // Method: FFI_UploadTo\n  //       This method will upload the specified file stream to the\n  //       specified URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       uploadTo        -   Pointer to the URL path, in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis,\n                       FPDF_FILEHANDLER* fileHandler,\n                       int fileFlag,\n                       FPDF_WIDESTRING uploadTo);\n\n  // Method: FFI_GetPlatform\n  //       This method will get the current platform.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       platform        -   Pointer to the data buffer to receive the\n  //                           platform,in UTF-16LE format. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* platform,\n                         int length);\n\n  // Method: FFI_GetLanguage\n  //       This method will get the current language.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       language        -   Pointer to the data buffer to receive the\n  //                           current language. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* language,\n                         int length);\n\n  // Method: FFI_DownloadFromURL\n  //       This method will download the specified file from the URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       URL             -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                           FPDF_WIDESTRING URL);\n  // Method: FFI_PostRequestURL\n  //       This method will post the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The post data,in UTF-16LE format.\n  //       wsContentType   -   The content type of the request data, in\n  //                           UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTF-16LE format.\n  //       wsHeader        -   The request header,in UTF-16LE format.\n  //       response        -   Pointer to the FPDF_BSTR to receive the response\n  //                           data from the server, in UTF-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_WIDESTRING wsURL,\n                                  FPDF_WIDESTRING wsData,\n                                  FPDF_WIDESTRING wsContentType,\n                                  FPDF_WIDESTRING wsEncode,\n                                  FPDF_WIDESTRING wsHeader,\n                                  FPDF_BSTR* response);\n\n  // Method: FFI_PutRequestURL\n  //       This method will put the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The put data, in UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTR-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_WIDESTRING wsURL,\n                                 FPDF_WIDESTRING wsData,\n                                 FPDF_WIDESTRING wsEncode);\n\n  // Method: FFI_OnFocusChange\n  //     Called when the focused annotation is updated.\n  // Interface Version:\n  //     Ignored if |version| < 2.\n  // Implementation Required:\n  //     No\n  // Parameters:\n  //     param           -   Pointer to the interface structure itself.\n  //     annot           -   The focused annotation.\n  //     page_index      -   Index number of the page which contains the\n  //                         focused annotation. 0 for the first page.\n  // Return value:\n  //     None.\n  // Comments:\n  //     This callback function is useful for implementing any view based\n  //     action such as scrolling the annotation rect into view. The\n  //     embedder should not copy and store the annot as its scope is\n  //     limited to this call only.\n  void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param,\n                            FPDF_ANNOTATION annot,\n                            int page_index);\n\n  // Method: FFI_DoURIActionWithKeyboardModifier\n  //       Ask the implementation to navigate to a uniform resource identifier\n  //       with the specified modifiers.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       param           -   Pointer to the interface structure itself.\n  //       uri             -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  //       modifiers       -   Keyboard modifier that indicates which of\n  //                           the virtual keys are down, if any.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder who is version 2 and does not implement this API,\n  //       then a call will be redirected to FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param,\n      FPDF_BYTESTRING uri,\n      int modifiers);\n} FPDF_FORMFILLINFO;\n\n// Function: FPDFDOC_InitFormFillEnvironment\n//       Initialize form fill environment.\n// Parameters:\n//       document        -   Handle to document from FPDF_LoadDocument().\n//       formInfo        -   Pointer to a FPDF_FORMFILLINFO structure.\n// Return Value:\n//       Handle to the form fill module, or NULL on failure.\n// Comments:\n//       This function should be called before any form fill operation.\n//       The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until\n//       the returned FPDF_FORMHANDLE is closed.\nFPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV\nFPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,\n                                FPDF_FORMFILLINFO* formInfo);\n\n// Function: FPDFDOC_ExitFormFillEnvironment\n//       Take ownership of |hHandle| and exit form fill environment.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This function is a no-op when |hHandle| is null.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnAfterLoadPage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked after user successfully loaded a\n//       PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,\n                                                    FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnBeforeClosePage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked before user closes the PDF page.\n// Parameters:\n//        page        -   Handle to the page, as returned by FPDF_LoadPage().\n//        hHandle     -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//        None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page,\n                                                      FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentJSAction\n//       This method is required for performing document-level JavaScript\n//       actions. It should be invoked after the PDF document has been loaded.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       If there is document-level JavaScript action embedded in the\n//       document, this method will execute the JavaScript action. Otherwise,\n//       the method will do nothing.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentOpenAction\n//       This method is required for performing open-action when the document\n//       is opened.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there are no open-actions embedded\n//       in the document.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle);\n\n// Additional actions type of document:\n//   WC, before closing document, JavaScript action.\n//   WS, before saving document, JavaScript action.\n//   DS, after saving document, JavaScript action.\n//   WP, before printing document, JavaScript action.\n//   DP, after printing document, JavaScript action.\n#define FPDFDOC_AACTION_WC 0x10\n#define FPDFDOC_AACTION_WS 0x11\n#define FPDFDOC_AACTION_DS 0x12\n#define FPDFDOC_AACTION_WP 0x13\n#define FPDFDOC_AACTION_DP 0x14\n\n// Function: FORM_DoDocumentAAction\n//       This method is required for performing the document's\n//       additional-action.\n// Parameters:\n//       hHandle     -   Handle to the form fill module. Returned by\n//                       FPDFDOC_InitFormFillEnvironment.\n//       aaType      -   The type of the additional-actions which defined\n//                       above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there is no document\n//       additional-action corresponding to the specified |aaType|.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,\n                                                      int aaType);\n\n// Additional-action types of page object:\n//   OPEN (/O) -- An action to be performed when the page is opened\n//   CLOSE (/C) -- An action to be performed when the page is closed\n#define FPDFPAGE_AACTION_OPEN 0\n#define FPDFPAGE_AACTION_CLOSE 1\n\n// Function: FORM_DoPageAAction\n//       This method is required for performing the page object's\n//       additional-action when opened or closed.\n// Parameters:\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       aaType      -   The type of the page object's additional-actions\n//                       which defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if no additional-action corresponding\n//       to the specified |aaType| exists.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page,\n                                                  FPDF_FORMHANDLE hHandle,\n                                                  int aaType);\n\n// Function: FORM_OnMouseMove\n//       Call this member function when the mouse cursor moves.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Experimental API\n// Function: FORM_OnMouseWheel\n//       Call this member function when the user scrolls the mouse wheel.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_coord  -   Specifies the coordinates of the cursor in PDF user\n//                       space.\n//       delta_x     -   Specifies the amount of wheel movement on the x-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean left.\n//       delta_y     -   Specifies the amount of wheel movement on the y-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean down.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       For |delta_x| and |delta_y|, the caller must normalize\n//       platform-specific wheel deltas. e.g. On Windows, a delta value of 240\n//       for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines\n//       WHEEL_DELTA as 120.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel(\n    FPDF_FORMHANDLE hHandle,\n    FPDF_PAGE page,\n    int modifier,\n    const FS_POINTF* page_coord,\n    int delta_x,\n    int delta_y);\n\n// Function: FORM_OnFocus\n//       This function focuses the form annotation at a given point. If the\n//       annotation at the point already has focus, nothing happens. If there\n//       is no annotation at the point, removes form focus.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True if there is an annotation at the given point and it has focus.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int modifier,\n                                                 double page_x,\n                                                 double page_y);\n\n// Function: FORM_OnLButtonDown\n//       Call this member function when the user presses the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n\n// Function: FORM_OnRButtonDown\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n// Function: FORM_OnLButtonUp\n//       Call this member function when the user releases the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in device.\n//       page_y      -   Specifies the y-coordinate of the cursor in device.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnRButtonUp\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnLButtonDoubleClick\n//       Call this member function when the user double clicks the\n//       left mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle,\n                          FPDF_PAGE page,\n                          int modifier,\n                          double page_x,\n                          double page_y);\n\n// Function: FORM_OnKeyDown\n//       Call this member function when a nonsystem key is pressed.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, aseturned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,\n                                                   FPDF_PAGE page,\n                                                   int nKeyCode,\n                                                   int modifier);\n\n// Function: FORM_OnKeyUp\n//       Call this member function when a nonsystem key is released.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       Currently unimplemented and always returns false. PDFium reserves this\n//       API and may implement it in the future on an as-needed basis.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int nKeyCode,\n                                                 int modifier);\n\n// Function: FORM_OnChar\n//       Call this member function when a keystroke translates to a\n//       nonsystem character.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nChar       -   The character code value itself.\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle,\n                                                FPDF_PAGE page,\n                                                int nChar,\n                                                int modifier);\n\n// Experimental API\n// Function: FORM_GetFocusedText\n//       Call this function to obtain the text within the current focused\n//       field, if any.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the form text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the form text string, |buffer| is\n//                       not modified.\n// Return Value:\n//       Length in bytes for the text in the focused field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetFocusedText(FPDF_FORMHANDLE hHandle,\n                    FPDF_PAGE page,\n                    void* buffer,\n                    unsigned long buflen);\n\n// Function: FORM_GetSelectedText\n//       Call this function to obtain selected text within a form text\n//       field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the selected text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the selected text string,\n//                       |buffer| is not modified.\n// Return Value:\n//       Length in bytes of selected text in form text field or form combobox\n//       text field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetSelectedText(FPDF_FORMHANDLE hHandle,\n                     FPDF_PAGE page,\n                     void* buffer,\n                     unsigned long buflen);\n\n// Experimental API\n// Function: FORM_ReplaceAndKeepSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the inserted text\n//       will be selected.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             FPDF_WIDESTRING wsText);\n\n// Function: FORM_ReplaceSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the selection range\n//       will be set to empty.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     FPDF_WIDESTRING wsText);\n\n// Experimental API\n// Function: FORM_SelectAllText\n//       Call this function to select all the text within the currently focused\n//       form text field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       Whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page);\n\n// Function: FORM_CanUndo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to undo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_CanRedo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to redo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_Undo\n//       Make the current focused widget perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the undo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_Redo\n//       Make the current focused widget perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the redo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_ForceToKillFocus.\n//       Call this member function to force to kill the focus of the form\n//       field which has focus. If it would kill the focus of a form field,\n//       save the value of form field if was changed by theuser.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Function: FORM_GetFocusedAnnot.\n//       Call this member function to get the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page_index  -   Buffer to hold the index number of the page which\n//                       contains the focused annotation. 0 for the first page.\n//                       Can't be NULL.\n//       annot       -   Buffer to hold the focused annotation. Can't be NULL.\n// Return Value:\n//       On success, return true and write to the out parameters. Otherwise\n//       return false and leave the out parameters unmodified.\n// Comments:\n//       Not currently supported for XFA forms - will report no focused\n//       annotation.\n//       Must call FPDFPage_CloseAnnot() when the annotation returned in |annot|\n//       by this function is no longer needed.\n//       This will return true and set |page_index| to -1 and |annot| to NULL,\n//       if there is no focused annotation.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_GetFocusedAnnot(FPDF_FORMHANDLE handle,\n                     int* page_index,\n                     FPDF_ANNOTATION* annot);\n\n// Experimental API.\n// Function: FORM_SetFocusedAnnot.\n//       Call this member function to set the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       annot       -   Handle to an annotation.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus()\n//       instead.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot);\n\n// Form Field Types\n// The names of the defines are stable, but the specific values associated with\n// them are not, so do not hardcode their values.\n#define FPDF_FORMFIELD_UNKNOWN 0      // Unknown.\n#define FPDF_FORMFIELD_PUSHBUTTON 1   // push button type.\n#define FPDF_FORMFIELD_CHECKBOX 2     // check box type.\n#define FPDF_FORMFIELD_RADIOBUTTON 3  // radio button type.\n#define FPDF_FORMFIELD_COMBOBOX 4     // combo box type.\n#define FPDF_FORMFIELD_LISTBOX 5      // list box type.\n#define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.\n#define FPDF_FORMFIELD_SIGNATURE 7    // text field type.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_XFA 8              // Generic XFA type.\n#define FPDF_FORMFIELD_XFA_CHECKBOX 9     // XFA check box type.\n#define FPDF_FORMFIELD_XFA_COMBOBOX 10    // XFA combo box type.\n#define FPDF_FORMFIELD_XFA_IMAGEFIELD 11  // XFA image field type.\n#define FPDF_FORMFIELD_XFA_LISTBOX 12     // XFA list box type.\n#define FPDF_FORMFIELD_XFA_PUSHBUTTON 13  // XFA push button type.\n#define FPDF_FORMFIELD_XFA_SIGNATURE 14   // XFA signture field type.\n#define FPDF_FORMFIELD_XFA_TEXTFIELD 15   // XFA text field type.\n#endif                                    // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 16\n#else  // PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 8\n#endif  // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define IS_XFA_FORMFIELD(type)                  \\\n  (((type) == FPDF_FORMFIELD_XFA) ||            \\\n   ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \\\n   ((type) == FPDF_FORMFIELD_XFA_LISTBOX) ||    \\\n   ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \\\n   ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) ||  \\\n   ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD))\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDFPage_HasFormFieldAtPoint\n//     Get the form field type by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the type of the form field; -1 indicates no field.\n//     See field types above.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             double page_x,\n                             double page_y);\n\n// Function: FPDFPage_FormFieldZOrderAtPoint\n//     Get the form field z-order by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the z-order of the form field; -1 indicates no field.\n//     Higher numbers are closer to the front.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,\n                                FPDF_PAGE page,\n                                double page_x,\n                                double page_y);\n\n// Function: FPDF_SetFormFieldHighlightColor\n//       Set the highlight color of the specified (or all) form fields\n//       in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returned by\n//                       FPDF_LoadDocument().\n//       fieldType   -   A 32-bit integer indicating the type of a form\n//                       field (defined above).\n//       color       -   The highlight color of the form field. Constructed by\n//                       0xxxrrggbb.\n// Return Value:\n//       None.\n// Comments:\n//       When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the\n//       highlight color will be applied to all the form fields in the\n//       document.\n//       Please refresh the client window to show the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,\n                                int fieldType,\n                                unsigned long color);\n\n// Function: FPDF_SetFormFieldHighlightAlpha\n//       Set the transparency of the form field highlight color in the\n//       document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returaned by\n//                       FPDF_LoadDocument().\n//       alpha       -   The transparency of the form field highlight color,\n//                       between 0-255.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha);\n\n// Function: FPDF_RemoveFormFieldHighlight\n//       Remove the form field highlight color in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       Please refresh the client window to remove the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle);\n\n// Function: FPDF_FFLDraw\n//       Render FormFields and popup window on a page to a device independent\n//       bitmap.\n// Parameters:\n//       hHandle      -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n//       bitmap       -   Handle to the device independent bitmap (as the\n//                        output buffer). Bitmap handles can be created by\n//                        FPDFBitmap_Create().\n//       page         -   Handle to the page, as returned by FPDF_LoadPage().\n//       start_x      -   Left pixel position of the display area in the\n//                        device coordinates.\n//       start_y      -   Top pixel position of the display area in the device\n//                        coordinates.\n//       size_x       -   Horizontal size (in pixels) for displaying the page.\n//       size_y       -   Vertical size (in pixels) for displaying the page.\n//       rotate       -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                        clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                        degrees counter-clockwise).\n//       flags        -   0 for normal display, or combination of flags\n//                        defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This function is designed to render annotations that are\n//       user-interactive, which are widget annotations (for FormFields) and\n//       popup annotations.\n//       With the FPDF_ANNOT flag, this function will render a popup annotation\n//       when users mouse-hover on a non-widget annotation. Regardless of\n//       FPDF_ANNOT flag, this function will always render widget annotations\n//       for FormFields.\n//       In order to implement the FormFill functions, implementation should\n//       call this function after rendering functions, such as\n//       FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have\n//       finished rendering the page contents.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,\n                                            FPDF_BITMAP bitmap,\n                                            FPDF_PAGE page,\n                                            int start_x,\n                                            int start_y,\n                                            int size_x,\n                                            int size_y,\n                                            int rotate,\n                                            int flags);\n\n#if defined(PDF_USE_SKIA)\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,\n                                                FPDF_SKIA_CANVAS canvas,\n                                                FPDF_PAGE page,\n                                                int start_x,\n                                                int start_y,\n                                                int size_x,\n                                                int size_y,\n                                                int rotate,\n                                                int flags);\n#endif\n\n// Experimental API\n// Function: FPDF_GetFormType\n//           Returns the type of form contained in the PDF document.\n// Parameters:\n//           document - Handle to document.\n// Return Value:\n//           Integer value representing one of the FORMTYPE_ values.\n// Comments:\n//           If |document| is NULL, then the return value is FORMTYPE_NONE.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document);\n\n// Experimental API\n// Function: FORM_SetIndexSelected\n//           Selects/deselects the value at the given |index| of the focused\n//           annotation.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based index of value to be set as\n//                           selected/unselected\n//           selected    -   true to select, false to deselect\n// Return Value:\n//           TRUE if the operation succeeded.\n//           FALSE if the operation failed or widget is not a supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Comboboxes\n//           have at most a single value selected at a time which cannot be\n//           deselected. Deselect on a combobox is a no-op that returns false.\n//           Default implementation is a no-op that will return false for\n//           other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetIndexSelected(FPDF_FORMHANDLE hHandle,\n                      FPDF_PAGE page,\n                      int index,\n                      FPDF_BOOL selected);\n\n// Experimental API\n// Function: FORM_IsIndexSelected\n//           Returns whether or not the value at |index| of the focused\n//           annotation is currently selected.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based Index of value to check\n// Return Value:\n//           TRUE if value at |index| is currently selected.\n//           FALSE if value at |index| is not selected or widget is not a\n//           supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Default\n//           implementation is a no-op that will return false for other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index);\n\n// Function: FPDF_LoadXFA\n//          If the document consists of XFA fields, call this method to\n//          attempt to load XFA fields.\n// Parameters:\n//          document     -   Handle to document from FPDF_LoadDocument().\n// Return Value:\n//          TRUE upon success, otherwise FALSE. If XFA support is not built\n//          into PDFium, performs no action and always returns FALSE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_FORMFILL_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_fwlevent.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FWLEVENT_H_\n#define PUBLIC_FPDF_FWLEVENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Key flags.\ntypedef enum {\n  FWL_EVENTFLAG_ShiftKey = 1 << 0,\n  FWL_EVENTFLAG_ControlKey = 1 << 1,\n  FWL_EVENTFLAG_AltKey = 1 << 2,\n  FWL_EVENTFLAG_MetaKey = 1 << 3,\n  FWL_EVENTFLAG_KeyPad = 1 << 4,\n  FWL_EVENTFLAG_AutoRepeat = 1 << 5,\n  FWL_EVENTFLAG_LeftButtonDown = 1 << 6,\n  FWL_EVENTFLAG_MiddleButtonDown = 1 << 7,\n  FWL_EVENTFLAG_RightButtonDown = 1 << 8,\n} FWL_EVENTFLAG;\n\n// Virtual keycodes.\ntypedef enum {\n  FWL_VKEY_Back = 0x08,\n  FWL_VKEY_Tab = 0x09,\n  FWL_VKEY_NewLine = 0x0A,\n  FWL_VKEY_Clear = 0x0C,\n  FWL_VKEY_Return = 0x0D,\n  FWL_VKEY_Shift = 0x10,\n  FWL_VKEY_Control = 0x11,\n  FWL_VKEY_Menu = 0x12,\n  FWL_VKEY_Pause = 0x13,\n  FWL_VKEY_Capital = 0x14,\n  FWL_VKEY_Kana = 0x15,\n  FWL_VKEY_Hangul = 0x15,\n  FWL_VKEY_Junja = 0x17,\n  FWL_VKEY_Final = 0x18,\n  FWL_VKEY_Hanja = 0x19,\n  FWL_VKEY_Kanji = 0x19,\n  FWL_VKEY_Escape = 0x1B,\n  FWL_VKEY_Convert = 0x1C,\n  FWL_VKEY_NonConvert = 0x1D,\n  FWL_VKEY_Accept = 0x1E,\n  FWL_VKEY_ModeChange = 0x1F,\n  FWL_VKEY_Space = 0x20,\n  FWL_VKEY_Prior = 0x21,\n  FWL_VKEY_Next = 0x22,\n  FWL_VKEY_End = 0x23,\n  FWL_VKEY_Home = 0x24,\n  FWL_VKEY_Left = 0x25,\n  FWL_VKEY_Up = 0x26,\n  FWL_VKEY_Right = 0x27,\n  FWL_VKEY_Down = 0x28,\n  FWL_VKEY_Select = 0x29,\n  FWL_VKEY_Print = 0x2A,\n  FWL_VKEY_Execute = 0x2B,\n  FWL_VKEY_Snapshot = 0x2C,\n  FWL_VKEY_Insert = 0x2D,\n  FWL_VKEY_Delete = 0x2E,\n  FWL_VKEY_Help = 0x2F,\n  FWL_VKEY_0 = 0x30,\n  FWL_VKEY_1 = 0x31,\n  FWL_VKEY_2 = 0x32,\n  FWL_VKEY_3 = 0x33,\n  FWL_VKEY_4 = 0x34,\n  FWL_VKEY_5 = 0x35,\n  FWL_VKEY_6 = 0x36,\n  FWL_VKEY_7 = 0x37,\n  FWL_VKEY_8 = 0x38,\n  FWL_VKEY_9 = 0x39,\n  FWL_VKEY_A = 0x41,\n  FWL_VKEY_B = 0x42,\n  FWL_VKEY_C = 0x43,\n  FWL_VKEY_D = 0x44,\n  FWL_VKEY_E = 0x45,\n  FWL_VKEY_F = 0x46,\n  FWL_VKEY_G = 0x47,\n  FWL_VKEY_H = 0x48,\n  FWL_VKEY_I = 0x49,\n  FWL_VKEY_J = 0x4A,\n  FWL_VKEY_K = 0x4B,\n  FWL_VKEY_L = 0x4C,\n  FWL_VKEY_M = 0x4D,\n  FWL_VKEY_N = 0x4E,\n  FWL_VKEY_O = 0x4F,\n  FWL_VKEY_P = 0x50,\n  FWL_VKEY_Q = 0x51,\n  FWL_VKEY_R = 0x52,\n  FWL_VKEY_S = 0x53,\n  FWL_VKEY_T = 0x54,\n  FWL_VKEY_U = 0x55,\n  FWL_VKEY_V = 0x56,\n  FWL_VKEY_W = 0x57,\n  FWL_VKEY_X = 0x58,\n  FWL_VKEY_Y = 0x59,\n  FWL_VKEY_Z = 0x5A,\n  FWL_VKEY_LWin = 0x5B,\n  FWL_VKEY_Command = 0x5B,\n  FWL_VKEY_RWin = 0x5C,\n  FWL_VKEY_Apps = 0x5D,\n  FWL_VKEY_Sleep = 0x5F,\n  FWL_VKEY_NumPad0 = 0x60,\n  FWL_VKEY_NumPad1 = 0x61,\n  FWL_VKEY_NumPad2 = 0x62,\n  FWL_VKEY_NumPad3 = 0x63,\n  FWL_VKEY_NumPad4 = 0x64,\n  FWL_VKEY_NumPad5 = 0x65,\n  FWL_VKEY_NumPad6 = 0x66,\n  FWL_VKEY_NumPad7 = 0x67,\n  FWL_VKEY_NumPad8 = 0x68,\n  FWL_VKEY_NumPad9 = 0x69,\n  FWL_VKEY_Multiply = 0x6A,\n  FWL_VKEY_Add = 0x6B,\n  FWL_VKEY_Separator = 0x6C,\n  FWL_VKEY_Subtract = 0x6D,\n  FWL_VKEY_Decimal = 0x6E,\n  FWL_VKEY_Divide = 0x6F,\n  FWL_VKEY_F1 = 0x70,\n  FWL_VKEY_F2 = 0x71,\n  FWL_VKEY_F3 = 0x72,\n  FWL_VKEY_F4 = 0x73,\n  FWL_VKEY_F5 = 0x74,\n  FWL_VKEY_F6 = 0x75,\n  FWL_VKEY_F7 = 0x76,\n  FWL_VKEY_F8 = 0x77,\n  FWL_VKEY_F9 = 0x78,\n  FWL_VKEY_F10 = 0x79,\n  FWL_VKEY_F11 = 0x7A,\n  FWL_VKEY_F12 = 0x7B,\n  FWL_VKEY_F13 = 0x7C,\n  FWL_VKEY_F14 = 0x7D,\n  FWL_VKEY_F15 = 0x7E,\n  FWL_VKEY_F16 = 0x7F,\n  FWL_VKEY_F17 = 0x80,\n  FWL_VKEY_F18 = 0x81,\n  FWL_VKEY_F19 = 0x82,\n  FWL_VKEY_F20 = 0x83,\n  FWL_VKEY_F21 = 0x84,\n  FWL_VKEY_F22 = 0x85,\n  FWL_VKEY_F23 = 0x86,\n  FWL_VKEY_F24 = 0x87,\n  FWL_VKEY_NunLock = 0x90,\n  FWL_VKEY_Scroll = 0x91,\n  FWL_VKEY_LShift = 0xA0,\n  FWL_VKEY_RShift = 0xA1,\n  FWL_VKEY_LControl = 0xA2,\n  FWL_VKEY_RControl = 0xA3,\n  FWL_VKEY_LMenu = 0xA4,\n  FWL_VKEY_RMenu = 0xA5,\n  FWL_VKEY_BROWSER_Back = 0xA6,\n  FWL_VKEY_BROWSER_Forward = 0xA7,\n  FWL_VKEY_BROWSER_Refresh = 0xA8,\n  FWL_VKEY_BROWSER_Stop = 0xA9,\n  FWL_VKEY_BROWSER_Search = 0xAA,\n  FWL_VKEY_BROWSER_Favorites = 0xAB,\n  FWL_VKEY_BROWSER_Home = 0xAC,\n  FWL_VKEY_VOLUME_Mute = 0xAD,\n  FWL_VKEY_VOLUME_Down = 0xAE,\n  FWL_VKEY_VOLUME_Up = 0xAF,\n  FWL_VKEY_MEDIA_NEXT_Track = 0xB0,\n  FWL_VKEY_MEDIA_PREV_Track = 0xB1,\n  FWL_VKEY_MEDIA_Stop = 0xB2,\n  FWL_VKEY_MEDIA_PLAY_Pause = 0xB3,\n  FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4,\n  FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5,\n  FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6,\n  FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7,\n  FWL_VKEY_OEM_1 = 0xBA,\n  FWL_VKEY_OEM_Plus = 0xBB,\n  FWL_VKEY_OEM_Comma = 0xBC,\n  FWL_VKEY_OEM_Minus = 0xBD,\n  FWL_VKEY_OEM_Period = 0xBE,\n  FWL_VKEY_OEM_2 = 0xBF,\n  FWL_VKEY_OEM_3 = 0xC0,\n  FWL_VKEY_OEM_4 = 0xDB,\n  FWL_VKEY_OEM_5 = 0xDC,\n  FWL_VKEY_OEM_6 = 0xDD,\n  FWL_VKEY_OEM_7 = 0xDE,\n  FWL_VKEY_OEM_8 = 0xDF,\n  FWL_VKEY_OEM_102 = 0xE2,\n  FWL_VKEY_ProcessKey = 0xE5,\n  FWL_VKEY_Packet = 0xE7,\n  FWL_VKEY_Attn = 0xF6,\n  FWL_VKEY_Crsel = 0xF7,\n  FWL_VKEY_Exsel = 0xF8,\n  FWL_VKEY_Ereof = 0xF9,\n  FWL_VKEY_Play = 0xFA,\n  FWL_VKEY_Zoom = 0xFB,\n  FWL_VKEY_NoName = 0xFC,\n  FWL_VKEY_PA1 = 0xFD,\n  FWL_VKEY_OEM_Clear = 0xFE,\n  FWL_VKEY_Unknown = 0,\n} FWL_VKEYCODE;\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FWLEVENT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_javascript.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_JAVASCRIPT_H_\n#define PUBLIC_FPDF_JAVASCRIPT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of JavaScript actions in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of JavaScript actions in |document| or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the JavaScript action at |index| in |document|.\n//\n//   document - handle to a document.\n//   index    - the index of the requested JavaScript action.\n//\n// Returns the handle to the JavaScript action, or NULL on failure.\n// Caller owns the returned handle and must close it with\n// FPDFDoc_CloseJavaScriptAction().\nFPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV\nFPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Close a loaded FPDF_JAVASCRIPT_ACTION object.\n\n//   javascript - Handle to a JavaScript action.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript);\n\n// Experimental API.\n// Get the name from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the name. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript,\n                             FPDF_WCHAR* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Get the script from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the script. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript,\n                               FPDF_WCHAR* buffer,\n                               unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_JAVASCRIPT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_ppo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PPO_H_\n#define PUBLIC_FPDF_PPO_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc     - The destination document for the pages.\n//   src_doc      - The document to be imported.\n//   page_indices - An array of page indices to be imported. The first page is\n//                  zero. If |page_indices| is NULL, all pages from |src_doc|\n//                  are imported.\n//   length       - The length of the |page_indices| array.\n//   index        - The page index at which to insert the first imported page\n//                  into |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |page_indices| is\n// invalid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        const int* page_indices,\n                        unsigned long length,\n                        int index);\n\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc  - The destination document for the pages.\n//   src_doc   - The document to be imported.\n//   pagerange - A page range string, Such as \"1,3,5-7\". The first page is one.\n//               If |pagerange| is NULL, all pages from |src_doc| are imported.\n//   index     - The page index at which to insert the first imported page into\n//               |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |pagerange| is\n// invalid or if |pagerange| cannot be read.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,\n                                                     FPDF_DOCUMENT src_doc,\n                                                     FPDF_BYTESTRING pagerange,\n                                                     int index);\n\n// Experimental API.\n// Create a new document from |src_doc|.  The pages of |src_doc| will be\n// combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per\n// |output_doc| page.\n//\n//   src_doc             - The document to be imported.\n//   output_width        - The output page width in PDF \"user space\" units.\n//   output_height       - The output page height in PDF \"user space\" units.\n//   num_pages_on_x_axis - The number of pages on X Axis.\n//   num_pages_on_y_axis - The number of pages on Y Axis.\n//\n// Return value:\n//   A handle to the created document, or NULL on failure.\n//\n// Comments:\n//   number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis\n//\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,\n                       float output_width,\n                       float output_height,\n                       size_t num_pages_on_x_axis,\n                       size_t num_pages_on_y_axis);\n\n// Experimental API.\n// Create a template to generate form xobjects from |src_doc|'s page at\n// |src_page_index|, for use in |dest_doc|.\n//\n// Returns a handle on success, or NULL on failure. Caller owns the newly\n// created object.\nFPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV\nFPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        int src_page_index);\n\n// Experimental API.\n// Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage().\n// FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject);\n\n// Experimental API.\n// Create a new form object from an FPDF_XOBJECT object.\n//\n// Returns a new form object on success, or NULL on failure. Caller owns the\n// newly created object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject);\n\n// Copy the viewer preferences from |src_doc| into |dest_doc|.\n//\n//   dest_doc - Document to write the viewer preferences into.\n//   src_doc  - Document to read the viewer preferences from.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_PPO_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_progressive.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PROGRESSIVE_H_\n#define PUBLIC_FPDF_PROGRESSIVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flags for progressive process status.\n#define FPDF_RENDER_READY 0\n#define FPDF_RENDER_TOBECONTINUED 1\n#define FPDF_RENDER_DONE 2\n#define FPDF_RENDER_FAILED 3\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// IFPDF_RENDERINFO interface.\ntypedef struct _IFSDK_PAUSE {\n  // Version number of the interface. Currently must be 1.\n  int version;\n\n  // Method: NeedToPauseNow\n  //           Check if we need to pause a progressive process now.\n  // Interface Version:\n  //           1\n  // Implementation Required:\n  //           yes\n  // Parameters:\n  //           pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //           Non-zero for pause now, 0 for continue.\n  FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis);\n\n  // A user defined data pointer, used by user's application. Can be NULL.\n  void* user;\n} IFSDK_PAUSE;\n\n// Experimental API.\n// Function: FPDF_RenderPageBitmapWithColorScheme_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively with a specified color scheme for the content.\n// Parameters:\n//          bitmap       -   Handle to the device independent bitmap (as the\n//                           output buffer). Bitmap handle can be created by\n//                           FPDFBitmap_Create function.\n//          page         -   Handle to the page as returned by FPDF_LoadPage\n//                           function.\n//          start_x      -   Left pixel position of the display area in the\n//                           bitmap coordinate.\n//          start_y      -   Top pixel position of the display area in the\n//                           bitmap coordinate.\n//          size_x       -   Horizontal size (in pixels) for displaying the\n//                           page.\n//          size_y       -   Vertical size (in pixels) for displaying the page.\n//          rotate       -   Page orientation: 0 (normal), 1 (rotated 90\n//                           degrees clockwise), 2 (rotated 180 degrees),\n//                           3 (rotated 90 degrees counter-clockwise).\n//          flags        -   0 for normal display, or combination of flags\n//                           defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                           renders all annotations that does not require\n//                           user-interaction, which are all annotations except\n//                           widget and popup annotations.\n//          color_scheme -   Color scheme to be used in rendering the |page|.\n//                           If null, this function will work similar to\n//                           FPDF_RenderPageBitmap_Start().\n//          pause        -   The IFSDK_PAUSE interface. A callback mechanism\n//                           allowing the page rendering process.\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap,\n                                           FPDF_PAGE page,\n                                           int start_x,\n                                           int start_y,\n                                           int size_x,\n                                           int size_y,\n                                           int rotate,\n                                           int flags,\n                                           const FPDF_COLORSCHEME* color_scheme,\n                                           IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPageBitmap_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). Bitmap handle can be created by\n//                          FPDFBitmap_Create().\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          start_x     -   Left pixel position of the display area in the\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in the bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                          clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                          degrees counter-clockwise).\n//          flags       -   0 for normal display, or combination of flags\n//                          defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                          renders all annotations that does not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n//          pause       -   The IFSDK_PAUSE interface.A callback mechanism\n//                          allowing the page rendering process\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,\n                                                          FPDF_PAGE page,\n                                                          int start_x,\n                                                          int start_y,\n                                                          int size_x,\n                                                          int size_y,\n                                                          int rotate,\n                                                          int flags,\n                                                          IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Continue\n//          Continue rendering a PDF page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          pause       -   The IFSDK_PAUSE interface (a callback mechanism\n//                          allowing the page rendering process to be paused\n//                          before it's finished). This can be NULL if you\n//                          don't want to pause.\n// Return value:\n//          The rendering status. See flags for progressive process status for\n//          the details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page,\n                                                       IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Close\n//          Release the resource allocate during page rendering. Need to be\n//          called after finishing rendering or\n//          cancel the rendering.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_PROGRESSIVE_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_save.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SAVE_H_\n#define PUBLIC_FPDF_SAVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Structure for custom file write\ntypedef struct FPDF_FILEWRITE_ {\n  //\n  // Version number of the interface. Currently must be 1.\n  //\n  int version;\n\n  // Method: WriteBlock\n  //          Output a block of data in your custom way.\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          Yes\n  // Comments:\n  //          Called by function FPDF_SaveDocument\n  // Parameters:\n  //          self        -   Pointer to the structure itself\n  //          data        -   Pointer to a buffer to output\n  //          size        -   The size of the buffer.\n  // Return value:\n  //          Should be non-zero if successful, zero for error.\n  int (*WriteBlock)(struct FPDF_FILEWRITE_* self,\n                    const void* data,\n                    unsigned long size);\n} FPDF_FILEWRITE;\n\n// Flags for FPDF_SaveAsCopy().\n// FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together.\n#define FPDF_INCREMENTAL (1 << 0)\n#define FPDF_NO_INCREMENTAL (1 << 1)\n // Deprecated. Use FPDF_REMOVE_SECURITY instead.\n // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED.\n#define FPDF_REMOVE_SECURITY_DEPRECATED 3\n#define FPDF_REMOVE_SECURITY (1 << 2)\n// Experimental. Subsets any embedded font files for new text objects added to\n// the document.\n#define FPDF_SUBSET_NEW_FONTS (1 << 3)\n\n// Function: FPDF_SaveAsCopy\n//          Saves the copy of specified document in custom way.\n// Parameters:\n//          document        -   Handle to document, as returned by\n//                              FPDF_LoadDocument() or FPDF_CreateNewDocument().\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   Flags above that affect how the PDF gets saved.\n//                              Pass in 0 when there are no flags.\n// Return value:\n//          TRUE for succeed, FALSE for failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,\n                                                    FPDF_FILEWRITE* file_write,\n                                                    FPDF_DWORD flags);\n\n// Function: FPDF_SaveWithVersion\n//          Same as FPDF_SaveAsCopy(), except the file version of the\n//          saved document can be specified by the caller.\n// Parameters:\n//          document        -   Handle to document.\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   The creating flags.\n//          file_version    -   The PDF file version. File version: 14 for 1.4,\n//                              15 for 1.5, ...\n// Return value:\n//          TRUE if succeed, FALSE if failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_SaveWithVersion(FPDF_DOCUMENT document,\n                     FPDF_FILEWRITE* file_write,\n                     FPDF_DWORD flags,\n                     int file_version);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SAVE_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_searchex.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SEARCHEX_H_\n#define PUBLIC_FPDF_SEARCHEX_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Get the character index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nTextIndex - index of the text returned from FPDFText_GetText().\n//\n// Returns the index of the character in internal character list. -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex);\n\n// Get the text index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nCharIndex - index of the character in internal character list.\n//\n// Returns the index of the text returned from FPDFText_GetText(). -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SEARCHEX_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_signature.h",
    "content": "// Copyright 2020 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_SIGNATURE_H_\n#define PUBLIC_FPDF_SIGNATURE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Function: FPDF_GetSignatureCount\n//          Get total number of signatures in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n// Return value:\n//          Total number of signatures in the document on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetSignatureObject\n//          Get the Nth signature of the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          index       -   Index into the array of signatures of the document.\n// Return value:\n//          Returns the handle to the signature, or NULL on failure. The caller\n//          does not take ownership of the returned FPDF_SIGNATURE. Instead, it\n//          remains valid until FPDF_CloseDocument() is called for the document.\nFPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV\nFPDF_GetSignatureObject(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetContents\n//          Get the contents of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the contents.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the contents on success, 0 on error.\n//\n// For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or\n// a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetContents(FPDF_SIGNATURE signature,\n                             void* buffer,\n                             unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetByteRange\n//          Get the byte range of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the\n//                          byte range.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the byte range on\n//          success, 0 on error.\n//\n// |buffer| is an array of pairs of integers (starting byte offset,\n// length in bytes) that describes the exact byte range for the digest\n// calculation. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,\n                              int* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetSubFilter\n//          Get the encoding of the value of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the encoding.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature,\n                              char* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetReason\n//          Get the reason (comment) of the signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the reason.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the reason on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetReason(FPDF_SIGNATURE signature,\n                           void* buffer,\n                           unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetTime\n//          Get the time of signing of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the time.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's\n// percision is seconds, with timezone information. This value should be used\n// only when the time of signing is not available in the (PKCS#7 binary)\n// signature.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetTime(FPDF_SIGNATURE signature,\n                         char* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetDocMDPPermission\n//          Get the DocMDP permission of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n// Return value:\n//          Returns the permission (1, 2 or 3) on success, 0 on error.\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SIGNATURE_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_structtree.h",
    "content": "// Copyright 2016 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_STRUCTTREE_H_\n#define PUBLIC_FPDF_STRUCTTREE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDF_StructTree_GetForPage\n//          Get the structure tree for a page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          A handle to the structure tree or NULL on error. The caller owns the\n//          returned handle and must use FPDF_StructTree_Close() to release it.\n//          The handle should be released before |page| gets released.\nFPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV\nFPDF_StructTree_GetForPage(FPDF_PAGE page);\n\n// Function: FPDF_StructTree_Close\n//          Release a resource allocated by FPDF_StructTree_GetForPage().\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_CountChildren\n//          Count the number of children for the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_GetChildAtIndex\n//          Get a child in the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n//          index       -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error. The caller does not\n//          own the handle. The handle remains valid as long as |struct_tree|\n//          remains valid.\n// Comments:\n//          The |index| must be less than the FPDF_StructTree_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index);\n\n// Function: FPDF_StructElement_GetAltText\n//          Get the alt text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the alt text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the alt text, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetActualText\n//          Get the actual text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the actual text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the actual text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetExpansion\n//          Get the expansion of an abbreviation or acronym for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the expansion text. May be\n//                             NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the expansion text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element,\n                                void* buffer,\n                                unsigned long buflen);\n\n// Function: FPDF_StructElement_GetID\n//          Get the ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the ID string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,\n                         void* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetLang\n//          Get the case-insensitive IETF BCP 47 language code for an element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the lang string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetStringAttribute\n//          Get a struct element attribute of type \"name\" or \"string\".\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          attr_name      -   The name of the attribute to retrieve.\n//          buffer         -   A buffer for output. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the attribute value, including the\n//          terminating NUL character. The number of bytes is returned\n//          regardless of the |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,\n                                      FPDF_BYTESTRING attr_name,\n                                      void* buffer,\n                                      unsigned long buflen);\n\n// Function: FPDF_StructElement_GetMarkedContentID\n//          Get the marked content ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to\n//          extract more marked content IDs out of |struct_element|. This API\n//          may be deprecated in the future.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetType\n//           Get the type (/S) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the type, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetObjType\n//           Get the object type (/Type) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the object type, including the terminating\n//           NUL character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Function: FPDF_StructElement_GetTitle\n//           Get the title (/T) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the title, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Function: FPDF_StructElement_CountChildren\n//          Count the number of children for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetChildAtIndex\n//          Get a child in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error.\n// Comments:\n//          If the child exists but is not an element, then this function will\n//          return NULL. This will also return NULL for out of bounds indices.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                   int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetChildMarkedContentID\n//          Get the child's content id\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The marked content ID of the child. If no ID exists, returns -1.\n// Comments:\n//          If the child exists but is not a stream or object, then this\n//          function will return -1. This will also return -1 for out of bounds\n//          indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex,\n//          it is scoped to the current page.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element,\n                                           int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetParent\n//          Get the parent of the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The parent structure element or NULL on error.\n// Comments:\n//          If structure element is StructTreeRoot, then this function will\n//          return NULL.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetAttributeCount\n//          Count the number of attributes for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetAttributeAtIndex\n//          Get an attribute object in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the attribute object, 0-based.\n// Return value:\n//          The attribute object at the n-th index or NULL on error.\n// Comments:\n//          If the attribute object exists but is not a dict, then this\n//          function will return NULL. This will also return NULL for out of\n//          bounds indices. The caller does not own the handle. The handle\n//          remains valid as long as |struct_element| remains valid.\n//          The |index| must be less than the\n//          FPDF_StructElement_GetAttributeCount() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV\nFPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetCount\n//          Count the number of attributes in a structure element attribute map.\n// Parameters:\n//          struct_attribute - Handle to the struct element attribute.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute);\n\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetName\n//          Get the name of an attribute in a structure element attribute map.\n// Parameters:\n//          struct_attribute   - Handle to the struct element attribute.\n//          index              - The index of attribute in the map.\n//          buffer             - A buffer for output. May be NULL. This is only\n//                               modified if |buflen| is longer than the length\n//                               of the key. Optional, pass null to just\n//                               retrieve the size of the buffer needed.\n//          buflen             - The length of the buffer.\n//          out_buflen         - A pointer to variable that will receive the\n//                               minimum buffer size to contain the key. Not\n//                               filled if FALSE is returned.\n// Return value:\n//          TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                int index,\n                                void* buffer,\n                                unsigned long buflen,\n                                unsigned long* out_buflen);\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetValue\n//           Get a handle to a value for an attribute in a structure element\n//           attribute map.\n// Parameters:\n//           struct_attribute   - Handle to the struct element attribute.\n//           name               - The attribute name.\n// Return value:\n//           Returns a handle to the value associated with the input, if any.\n//           Returns NULL on failure. The caller does not own the handle.\n//           The handle remains valid as long as |struct_attribute| remains\n//           valid.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                 FPDF_BYTESTRING name);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetType\n//           Get the type of an attribute in a structure element attribute map.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of\n//           failure. Note that this will never return FPDF_OBJECT_REFERENCE, as\n//           references are always dereferenced.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBooleanValue\n//           Get the value of a boolean attribute in an attribute map as\n//           FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_BOOLEAN for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a boolean value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        FPDF_BOOL* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetNumberValue\n//           Get the value of a number attribute in an attribute map as float.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_NUMBER for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a number value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       float* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetStringValue\n//           Get the value of a string attribute in an attribute map as string.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned key in UTF-16LE.\n//                        This is only modified if |buflen| is longer than the\n//                        length of the key. Optional, pass null to just\n//                        retrieve the size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       void* buffer,\n                                       unsigned long buflen,\n                                       unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBlobValue\n//           Get the value of a blob attribute in an attribute map as string.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned value. This is only\n//                        modified if |buflen| is at least as long as the length\n//                        of the value. Optional, pass null to just retrieve the\n//                        size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                     void* buffer,\n                                     unsigned long buflen,\n                                     unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_CountChildren\n//           Count the number of children values in an attribute.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetChildAtIndex\n//           Get a child from an attribute.\n// Parameters:\n//           value - Handle to the value.\n//           index - The index for the child, 0-based.\n// Return value:\n//           The child at the n-th index or NULL on error.\n// Comments:\n//           The |index| must be less than the\n//           FPDF_StructElement_Attr_CountChildren() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdCount\n//          Get the count of marked content ids for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The count of marked content ids or -1 if none exists.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdAtIndex\n//          Get the marked content id at a given index for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index of the marked content id, 0-based.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          The |index| must be less than the\n//          FPDF_StructElement_GetMarkedContentIdCount() return value.\n//          This will likely supersede FPDF_StructElement_GetMarkedContentID().\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                             int index);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n#endif  // PUBLIC_FPDF_STRUCTTREE_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_sysfontinfo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SYSFONTINFO_H_\n#define PUBLIC_FPDF_SYSFONTINFO_H_\n\n#include <stddef.h>\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Character sets for the font\n#define FXFONT_ANSI_CHARSET 0\n#define FXFONT_DEFAULT_CHARSET 1\n#define FXFONT_SYMBOL_CHARSET 2\n#define FXFONT_SHIFTJIS_CHARSET 128\n#define FXFONT_HANGEUL_CHARSET 129\n#define FXFONT_GB2312_CHARSET 134\n#define FXFONT_CHINESEBIG5_CHARSET 136\n#define FXFONT_GREEK_CHARSET 161\n#define FXFONT_VIETNAMESE_CHARSET 163\n#define FXFONT_HEBREW_CHARSET 177\n#define FXFONT_ARABIC_CHARSET 178\n#define FXFONT_CYRILLIC_CHARSET 204\n#define FXFONT_THAI_CHARSET 222\n#define FXFONT_EASTERNEUROPEAN_CHARSET 238\n\n// Font pitch and family flags\n#define FXFONT_FF_FIXEDPITCH (1 << 0)\n#define FXFONT_FF_ROMAN (1 << 4)\n#define FXFONT_FF_SCRIPT (4 << 4)\n\n// Typical weight values\n#define FXFONT_FW_NORMAL 400\n#define FXFONT_FW_BOLD 700\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Interface: FPDF_SYSFONTINFO\n//          Interface for getting system font information and font mapping\ntypedef struct _FPDF_SYSFONTINFO {\n  // Version number of the interface. Currently must be 1 or 2.\n  // Version 1: Traditional behavior - calls EnumFonts during initialization.\n  // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont.\n  //            Experimental: Subject to change based on feedback.\n  int version;\n\n  // Method: Release\n  //          Give implementation a chance to release any data after the\n  //          interface is no longer used.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //          None\n  // Comments:\n  //          Called by PDFium during the final cleanup process.\n  void (*Release)(struct _FPDF_SYSFONTINFO* pThis);\n\n  // Method: EnumFonts\n  //          Enumerate all fonts installed on the system\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          pMapper     -   An opaque pointer to internal font mapper, used\n  //                          when calling FPDF_AddInstalledFont().\n  // Return Value:\n  //          None\n  // Comments:\n  //          Implementations should call FPDF_AddInstalledFont() function for\n  //          each font found. Only TrueType/OpenType and Type1 fonts are\n  //          accepted by PDFium.\n  //          NOTE: This method will not be called when version is set to 2.\n  //          Version 2 relies entirely on MapFont() for per-request matching.\n  void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper);\n\n  // Method: MapFont\n  //          Use the system font mapper to get a font handle from requested\n  //          parameters.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if GetFont method is not implemented.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          weight      -   Weight of the requested font. 400 is normal and\n  //                          700 is bold.\n  //          bItalic     -   Italic option of the requested font, TRUE or\n  //                          FALSE.\n  //          charset     -   Character set identifier for the requested font.\n  //                          See above defined constants.\n  //          pitch_family -  A combination of flags. See above defined\n  //                          constants.\n  //          face        -   Typeface name. Currently use system local encoding\n  //                          only.\n  //          bExact      -   Obsolete: this parameter is now ignored.\n  // Return Value:\n  //          An opaque pointer for font handle, or NULL if system mapping is\n  //          not supported.\n  // Comments:\n  //          If the system supports native font mapper (like Windows),\n  //          implementation can implement this method to get a font handle.\n  //          Otherwise, PDFium will do the mapping and then call GetFont\n  //          method. Only TrueType/OpenType and Type1 fonts are accepted\n  //          by PDFium.\n  void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis,\n                   int weight,\n                   FPDF_BOOL bItalic,\n                   int charset,\n                   int pitch_family,\n                   const char* face,\n                   FPDF_BOOL* bExact);\n\n  // Method: GetFont\n  //          Get a handle to a particular font by its internal ID\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if MapFont method is not implemented.\n  // Return Value:\n  //          An opaque pointer for font handle.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          face        -   Typeface name in system local encoding.\n  // Comments:\n  //          If the system mapping not supported, PDFium will do the font\n  //          mapping and use this method to get a font handle.\n  void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face);\n\n  // Method: GetFontData\n  //          Get font data from a font\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          table       -   TrueType/OpenType table identifier (refer to\n  //                          TrueType specification), or 0 for the whole file.\n  //          buffer      -   The buffer receiving the font data. Can be NULL if\n  //                          not provided.\n  //          buf_size    -   Buffer size, can be zero if not provided.\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  // Comments:\n  //          Can read either the full font file, or a particular\n  //          TrueType/OpenType table.\n  unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               unsigned int table,\n                               unsigned char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFaceName\n  //          Get face name from a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          buffer      -   The buffer receiving the face name. Can be NULL if\n  //                          not provided\n  //          buf_size    -   Buffer size, can be zero if not provided\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFontCharset\n  //          Get character set information for a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          Character set identifier. See defined constants above.\n  int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n\n  // Method: DeleteFont\n  //          Delete a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          None\n  void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n} FPDF_SYSFONTINFO;\n\n// Struct: FPDF_CharsetFontMap\n//    Provides the name of a font to use for a given charset value.\ntypedef struct FPDF_CharsetFontMap_ {\n  int charset;  // Character Set Enum value, see FXFONT_*_CHARSET above.\n  const char* fontname;  // Name of default font to use with that charset.\n} FPDF_CharsetFontMap;\n\n// Function: FPDF_GetDefaultTTFMap\n//    Returns a pointer to the default character set to TT Font name map. The\n//    map is an array of FPDF_CharsetFontMap structs, with its end indicated\n//    by a { -1, NULL } entry.\n// Parameters:\n//     None.\n// Return Value:\n//     Pointer to the Charset Font Map.\n// Note:\n//     Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no\n//     longer experimental, this API will be marked as deprecated.\n//     See https://crbug.com/348468114\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapCount\n//    Returns the number of entries in the default character set to TT Font name\n//    map.\n// Parameters:\n//    None.\n// Return Value:\n//    The number of entries in the map.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapEntry\n//    Returns an entry in the default character set to TT Font name map.\n// Parameters:\n//    index    -   The index to the entry in the map to retrieve.\n// Return Value:\n//     A pointer to the entry, if it is in the map, or NULL if the index is out\n//     of bounds.\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV\nFPDF_GetDefaultTTFMapEntry(size_t index);\n\n// Function: FPDF_AddInstalledFont\n//          Add a system font to the list in PDFium.\n// Comments:\n//          This function is only called during the system font list building\n//          process.\n// Parameters:\n//          mapper          -   Opaque pointer to Foxit font mapper\n//          face            -   The font face name\n//          charset         -   Font character set. See above defined constants.\n// Return Value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper,\n                                                     const char* face,\n                                                     int charset);\n\n// Function: FPDF_SetSystemFontInfo\n//          Set the system font info interface into PDFium\n// Parameters:\n//          font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//          None\n// Comments:\n//          Platform support implementation should implement required methods of\n//          FFDF_SYSFONTINFO interface, then call this function during PDFium\n//          initialization process.\n//\n//          Call this with NULL to tell PDFium to stop using a previously set\n//          |FPDF_SYSFONTINFO|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n// Function: FPDF_GetDefaultSystemFontInfo\n//          Get default system font info interface for current platform\n// Parameters:\n//          None\n// Return Value:\n//          Pointer to a FPDF_SYSFONTINFO structure describing the default\n//          interface, or NULL if the platform doesn't have a default interface.\n//          Application should call FPDF_FreeDefaultSystemFontInfo to free the\n//          returned pointer.\n// Comments:\n//          For some platforms, PDFium implements a default version of system\n//          font info interface. The default implementation can be passed to\n//          FPDF_SetSystemFontInfo().\nFPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo();\n\n// Function: FPDF_FreeDefaultSystemFontInfo\n//           Free a default system font info interface\n// Parameters:\n//           font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//           None\n// Comments:\n//           This function should be called on the output from\n//           FPDF_GetDefaultSystemFontInfo() once it is no longer needed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SYSFONTINFO_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_text.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TEXT_H_\n#define PUBLIC_FPDF_TEXT_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDFText_LoadPage\n//          Prepare information about all characters in a page.\n// Parameters:\n//          page    -   Handle to the page. Returned by FPDF_LoadPage function\n//                      (in FPDFVIEW module).\n// Return value:\n//          A handle to the text page information structure.\n//          NULL if something goes wrong.\n// Comments:\n//          Application must call FPDFText_ClosePage to release the text page\n//          information.\n//\nFPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page);\n\n// Function: FPDFText_ClosePage\n//          Release all resources allocated for a text page information\n//          structure.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_CountChars\n//          Get number of characters in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return value:\n//          Number of characters in the page. Return -1 for error.\n//          Generated characters, like additional space characters, new line\n//          characters, are also counted.\n// Comments:\n//          Characters in a page form a \"stream\", inside the stream, each\n//          character has an index.\n//          We will use the index parameters in many of FPDFTEXT functions. The\n//          first character in the page\n//          has an index value of zero.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_GetUnicode\n//          Get Unicode of a character in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The Unicode of the particular character.\n//          If a character is not encoded in Unicode and Foxit engine can't\n//          convert to Unicode,\n//          the return value will be zero.\n//\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_GetTextObject\n//          Get the FPDF_PAGEOBJECT associated with a given character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The associated text object for the character at |index|, or NULL on\n//          error. The returned text object, if non-null, is of type\n//          |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object.\n//\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsGenerated\n//          Get if a character in a page is generated by PDFium.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is generated by PDFium.\n//          0 if the character is not generated by PDFium.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsHyphen\n//          Get if a character in a page is a hyphen.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is a hyphen.\n//          0 if the character is not a hyphen.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_HasUnicodeMapError\n//          Get if a character in a page has an invalid unicode mapping.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character has an invalid unicode mapping.\n//          0 if the character has no known unicode mapping issues.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index);\n\n// Function: FPDFText_GetFontSize\n//          Get the font size of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The font size of the particular character, measured in points (about\n//          1/72 inch). This is the typographic size of the font (so called\n//          \"em size\").\n//\nFPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Experimental API.\n// Function: FPDFText_GetFontInfo\n//          Get the font name and flags of a particular character.\n// Parameters:\n//          text_page - Handle to a text page information structure.\n//                      Returned by FPDFText_LoadPage function.\n//          index     - Zero-based index of the character.\n//          buffer    - A buffer receiving the font name.\n//          buflen    - The length of |buffer| in bytes.\n//          flags     - Optional pointer to an int receiving the font flags.\n//                      These flags should be interpreted per PDF spec 1.7\n//                      Section 5.7.1 Font Descriptor Flags.\n// Return value:\n//          On success, return the length of the font name, including the\n//          trailing NUL character, in bytes. If this length is less than or\n//          equal to |length|, |buffer| is set to the font name, |flags| is\n//          set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on\n//          failure.\n//\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,\n                     int index,\n                     void* buffer,\n                     unsigned long buflen,\n                     int* flags);\n\n// Experimental API.\n// Function: FPDFText_GetFontWeight\n//          Get the font weight of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          On success, return the font weight of the particular character. If\n//          |text_page| is invalid, if |index| is out of bounds, or if the\n//          character's text object is undefined, return -1.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,\n                                                     int index);\n\n// Experimental API.\n// Function: FPDFText_GetFillColor\n//          Get the fill color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the fill color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the fill color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the fill color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the fill color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetFillColor(FPDF_TEXTPAGE text_page,\n                      int index,\n                      unsigned int* R,\n                      unsigned int* G,\n                      unsigned int* B,\n                      unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetStrokeColor\n//          Get the stroke color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the stroke color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the stroke color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the stroke color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the stroke color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,\n                        int index,\n                        unsigned int* R,\n                        unsigned int* G,\n                        unsigned int* B,\n                        unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetCharAngle\n//          Get character rotation angle.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return Value:\n//          On success, return the angle value in radian. Value will always be\n//          greater or equal to 0. If |text_page| is invalid, or if |index| is\n//          out of bounds, then return -1.\n//\nFPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Function: FPDFText_GetCharBox\n//          Get bounding box of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          left        -   Pointer to a double number receiving left position\n//                          of the character box.\n//          right       -   Pointer to a double number receiving right position\n//                          of the character box.\n//          bottom      -   Pointer to a double number receiving bottom position\n//                          of the character box.\n//          top         -   Pointer to a double number receiving top position of\n//                          the character box.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |right|, |bottom|, and\n//          |top|. If |text_page| is invalid, or if |index| is out of bounds,\n//          then return FALSE, and the out parameters remain unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,\n                                                        int index,\n                                                        double* left,\n                                                        double* right,\n                                                        double* bottom,\n                                                        double* top);\n\n// Experimental API.\n// Function: FPDFText_GetLooseCharBox\n//          Get a \"loose\" bounding box of a particular character, i.e., covering\n//          the entire glyph bounds, without taking the actual glyph shape into\n//          account.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          rect        -   Pointer to a FS_RECTF receiving the character box.\n// Return Value:\n//          On success, return TRUE and fill in |rect|. If |text_page| is\n//          invalid, or if |index| is out of bounds, then return FALSE, and the\n//          |rect| out parameter remains unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDFText_GetMatrix\n//          Get the effective transformation matrix for a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage().\n//          index       -   Zero-based index of the character.\n//          matrix      -   Pointer to a FS_MATRIX receiving the transformation\n//                          matrix.\n// Return Value:\n//          On success, return TRUE and fill in |matrix|. If |text_page| is\n//          invalid, or if |index| is out of bounds, or if |matrix| is NULL,\n//          then return FALSE, and |matrix| remains unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,\n                                                       int index,\n                                                       FS_MATRIX* matrix);\n\n// Function: FPDFText_GetCharOrigin\n//          Get origin of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          x           -   Pointer to a double number receiving x coordinate of\n//                          the character origin.\n//          y           -   Pointer to a double number receiving y coordinate of\n//                          the character origin.\n// Return Value:\n//          Whether the call succeeded. If false, x and y are unchanged.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,\n                       int index,\n                       double* x,\n                       double* y);\n\n// Function: FPDFText_GetCharIndexAtPos\n//          Get the index of a character at or nearby a certain position on the\n//          page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          x           -   X position in PDF \"user space\".\n//          y           -   Y position in PDF \"user space\".\n//          xTolerance  -   An x-axis tolerance value for character hit\n//                          detection, in point units.\n//          yTolerance  -   A y-axis tolerance value for character hit\n//                          detection, in point units.\n// Return Value:\n//          The zero-based index of the character at, or nearby the point (x,y).\n//          If there is no character at or nearby the point, return value will\n//          be -1. If an error occurs, -3 will be returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,\n                           double x,\n                           double y,\n                           double xTolerance,\n                           double yTolerance);\n\n// Function: FPDFText_GetText\n//          Extract unicode text string from the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start characters.\n//          count       -   Number of UCS-2 values to be extracted.\n//          result      -   A buffer (allocated by application) receiving the\n//                          extracted UCS-2 values. The buffer must be able to\n//                          hold `count` UCS-2 values plus a terminator.\n// Return Value:\n//          Number of characters written into the result buffer, including the\n//          trailing terminator.\n// Comments:\n//          This function ignores characters without UCS-2 representations.\n//          It considers all characters on the page, even those that are not\n//          visible when the page has a cropbox. To filter out the characters\n//          outside of the cropbox, use FPDF_GetPageBoundingBox() and\n//          FPDFText_GetCharBox().\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page,\n                                               int start_index,\n                                               int count,\n                                               unsigned short* result);\n\n// Function: FPDFText_CountRects\n//          Counts number of rectangular areas occupied by a segment of text,\n//          and caches the result for subsequent FPDFText_GetRect() calls.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start character.\n//          count       -   Number of characters, or -1 for all remaining.\n// Return value:\n//          Number of rectangles, 0 if text_page is null, or -1 on bad\n//          start_index.\n// Comments:\n//          This function, along with FPDFText_GetRect can be used by\n//          applications to detect the position on the page for a text segment,\n//          so proper areas can be highlighted. The FPDFText_* functions will\n//          automatically merge small character boxes into bigger one if those\n//          characters are on the same line and use same font settings.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,\n                                                  int start_index,\n                                                  int count);\n\n// Function: FPDFText_GetRect\n//          Get a rectangular area from the result generated by\n//          FPDFText_CountRects.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          rect_index  -   Zero-based index for the rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |text_page| is invalid then return FALSE, and the out\n//          parameters remain unmodified. If |text_page| is valid but\n//          |rect_index| is out of bounds, then return FALSE and set the out\n//          parameters to 0.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Function: FPDFText_GetBoundedText\n//          Extract unicode text within a rectangular boundary on the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          left        -   Left boundary.\n//          top         -   Top boundary.\n//          right       -   Right boundary.\n//          bottom      -   Bottom boundary.\n//          buffer      -   Caller-allocated buffer to receive UTF-16 values.\n//          buflen      -   Number of UTF-16 values (not bytes) that `buffer`\n//                          is capable of holding.\n// Return Value:\n//          If buffer is NULL or buflen is zero, return number of UTF-16\n//          values (not bytes) of text present within the rectangle, excluding\n//          a terminating NUL. Generally you should pass a buffer at least one\n//          larger than this if you want a terminating NUL, which will be\n//          provided if space is available. Otherwise, return number of UTF-16\n//          values copied into the buffer, including the terminating NUL when\n//          space for it is available.\n// Comment:\n//          If the buffer is too small, as much text as will fit is copied into\n//          it. May return a split surrogate in that case.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,\n                                                      double left,\n                                                      double top,\n                                                      double right,\n                                                      double bottom,\n                                                      unsigned short* buffer,\n                                                      int buflen);\n\n// Flags used by FPDFText_FindStart function.\n//\n// If not set, it will not match case by default.\n#define FPDF_MATCHCASE 0x00000001\n// If not set, it will not match the whole word by default.\n#define FPDF_MATCHWHOLEWORD 0x00000002\n// If not set, it will skip past the current match to look for the next match.\n#define FPDF_CONSECUTIVE 0x00000004\n\n// Function: FPDFText_FindStart\n//          Start a search.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          findwhat    -   A unicode match pattern.\n//          flags       -   Option flags.\n//          start_index -   Start from this character. -1 for end of the page.\n// Return Value:\n//          A handle for the search context. FPDFText_FindClose must be called\n//          to release this handle.\n//\nFPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV\nFPDFText_FindStart(FPDF_TEXTPAGE text_page,\n                   FPDF_WIDESTRING findwhat,\n                   unsigned long flags,\n                   int start_index);\n\n// Function: FPDFText_FindNext\n//          Search in the direction from page start to end.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindPrev\n//          Search in the direction from page end to start.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchResultIndex\n//          Get the starting character index of the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Index for the starting character.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchCount\n//          Get the number of matched characters in the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Number of matched characters.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindClose\n//          Release a search context.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle);\n\n// Function: FPDFLink_LoadWebLinks\n//          Prepare information about weblinks in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          A handle to the page's links information structure, or\n//          NULL if something goes wrong.\n// Comments:\n//          Weblinks are those links implicitly embedded in PDF pages. PDF also\n//          has a type of annotation called \"link\" (FPDFTEXT doesn't deal with\n//          that kind of link). FPDFTEXT weblink feature is useful for\n//          automatically detecting links in the page contents. For example,\n//          things like \"https://www.example.com\" will be detected, so\n//          applications can allow user to click on those characters to activate\n//          the link, even the PDF doesn't come with link annotations.\n//\n//          FPDFLink_CloseWebLinks must be called to release resources.\n//\nFPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV\nFPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFLink_CountWebLinks\n//          Count number of detected web links.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          Number of detected web links.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page);\n\n// Function: FPDFLink_GetURL\n//          Fetch the URL information for a detected web link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          buffer      -   A unicode buffer for the result.\n//          buflen      -   Number of 16-bit code units (not bytes) for the\n//                          buffer, including an additional terminator.\n// Return Value:\n//          If |buffer| is NULL or |buflen| is zero, return the number of 16-bit\n//          code units (not bytes) needed to buffer the result (an additional\n//          terminator is included in this count).\n//          Otherwise, copy the result into |buffer|, truncating at |buflen| if\n//          the result is too large to fit, and return the number of 16-bit code\n//          units actually copied into the buffer (the additional terminator is\n//          also included in this count).\n//          If |link_index| does not correspond to a valid link, then the result\n//          is an empty string.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,\n                                              int link_index,\n                                              unsigned short* buffer,\n                                              int buflen);\n\n// Function: FPDFLink_CountRects\n//          Count number of rectangular areas for the link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n// Return Value:\n//          Number of rectangular areas for the link.  If |link_index| does\n//          not correspond to a valid link, then 0 is returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,\n                                                  int link_index);\n\n// Function: FPDFLink_GetRect\n//          Fetch the boundaries of a rectangle for a link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          rect_index  -   Zero-based index for a rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |link_page| is invalid or if |link_index| does not\n//          correspond to a valid link, then return FALSE, and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,\n                                                     int link_index,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Experimental API.\n// Function: FPDFLink_GetTextRange\n//          Fetch the start char index and char count for a link.\n// Parameters:\n//          link_page         -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index        -   Zero-based index for the link.\n//          start_char_index  -   pointer to int receiving the start char index\n//          char_count        -   pointer to int receiving the char count\n// Return Value:\n//          On success, return TRUE and fill in |start_char_index| and\n//          |char_count|. if |link_page| is invalid or if |link_index| does\n//          not correspond to a valid link, then return FALSE and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetTextRange(FPDF_PAGELINK link_page,\n                      int link_index,\n                      int* start_char_index,\n                      int* char_count);\n\n// Function: FPDFLink_CloseWebLinks\n//          Release resources used by weblink feature.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TEXT_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_thumbnail.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_THUMBNAIL_H_\n#define PUBLIC_FPDF_THUMBNAIL_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Gets the decoded data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| less than or equal to the\n// size of the decoded data. Returns the size of the decoded\n// data or 0 if thumbnail DNE. Optional, pass null to just retrieve\n// the size of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the decoded image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetDecodedThumbnailData(FPDF_PAGE page,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Gets the raw data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| is less than or equal to\n// the size of the raw data. Returns the size of the raw data or 0\n// if thumbnail DNE. Optional, pass null to just retrieve the size\n// of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the raw image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetRawThumbnailData(FPDF_PAGE page,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr\n// if unable to access the thumbnail's stream.\n//\n//   page - handle to a page.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_THUMBNAIL_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdf_transformpage.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_\n#define PUBLIC_FPDF_TRANSFORMPAGE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Set \"MediaBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"CropBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"BleedBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"TrimBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"ArtBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page,\n                                                  float left,\n                                                  float bottom,\n                                                  float right,\n                                                  float top);\n\n// Get \"MediaBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"CropBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"BleedBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"TrimBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"ArtBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page,\n                                                       float* left,\n                                                       float* bottom,\n                                                       float* right,\n                                                       float* top);\n\n// Apply transforms to |page|.\n//\n// If |matrix| is provided it will be applied to transform the page.\n// If |clipRect| is provided it will be used to clip the resulting page.\n// If neither |matrix| or |clipRect| are provided this method returns |false|.\n// Returns |true| if transforms are applied.\n//\n// This function will transform the whole page, and would take effect to all the\n// objects in the page.\n//\n// page        - Page handle.\n// matrix      - Transform matrix.\n// clipRect    - Clipping rectangle.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_TransFormWithClip(FPDF_PAGE page,\n                           const FS_MATRIX* matrix,\n                           const FS_RECTF* clipRect);\n\n// Transform (scale, rotate, shear, move) the clip path of page object.\n// page_object - Handle to a page object. Returned by\n// FPDFPageObj_NewImageObj().\n//\n// a  - The coefficient \"a\" of the matrix.\n// b  - The coefficient \"b\" of the matrix.\n// c  - The coefficient \"c\" of the matrix.\n// d  - The coefficient \"d\" of the matrix.\n// e  - The coefficient \"e\" of the matrix.\n// f  - The coefficient \"f\" of the matrix.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,\n                              double a,\n                              double b,\n                              double c,\n                              double d,\n                              double e,\n                              double f);\n\n// Experimental API.\n// Get the clip path of the page object.\n//\n//   page object - Handle to a page object. Returned by e.g.\n//                 FPDFPage_GetObject().\n//\n// Returns the handle to the clip path, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until\n// FPDF_ClosePage() is called for the page containing |page_object|.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV\nFPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of paths inside |clip_path|.\n//\n//   clip_path - handle to a clip_path.\n//\n// Returns the number of objects in |clip_path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path);\n\n// Experimental API.\n// Get number of segments inside one path of |clip_path|.\n//\n//   clip_path  - handle to a clip_path.\n//   path_index - index into the array of paths of the clip path.\n//\n// Returns the number of segments or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index);\n\n// Experimental API.\n// Get segment in one specific path of |clip_path| at index.\n//\n//   clip_path     - handle to a clip_path.\n//   path_index    - the index of a path.\n//   segment_index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid\n// until FPDF_ClosePage() is called for the page containing |clip_path|.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,\n                            int path_index,\n                            int segment_index);\n\n// Create a new clip path, with a rectangle inserted.\n//\n// Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with\n// FPDF_DestroyClipPath().\n//\n// left   - The left of the clip box.\n// bottom - The bottom of the clip box.\n// right  - The right of the clip box.\n// top    - The top of the clip box.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,\n                                                            float bottom,\n                                                            float right,\n                                                            float top);\n\n// Destroy the clip path.\n//\n// clipPath - A handle to the clip path. It will be invalid after this call.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath);\n\n// Clip the page content, the page content that outside the clipping region\n// become invisible.\n//\n// A clip path will be inserted before the page content stream or content array.\n// In this way, the page content will be clipped by this clip path.\n//\n// page        - A page handle.\n// clipPath    - A handle to the clip path. (Does not take ownership.)\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,\n                                                       FPDF_CLIPPATH clipPath);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TRANSFORMPAGE_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdfview.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/include/fpdfview.h.orig",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(COMPONENT_BUILD)\n// FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer\n// template in testing/fuzzers/BUILD.gn.\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n#else\n#define FPDF_EXPORT\n#endif  // defined(COMPONENT_BUILD)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/abseil.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/agg23.txt",
    "content": "//----------------------------------------------------------------------------\n// Anti-Grain Geometry - Version 2.3\n// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)\n//\n// Permission to copy, use, modify, sell and distribute this software\n// is granted provided this copyright notice appears in all copies.\n// This software is provided \"as is\" without express or implied\n// warranty, and with no claim as to its suitability for any purpose.\n//\n//----------------------------------------------------------------------------\n// Contact: mcseem@antigrain.com\n//          mcseemagg@yahoo.com\n//          http://www.antigrain.com\n//----------------------------------------------------------------------------\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/fast_float.txt",
    "content": "MIT License\n\nCopyright (c) 2021 The fast_float authors\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/freetype.txt",
    "content": "                    The FreeType Project LICENSE\n                    ----------------------------\n\n                            2006-Jan-27\n\n                    Copyright 1996-2002, 2006 by\n          David Turner, Robert Wilhelm, and Werner Lemberg\n\n\n\nIntroduction\n============\n\n  The FreeType  Project is distributed in  several archive packages;\n  some of them may contain, in addition to the FreeType font engine,\n  various tools and  contributions which rely on, or  relate to, the\n  FreeType Project.\n\n  This  license applies  to all  files found  in such  packages, and\n  which do not  fall under their own explicit  license.  The license\n  affects  thus  the  FreeType   font  engine,  the  test  programs,\n  documentation and makefiles, at the very least.\n\n  This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG\n  (Independent JPEG  Group) licenses, which  all encourage inclusion\n  and  use of  free  software in  commercial  and freeware  products\n  alike.  As a consequence, its main points are that:\n\n    o We don't promise that this software works. However, we will be\n      interested in any kind of bug reports. (`as is' distribution)\n\n    o You can  use this software for whatever you  want, in parts or\n      full form, without having to pay us. (`royalty-free' usage)\n\n    o You may not pretend that  you wrote this software.  If you use\n      it, or  only parts of it,  in a program,  you must acknowledge\n      somewhere  in  your  documentation  that  you  have  used  the\n      FreeType code. (`credits')\n\n  We  specifically  permit  and  encourage  the  inclusion  of  this\n  software, with  or without modifications,  in commercial products.\n  We  disclaim  all warranties  covering  The  FreeType Project  and\n  assume no liability related to The FreeType Project.\n\n\n  Finally,  many  people  asked  us  for  a  preferred  form  for  a\n  credit/disclaimer to use in compliance with this license.  We thus\n  encourage you to use the following text:\n\n   \"\"\"\n    Portions of this software are copyright  <year> The FreeType\n    Project (www.freetype.org).  All rights reserved.\n   \"\"\"\n\n  Please replace <year> with the value from the FreeType version you\n  actually use.\n\n\nLegal Terms\n===========\n\n0. Definitions\n--------------\n\n  Throughout this license,  the terms `package', `FreeType Project',\n  and  `FreeType  archive' refer  to  the  set  of files  originally\n  distributed  by the  authors  (David Turner,  Robert Wilhelm,  and\n  Werner Lemberg) as the `FreeType Project', be they named as alpha,\n  beta or final release.\n\n  `You' refers to  the licensee, or person using  the project, where\n  `using' is a generic term including compiling the project's source\n  code as  well as linking it  to form a  `program' or `executable'.\n  This  program is  referred to  as  `a program  using the  FreeType\n  engine'.\n\n  This  license applies  to all  files distributed  in  the original\n  FreeType  Project,   including  all  source   code,  binaries  and\n  documentation,  unless  otherwise  stated   in  the  file  in  its\n  original, unmodified form as  distributed in the original archive.\n  If you are  unsure whether or not a particular  file is covered by\n  this license, you must contact us to verify this.\n\n  The FreeType  Project is copyright (C) 1996-2000  by David Turner,\n  Robert Wilhelm, and Werner Lemberg.  All rights reserved except as\n  specified below.\n\n1. No Warranty\n--------------\n\n  THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY\n  KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,\n  WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR\n  PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS\n  BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO\n  USE, OF THE FREETYPE PROJECT.\n\n2. Redistribution\n-----------------\n\n  This  license  grants  a  worldwide, royalty-free,  perpetual  and\n  irrevocable right  and license to use,  execute, perform, compile,\n  display,  copy,   create  derivative  works   of,  distribute  and\n  sublicense the  FreeType Project (in  both source and  object code\n  forms)  and  derivative works  thereof  for  any  purpose; and  to\n  authorize others  to exercise  some or all  of the  rights granted\n  herein, subject to the following conditions:\n\n    o Redistribution of  source code  must retain this  license file\n      (`FTL.TXT') unaltered; any  additions, deletions or changes to\n      the original  files must be clearly  indicated in accompanying\n      documentation.   The  copyright   notices  of  the  unaltered,\n      original  files must  be  preserved in  all  copies of  source\n      files.\n\n    o Redistribution in binary form must provide a  disclaimer  that\n      states  that  the software is based in part of the work of the\n      FreeType Team,  in  the  distribution  documentation.  We also\n      encourage you to put an URL to the FreeType web page  in  your\n      documentation, though this isn't mandatory.\n\n  These conditions  apply to any  software derived from or  based on\n  the FreeType Project,  not just the unmodified files.   If you use\n  our work, you  must acknowledge us.  However, no  fee need be paid\n  to us.\n\n3. Advertising\n--------------\n\n  Neither the  FreeType authors and  contributors nor you  shall use\n  the name of the  other for commercial, advertising, or promotional\n  purposes without specific prior written permission.\n\n  We suggest,  but do not require, that  you use one or  more of the\n  following phrases to refer  to this software in your documentation\n  or advertising  materials: `FreeType Project',  `FreeType Engine',\n  `FreeType library', or `FreeType Distribution'.\n\n  As  you have  not signed  this license,  you are  not  required to\n  accept  it.   However,  as  the FreeType  Project  is  copyrighted\n  material, only  this license, or  another one contracted  with the\n  authors, grants you  the right to use, distribute,  and modify it.\n  Therefore,  by  using,  distributing,  or modifying  the  FreeType\n  Project, you indicate that you understand and accept all the terms\n  of this license.\n\n4. Contacts\n-----------\n\n  There are two mailing lists related to FreeType:\n\n    o freetype@nongnu.org\n\n      Discusses general use and applications of FreeType, as well as\n      future and  wanted additions to the  library and distribution.\n      If  you are looking  for support,  start in  this list  if you\n      haven't found anything to help you in the documentation.\n\n    o freetype-devel@nongnu.org\n\n      Discusses bugs,  as well  as engine internals,  design issues,\n      specific licenses, porting, etc.\n\n  Our home page can be found at\n\n    http://www.freetype.org\n\n\n--- end of FTL.TXT ---\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/icu.txt",
    "content": "UNICODE LICENSE V3\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright © 2016-2025 Unicode, Inc.\n\nNOTICE TO USER: Carefully read the following legal agreement. BY\nDOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\nSOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\nTERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\nDOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of data files and any associated documentation (the \"Data Files\") or\nsoftware and any associated documentation (the \"Software\") to deal in the\nData Files or Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, and/or sell\ncopies of the Data Files or Software, and to permit persons to whom the\nData Files or Software are furnished to do so, provided that either (a)\nthis copyright and permission notice appear with all copies of the Data\nFiles or Software, or (b) this copyright and permission notice appear in\nassociated Documentation.\n\nTHE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\nKIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\nTHIRD PARTY RIGHTS.\n\nIN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\nBE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\nFILES OR SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder shall\nnot be used in advertising or otherwise to promote the sale, use or other\ndealings in these Data Files or Software without prior written\nauthorization of the copyright holder.\n\nSPDX-License-Identifier: Unicode-3.0\n\n----------------------------------------------------------------------\n\nThird-Party Software Licenses\n\nThis section contains third-party software notices and/or additional\nterms for licensed third-party software components included within ICU\nlibraries.\n\n----------------------------------------------------------------------\n\nICU License - ICU 1.8.1 to ICU 57.1\n\nCOPYRIGHT AND PERMISSION NOTICE\n\nCopyright (c) 1995-2016 International Business Machines Corporation and others\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, and/or sell copies of the Software, and to permit persons\nto whom the Software is furnished to do so, provided that the above\ncopyright notice(s) and this permission notice appear in all copies of\nthe Software and that both the above copyright notice(s) and this\npermission notice appear in supporting documentation.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\nHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\nSPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\nRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\nCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nExcept as contained in this notice, the name of a copyright holder\nshall not be used in advertising or otherwise to promote the sale, use\nor other dealings in this Software without prior written authorization\nof the copyright holder.\n\nAll trademarks and registered trademarks mentioned herein are the\nproperty of their respective owners.\n\n----------------------------------------------------------------------\n\nChinese/Japanese Word Break Dictionary Data (cjdict.txt)\n\n #     The Google Chrome software developed by Google is licensed under\n # the BSD license. Other software included in this distribution is\n # provided under other licenses, as set forth below.\n #\n #  The BSD License\n #  http://opensource.org/licenses/bsd-license.php\n #  Copyright (C) 2006-2008, Google Inc.\n #\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice,\n # this list of conditions and the following disclaimer.\n #  Redistributions in binary form must reproduce the above\n # copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided with\n # the distribution.\n #  Neither the name of  Google Inc. nor the names of its\n # contributors may be used to endorse or promote products derived from\n # this software without specific prior written permission.\n #\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #\n #\n #  The word list in cjdict.txt are generated by combining three word lists\n # listed below with further processing for compound word breaking. The\n # frequency is generated with an iterative training against Google web\n # corpora.\n #\n #  * Libtabe (Chinese)\n #    - https://sourceforge.net/project/?group_id=1519\n #    - Its license terms and conditions are shown below.\n #\n #  * IPADIC (Japanese)\n #    - http://chasen.aist-nara.ac.jp/chasen/distribution.html\n #    - Its license terms and conditions are shown below.\n #\n #  ---------COPYING.libtabe ---- BEGIN--------------------\n #\n #  /*\n #   * Copyright (c) 1999 TaBE Project.\n #   * Copyright (c) 1999 Pai-Hsiang Hsiao.\n #   * All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the TaBE Project nor the names of its\n #   *   contributors may be used to endorse or promote products derived\n #   *   from this software without specific prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  /*\n #   * Copyright (c) 1999 Computer Systems and Communication Lab,\n #   *                    Institute of Information Science, Academia\n #       *                    Sinica. All rights reserved.\n #   *\n #   * Redistribution and use in source and binary forms, with or without\n #   * modification, are permitted provided that the following conditions\n #   * are met:\n #   *\n #   * . Redistributions of source code must retain the above copyright\n #   *   notice, this list of conditions and the following disclaimer.\n #   * . Redistributions in binary form must reproduce the above copyright\n #   *   notice, this list of conditions and the following disclaimer in\n #   *   the documentation and/or other materials provided with the\n #   *   distribution.\n #   * . Neither the name of the Computer Systems and Communication Lab\n #   *   nor the names of its contributors may be used to endorse or\n #   *   promote products derived from this software without specific\n #   *   prior written permission.\n #   *\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\n #   */\n #\n #  Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\n #      University of Illinois\n #  c-tsai4@uiuc.edu  http://casper.beckman.uiuc.edu/~c-tsai4\n #\n #  ---------------COPYING.libtabe-----END--------------------------------\n #\n #\n #  ---------------COPYING.ipadic-----BEGIN-------------------------------\n #\n #  Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\n #  and Technology.  All Rights Reserved.\n #\n #  Use, reproduction, and distribution of this software is permitted.\n #  Any copy of this software, whether in its original form or modified,\n #  must include both the above copyright notice and the following\n #  paragraphs.\n #\n #  Nara Institute of Science and Technology (NAIST),\n #  the copyright holders, disclaims all warranties with regard to this\n #  software, including all implied warranties of merchantability and\n #  fitness, in no event shall NAIST be liable for\n #  any special, indirect or consequential damages or any damages\n #  whatsoever resulting from loss of use, data or profits, whether in an\n #  action of contract, negligence or other tortuous action, arising out\n #  of or in connection with the use or performance of this software.\n #\n #  A large portion of the dictionary entries\n #  originate from ICOT Free Software.  The following conditions for ICOT\n #  Free Software applies to the current dictionary as well.\n #\n #  Each User may also freely distribute the Program, whether in its\n #  original form or modified, to any third party or parties, PROVIDED\n #  that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\n #  on, or be attached to, the Program, which is distributed substantially\n #  in the same form as set out herein and that such intended\n #  distribution, if actually made, will neither violate or otherwise\n #  contravene any of the laws and regulations of the countries having\n #  jurisdiction over the User or the intended distribution itself.\n #\n #  NO WARRANTY\n #\n #  The program was produced on an experimental basis in the course of the\n #  research and development conducted during the project and is provided\n #  to users as so produced on an experimental basis.  Accordingly, the\n #  program is provided without any warranty whatsoever, whether express,\n #  implied, statutory or otherwise.  The term \"warranty\" used herein\n #  includes, but is not limited to, any warranty of the quality,\n #  performance, merchantability and fitness for a particular purpose of\n #  the program and the nonexistence of any infringement or violation of\n #  any right of any third party.\n #\n #  Each user of the program will agree and understand, and be deemed to\n #  have agreed and understood, that there is no warranty whatsoever for\n #  the program and, accordingly, the entire risk arising from or\n #  otherwise connected with the program is assumed by the user.\n #\n #  Therefore, neither ICOT, the copyright holder, or any other\n #  organization that participated in or was otherwise related to the\n #  development of the program and their respective officials, directors,\n #  officers and other employees shall be held liable for any and all\n #  damages, including, without limitation, general, special, incidental\n #  and consequential damages, arising out of or otherwise in connection\n #  with the use or inability to use the program or any product, material\n #  or result produced or otherwise obtained by using the program,\n #  regardless of whether they have been advised of, or otherwise had\n #  knowledge of, the possibility of such damages at any time during the\n #  project or thereafter.  Each user will be deemed to have agreed to the\n #  foregoing by his or her commencement of use of the program.  The term\n #  \"use\" as used herein includes, but is not limited to, the use,\n #  modification, copying and distribution of the program and the\n #  production of secondary products from the program.\n #\n #  In the case where the program, whether in its original form or\n #  modified, was distributed or delivered to or received by a user from\n #  any person, organization or entity other than ICOT, unless it makes or\n #  grants independently of ICOT any specific warranty to the user in\n #  writing, such person, organization or entity, will also be exempted\n #  from and not be held liable to the user for any such damages as noted\n #  above as far as the program is concerned.\n #\n #  ---------------COPYING.ipadic-----END----------------------------------\n\n----------------------------------------------------------------------\n\nLao Word Break Dictionary Data (laodict.txt)\n\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\n # License & terms of use: http://www.unicode.org/copyright.html\n # Copyright (c) 2015 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # Project: https://github.com/rober42539/lao-dictionary\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\n #          (copied below)\n #\n #\tThis file is derived from the above dictionary version of Nov 22, 2020\n #  ----------------------------------------------------------------------\n #  Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions are met:\n #\n #  Redistributions of source code must retain the above copyright notice, this\n #  list of conditions and the following disclaimer. Redistributions in binary\n #  form must reproduce the above copyright notice, this list of conditions and\n #  the following disclaimer in the documentation and/or other materials\n #  provided with the distribution.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # OF THE POSSIBILITY OF SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nBurmese Word Break Dictionary Data (burmesedict.txt)\n\n #  Copyright (c) 2014 International Business Machines Corporation\n #  and others. All Rights Reserved.\n #\n #  This list is part of a project hosted at:\n #    github.com/kanyawtech/myanmar-karen-word-lists\n #\n #  --------------------------------------------------------------------------\n #  Copyright (c) 2013, LeRoy Benjamin Sharon\n #  All rights reserved.\n #\n #  Redistribution and use in source and binary forms, with or without\n #  modification, are permitted provided that the following conditions\n #  are met: Redistributions of source code must retain the above\n #  copyright notice, this list of conditions and the following\n #  disclaimer.  Redistributions in binary form must reproduce the\n #  above copyright notice, this list of conditions and the following\n #  disclaimer in the documentation and/or other materials provided\n #  with the distribution.\n #\n #    Neither the name Myanmar Karen Word Lists, nor the names of its\n #    contributors may be used to endorse or promote products derived\n #    from this software without specific prior written permission.\n #\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n #  CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n #  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n #  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n #  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n #  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n #  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n #  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\n #  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n #  SUCH DAMAGE.\n #  --------------------------------------------------------------------------\n\n----------------------------------------------------------------------\n\nTime Zone Database\n\n  ICU uses the public domain data and code derived from Time Zone\nDatabase for its time zone support. The ownership of the TZ database\nis explained in BCP 175: Procedure for Maintaining the Time Zone\nDatabase section 7.\n\n # 7.  Database Ownership\n #\n #    The TZ database itself is not an IETF Contribution or an IETF\n #    document.  Rather it is a pre-existing and regularly updated work\n #    that is in the public domain, and is intended to remain in the\n #    public domain.  Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\n #    not apply to the TZ Database or contributions that individuals make\n #    to it.  Should any claims be made and substantiated against the TZ\n #    Database, the organization that is providing the IANA\n #    Considerations defined in this RFC, under the memorandum of\n #    understanding with the IETF, currently ICANN, may act in accordance\n #    with all competent court orders.  No ownership claims will be made\n #    by ICANN or the IETF Trust on the database or the code.  Any person\n #    making a contribution to the database or code waives all rights to\n #    future claims in that contribution or in the TZ Database.\n\n----------------------------------------------------------------------\n\nGoogle double-conversion\n\nCopyright 2006-2011, the V8 project authors. All rights reserved.\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials provided\n      with the distribution.\n    * Neither the name of Google Inc. nor the names of its\n      contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n----------------------------------------------------------------------\n\nJSON parsing library (nlohmann/json)\n\nFile: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\n\nMIT License\n\nCopyright (c) 2013-2022 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n----------------------------------------------------------------------\n\nFile: aclocal.m4 (only for ICU4C)\nSection: pkg.m4 - Macros to locate and utilise pkg-config.\n\n\nCopyright © 2004 Scott James Remnant <scott@netsplit.com>.\nCopyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n02111-1307, USA.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: config.guess (only for ICU4C)\n\n\nThis file is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nGeneral Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, see <https://www.gnu.org/licenses/>.\n\nAs a special exception to the GNU General Public License, if you\ndistribute this file as part of a program that contains a\nconfiguration script generated by Autoconf, you may include it under\nthe same distribution terms that you use for the rest of that\nprogram.  This Exception is an additional permission under section 7\nof the GNU General Public License, version 3 (\"GPLv3\").\n\n\n(The condition for the exception is fulfilled because\nICU4C includes a configuration script generated by Autoconf,\nnamely the `configure` script.)\n\n----------------------------------------------------------------------\n\nFile: install-sh (only for ICU4C)\n\n\nCopyright 1991 by the Massachusetts Institute of Technology\n\nPermission to use, copy, modify, distribute, and sell this software and its\ndocumentation for any purpose is hereby granted without fee, provided that\nthe above copyright notice appear in all copies and that both that\ncopyright notice and this permission notice appear in supporting\ndocumentation, and that the name of M.I.T. not be used in advertising or\npublicity pertaining to distribution of the software without specific,\nwritten prior permission.  M.I.T. makes no representations about the\nsuitability of this software for any purpose.  It is provided \"as is\"\nwithout express or implied warranty.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/lcms.txt",
    "content": "//---------------------------------------------------------------------------------\n//\n//  Little Color Management System\n//  Copyright (c) 1998-2023 Marti Maria Saguer\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the Software\n// is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n//---------------------------------------------------------------------------------\n//\n// Version 2.15 \n//\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/libjpeg_turbo.ijg",
    "content": "libjpeg-turbo note:  This file has been modified by The libjpeg-turbo Project\nto include only information relevant to libjpeg-turbo, to wordsmith certain\nsections, and to remove impolitic language that existed in the libjpeg v8\nREADME.  It is included only for reference.  Please see README.md for\ninformation specific to libjpeg-turbo.\n\n\nThe Independent JPEG Group's JPEG software\n==========================================\n\nThis distribution contains a release of the Independent JPEG Group's free JPEG\nsoftware.  You are welcome to redistribute this software and to use it for any\npurpose, subject to the conditions under LEGAL ISSUES, below.\n\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\nJulian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,\nand other members of the Independent JPEG Group.\n\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\n(also known as JPEG, together with ITU-T SG16).\n\n\nDOCUMENTATION ROADMAP\n=====================\n\nThis file contains the following sections:\n\nOVERVIEW            General description of JPEG and the IJG software.\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\nREFERENCES          Where to learn more about JPEG.\nARCHIVE LOCATIONS   Where to find newer versions of this software.\nFILE FORMAT WARS    Software *not* to get.\nTO DO               Plans for future IJG releases.\n\nOther documentation files in the distribution are:\n\nUser documentation:\n  doc/usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\n                        rdjpgcom, and wrjpgcom.\n  doc/*.1               Unix-style man pages for programs (same info as\n                        usage.txt).\n  doc/wizard.txt        Advanced usage instructions for JPEG wizards only.\n  doc/change.log        Version-to-version change highlights.\nProgrammer and internal documentation:\n  doc/libjpeg.txt       How to use the JPEG library in your own programs.\n  src/example.c         Sample code for calling the JPEG library.\n  doc/structure.txt     Overview of the JPEG library's internal structure.\n  doc/coderules.txt     Coding style rules --- please read if you contribute\n                        code.\n\nPlease read at least usage.txt.  Some information can also be found in the JPEG\nFAQ (Frequently Asked Questions) article.  See ARCHIVE LOCATIONS below to find\nout where to obtain the FAQ article.\n\nIf you want to understand how the JPEG code works, we suggest reading one or\nmore of the REFERENCES, then looking at the documentation files (in roughly\nthe order listed) before diving into the code.\n\n\nOVERVIEW\n========\n\nThis package contains C software to implement JPEG image encoding, decoding,\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\nmethod for full-color and grayscale images.  JPEG's strong suit is compressing\nphotographic images or other types of images that have smooth color and\nbrightness transitions between neighboring pixels.  Images with sharp lines or\nother abrupt features may not compress well with JPEG, and a higher JPEG\nquality may have to be used to avoid visible compression artifacts with such\nimages.\n\nJPEG is normally lossy, meaning that the output pixels are not necessarily\nidentical to the input pixels.  However, on photographic content and other\n\"smooth\" images, very good compression ratios can be obtained with no visible\ncompression artifacts, and extremely high compression ratios are possible if\nyou are willing to sacrifice image quality (by reducing the \"quality\" setting\nin the compressor.)\n\nThis software implements JPEG baseline, extended-sequential, progressive, and\nlossless compression processes.  Provision is made for supporting all variants\nof these processes, although some uncommon parameter settings aren't\nimplemented yet.  We have made no provision for supporting the hierarchical\nprocesses defined in the standard.\n\nWe provide a set of library routines for reading and writing JPEG image files,\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\nperform conversion between JPEG and some other popular image file formats.\nThe library is intended to be reused in other applications.\n\nIn order to support file conversion and viewing software, we have included\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\nfor example, the color quantization modules are not strictly part of JPEG\ndecoding, but they are essential for output to colormapped file formats.  These\nextra functions can be compiled out of the library if not required for a\nparticular application.\n\nWe have also included \"jpegtran\", a utility for lossless transcoding between\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\napplications for inserting and extracting textual comments in JFIF files.\n\nThe emphasis in designing this software has been on achieving portability and\nflexibility, while also making it fast enough to be useful.  In particular,\nthe software is not intended to be read as a tutorial on JPEG.  (See the\nREFERENCES section for introductory material.)  Rather, it is intended to\nbe reliable, portable, industrial-strength code.  We do not claim to have\nachieved that goal in every aspect of the software, but we strive for it.\n\nWe welcome the use of this software as a component of commercial products.\nNo royalty is required, but we do ask for an acknowledgement in product\ndocumentation, as described under LEGAL ISSUES.\n\n\nLEGAL ISSUES\n============\n\nIn plain English:\n\n1. We don't promise that this software works.  (But if you find any bugs,\n   please let us know!)\n2. You can use this software for whatever you want.  You don't have to pay us.\n3. You may not pretend that you wrote this software.  If you use it in a\n   program, you must acknowledge somewhere in your documentation that\n   you've used the IJG code.\n\nIn legalese:\n\nThe authors make NO WARRANTY or representation, either express or implied,\nwith respect to this software, its quality, accuracy, merchantability, or\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\nits user, assume the entire risk as to its quality and accuracy.\n\nThis software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.\nAll Rights Reserved except as specified below.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nPermission is NOT granted for the use of any IJG author's name or company name\nin advertising or publicity relating to this software or products derived from\nit.  This software may be referred to only as \"the Independent JPEG Group's\nsoftware\".\n\nWe specifically permit and encourage the use of this software as the basis of\ncommercial products, provided that all warranty or liability claims are\nassumed by the product vendor.\n\n\nREFERENCES\n==========\n\nWe recommend reading one or more of these references before trying to\nunderstand the innards of the JPEG software.\n\nThe best short technical introduction to the JPEG compression algorithm is\n        Wallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\n        Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\n(Adjacent articles in that issue discuss MPEG motion picture compression,\napplications of JPEG, and related topics.)  If you don't have the CACM issue\nhandy, a PDF file containing a revised version of Wallace's article is\navailable at http://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\nomits the sample images that appeared in CACM, but it includes corrections\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\nand it may not be used for commercial purposes.\n\nA somewhat less technical, more leisurely introduction to JPEG can be found in\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\ngood explanations and example C code for a multitude of compression methods\nincluding JPEG.  It is an excellent source if you are comfortable reading C\ncode but don't know much about data compression in general.  The book's JPEG\nsample code is far from industrial-strength, but when you are ready to look\nat a full implementation, you've got one here...\n\nThe best currently available description of JPEG is the textbook \"JPEG Still\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\nstandards (DIS 10918-1 and draft DIS 10918-2).\n\nThe original JPEG standard is divided into two parts, Part 1 being the actual\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\n\nThe JPEG standard does not specify all details of an interchangeable file\nformat.  For the omitted details, we follow the \"JFIF\" conventions, revision\n1.02.  JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and\nRecommendation ITU-T T.871 (05/2011): Information technology - Digital\ncompression and coding of continuous-tone still images: JPEG File Interchange\nFormat (JFIF).  It is available as a free download in PDF file format from\nhttps://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.\nA PDF file of the older JFIF 1.02 specification is available at\nhttp://www.w3.org/Graphics/JPEG/jfif3.pdf.\n\nThe TIFF 6.0 file format specification can be obtained from\nhttp://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation\nscheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious\nproblems.  IJG does not recommend use of the TIFF 6.0 design (TIFF Compression\ntag 6).  Instead, we recommend the JPEG design proposed by TIFF Technical Note\n#2 (Compression tag 7).  Copies of this Note can be obtained from\nhttp://www.ijg.org/files/.  It is expected that the next revision\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\nuses our library to implement TIFF/JPEG per the Note.\n\n\nARCHIVE LOCATIONS\n=================\n\nThe \"official\" archive site for this software is www.ijg.org.\nThe most recent released version can always be found there in\ndirectory \"files\".\n\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\ngeneral information about JPEG.  It is available at\nhttp://www.faqs.org/faqs/jpeg-faq.\n\n\nFILE FORMAT COMPATIBILITY\n=========================\n\nThis software implements ITU T.81 | ISO/IEC 10918 with some extensions from\nITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).\nInformally, the term \"JPEG image\" or \"JPEG file\" most often refers to JFIF or\na subset thereof, but there are other formats containing the name \"JPEG\" that\nare incompatible with the original JPEG standard or with JFIF (for instance,\nJPEG 2000 and JPEG XR).  This software therefore does not support these\nformats.  Indeed, one of the original reasons for developing this free software\nwas to help force convergence on a common, interoperable format standard for\nJPEG files.\n\nJFIF is a minimal or \"low end\" representation.  TIFF/JPEG (TIFF revision 6.0 as\nmodified by TIFF Technical Note #2) can be used for \"high end\" applications\nthat need to record a lot of additional data about an image.\n\n\nTO DO\n=====\n\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/libjpeg_turbo.md",
    "content": "libjpeg-turbo Licenses\n======================\n\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\n\n- The IJG (Independent JPEG Group) License, which is listed in\n  [README.ijg](README.ijg)\n\n  This license applies to the libjpeg API library and associated programs,\n  including any code inherited from libjpeg and any modifications to that\n  code.  Note that the libjpeg-turbo SIMD source code bears the\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\n  the overall libjpeg API library, the terms of the zlib License are subsumed\n  by the terms of the IJG License.\n\n- The Modified (3-clause) BSD License, which is listed below\n\n  This license applies to the TurboJPEG API library and associated programs, as\n  well as the build system.  Note that the TurboJPEG API library wraps the\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\n  both the terms of the IJG License and the terms of the Modified (3-clause)\n  BSD License apply.\n\n\nComplying with the libjpeg-turbo Licenses\n=========================================\n\nThis section provides a roll-up of the libjpeg-turbo licensing terms, to the\nbest of our understanding.  This is not a license in and of itself.  It is\nintended solely for clarification.\n\n1.  If you are distributing a modified version of the libjpeg-turbo source,\n    then:\n\n    1.  You cannot alter or remove any existing copyright or license notices\n        from the source.\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 1 of the Modified BSD License\n        - Clauses 1 and 3 of the zlib License\n\n    2.  You must add your own copyright notice to the header of each source\n        file you modified, so others can tell that you modified that file.  (If\n        there is not an existing copyright header in that file, then you can\n        simply add a notice stating that you modified the file.)\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 2 of the zlib License\n\n    3.  You must include the IJG README file, and you must not alter any of the\n        copyright or license text in that file.\n\n        **Origin**\n        - Clause 1 of the IJG License\n\n2.  If you are distributing only libjpeg-turbo binaries without the source, or\n    if you are distributing an application that statically links with\n    libjpeg-turbo, then:\n\n    1.  Your product documentation must include a message stating:\n\n        This software is based in part on the work of the Independent JPEG\n        Group.\n\n        **Origin**\n        - Clause 2 of the IJG license\n\n    2.  If your binary distribution includes or uses the TurboJPEG API, then\n        your product documentation must include the text of the Modified BSD\n        License (see below.)\n\n        **Origin**\n        - Clause 2 of the Modified BSD License\n\n3.  You cannot use the name of the IJG or The libjpeg-turbo Project or the\n    contributors thereof in advertising, publicity, etc.\n\n    **Origin**\n    - IJG License\n    - Clause 3 of the Modified BSD License\n\n4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be\n    free of defects, nor do we accept any liability for undesirable\n    consequences resulting from your use of the software.\n\n    **Origin**\n    - IJG License\n    - Modified BSD License\n    - zlib License\n\n\nThe Modified (3-clause) BSD License\n===================================\n\nCopyright (C)2009-2024 D. R. Commander.  All Rights Reserved.<br>\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n- Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n- Neither the name of the libjpeg-turbo Project nor the names of its\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n\nWhy Two Licenses?\n=================\n\nThe zlib License could have been used instead of the Modified (3-clause) BSD\nLicense, and since the IJG License effectively subsumes the distribution\nconditions of the zlib License, this would have effectively placed\nlibjpeg-turbo binary distributions under the IJG License.  However, the IJG\nLicense specifically refers to the Independent JPEG Group and does not extend\nattribution and endorsement protections to other entities.  Thus, it was\ndesirable to choose a license that granted us the same protections for new code\nthat were granted to the IJG for code derived from their software.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/libopenjpeg.txt",
    "content": "/*\n * The copyright in this software is being made available under the 2-clauses\n * BSD License, included below. This software may be subject to other third\n * party and contributor rights, including patent rights, and no such rights\n * are granted under this license.\n *\n * Copyright (c) 2005, Herve Drolon, FreeImage Team\n * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR\n * Copyright (c) 2012, CS Systemes d'Information, France\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/libpng.txt",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n=========================================\n\nPNG Reference Library License version 2\n---------------------------------------\n\n * Copyright (c) 1995-2019 The PNG Reference Library Authors.\n * Copyright (c) 2018-2019 Cosmin Truta.\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n * Copyright (c) 1996-1997 Andreas Dilger.\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nThe software is supplied \"as is\", without warranty of any kind,\nexpress or implied, including, without limitation, the warranties\nof merchantability, fitness for a particular purpose, title, and\nnon-infringement.  In no event shall the Copyright owners, or\nanyone distributing the software, be liable for any damages or\nother liability, whether in contract, tort or otherwise, arising\nfrom, out of, or in connection with the software, or the use or\nother dealings in the software, even if advised of the possibility\nof such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute\nthis software, or portions hereof, for any purpose, without fee,\nsubject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you\n    must not claim that you wrote the original software.  If you\n    use this software in a product, an acknowledgment in the product\n    documentation would be appreciated, but is not required.\n\n 2. Altered source versions must be plainly marked as such, and must\n    not be misrepresented as being the original software.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\n\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n-----------------------------------------------------------------------\n\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\nderived from libpng-1.0.6, and are distributed according to the same\ndisclaimer and license as libpng-1.0.6 with the following individuals\nadded to the list of Contributing Authors:\n\n    Simon-Pierre Cadieux\n    Eric S. Raymond\n    Mans Rullgard\n    Cosmin Truta\n    Gilles Vollant\n    James Yu\n    Mandar Sahastrabuddhe\n    Google Inc.\n    Vadim Barkov\n\nand with the following additions to the disclaimer:\n\n    There is no warranty against interference with your enjoyment of\n    the library or against infringement.  There is no warranty that our\n    efforts or the library will fulfill any of your particular purposes\n    or needs.  This library is provided with all faults, and the entire\n    risk of satisfactory quality, performance, accuracy, and effort is\n    with the user.\n\nSome files in the \"contrib\" directory and some configure-generated\nfiles that are distributed with libpng have other copyright owners, and\nare released under other open source licenses.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\nlibpng-0.96, and are distributed according to the same disclaimer and\nlicense as libpng-0.96, with the following individuals added to the\nlist of Contributing Authors:\n\n    Tom Lane\n    Glenn Randers-Pehrson\n    Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\nand are distributed according to the same disclaimer and license as\nlibpng-0.88, with the following individuals added to the list of\nContributing Authors:\n\n    John Bowler\n    Kevin Bracey\n    Sam Bushell\n    Magnus Holmgren\n    Greg Roelofs\n    Tom Tanner\n\nSome files in the \"scripts\" directory have other copyright owners,\nbut are released under this license.\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n    Andreas Dilger\n    Dave Martindale\n    Guy Eric Schalnat\n    Paul Schmidt\n    Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\nimplied, including, without limitation, the warranties of\nmerchantability and of fitness for any purpose.  The Contributing\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\nincidental, special, exemplary, or consequential damages, which may\nresult from the use of the PNG Reference Library, even if advised of\nthe possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n 1. The origin of this source code must not be misrepresented.\n\n 2. Altered versions must be plainly marked as such and must not\n    be misrepresented as being the original source.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit,\nwithout fee, and encourage the use of this source code as a component\nto supporting the PNG file format in commercial products.  If you use\nthis source code in a product, acknowledgment is not required but would\nbe appreciated.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/libtiff.txt",
    "content": "Copyright (c) 1988-1997 Sam Leffler\nCopyright (c) 1991-1997 Silicon Graphics, Inc.\n\nPermission to use, copy, modify, distribute, and sell this software and\nits documentation for any purpose is hereby granted without fee, provided\nthat (i) the above copyright notices and this permission notice appear in\nall copies of the software and related documentation, and (ii) the names of\nSam Leffler and Silicon Graphics may not be used in any advertising or\npublicity relating to the software without the specific, prior written\npermission of Sam Leffler and Silicon Graphics.\n\nTHE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\nEXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\nWARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n\nIN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR\nANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF\nLIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\nOF THIS SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/llvm-libc.txt",
    "content": "==============================================================================\nThe LLVM Project is under the Apache License v2.0 with LLVM Exceptions:\n==============================================================================\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n    1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n    2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n    3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n    4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n    5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n    6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n    7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n    8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n    9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    END OF TERMS AND CONDITIONS\n\n    APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n    Copyright [yyyy] [name of copyright owner]\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n---- LLVM Exceptions to the Apache 2.0 License ----\n\nAs an exception, if, as a result of your compiling your source code, portions\nof this Software are embedded into an Object form of such source code, you\nmay redistribute such embedded portions in such Object form without complying\nwith the conditions of Sections 4(a), 4(b) and 4(d) of the License.\n\nIn addition, if you combine or link compiled forms of this Software with\nsoftware that is licensed under the GPLv2 (\"Combined Software\") and if a\ncourt of competent jurisdiction determines that the patent provision (Section\n3), the indemnity provision (Section 9) or other Section of the License\nconflicts with the conditions of the GPLv2, you may retroactively and\nprospectively choose to deem waived or otherwise exclude such Section(s) of\nthe License, but only in their entirety and only with respect to the Combined\nSoftware.\n\n==============================================================================\nSoftware from third parties included in the LLVM Project:\n==============================================================================\nThe LLVM Project contains third party software which is under different license\nterms. All such code will be identified clearly using at least one of two\nmechanisms:\n1) It will be in a separate directory tree with its own `LICENSE.txt` or\n   `LICENSE` file at the top containing the specific license and restrictions\n   which apply to that software, or\n2) It will contain specific license and restriction terms at the top of every\n   file.\n\n==============================================================================\nLegacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):\n==============================================================================\nUniversity of Illinois/NCSA\nOpen Source License\n\nCopyright (c) 2007-2019 University of Illinois at Urbana-Champaign.\nAll rights reserved.\n\nDeveloped by:\n\n    LLVM Team\n\n    University of Illinois at Urbana-Champaign\n\n    http://llvm.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal with\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimers.\n\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimers in the\n      documentation and/or other materials provided with the distribution.\n\n    * Neither the names of the LLVM Team, University of Illinois at\n      Urbana-Champaign, nor the names of its contributors may be used to\n      endorse or promote products derived from this Software without specific\n      prior written permission.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nCONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE\nSOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/pdfium.txt",
    "content": "// Copyright 2014 The PDFium Authors\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/simdutf.txt",
    "content": "Copyright 2021 The simdutf authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/macos-x64/licenses/zlib.txt",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.3.1, January 22nd, 2024\n\n  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n"
  },
  {
    "path": "external/pdfium/windows-x64/LICENSE",
    "content": "Copyright 2014-2025 Benoit Blanchon\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n\nThis package also includes third-party software. See the licenses/ directory for their respective licenses.\n"
  },
  {
    "path": "external/pdfium/windows-x64/PDFiumConfig.cmake",
    "content": "# PDFium Package Configuration for CMake\n#\n# To use PDFium in your CMake project:\n#\n#   1. set the environment variable PDFium_DIR to the folder containing this file.\n#   2. in your CMakeLists.txt, add\n#       find_package(PDFium)\n#   3. then link your executable with PDFium\n#       target_link_libraries(my_exe pdfium)\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_path(PDFium_INCLUDE_DIR\n    NAMES \"fpdfview.h\"\n    PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n    PATH_SUFFIXES \"include\"\n)\n\nset(PDFium_VERSION \"147.0.7713.0\")\n\nif(WIN32)\n  find_file(PDFium_LIBRARY\n        NAMES \"pdfium.dll\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"bin\")\n\n  find_file(PDFium_IMPLIB\n        NAMES \"pdfium.dll.lib\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    IMPORTED_IMPLIB               \"${PDFium_IMPLIB}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_IMPLIB PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nelse()\n  find_library(PDFium_LIBRARY\n        NAMES \"pdfium\"\n        PATHS \"${CMAKE_CURRENT_LIST_DIR}\"\n        PATH_SUFFIXES \"lib\")\n\n  add_library(pdfium SHARED IMPORTED)\n  set_target_properties(pdfium\n    PROPERTIES\n    IMPORTED_LOCATION             \"${PDFium_LIBRARY}\"\n    INTERFACE_INCLUDE_DIRECTORIES \"${PDFium_INCLUDE_DIR};${PDFium_INCLUDE_DIR}/cpp\"\n  )\n\n  find_package_handle_standard_args(PDFium\n    REQUIRED_VARS PDFium_LIBRARY PDFium_INCLUDE_DIR\n    VERSION_VAR PDFium_VERSION\n  )\nendif()\n"
  },
  {
    "path": "external/pdfium/windows-x64/VERSION",
    "content": "MAJOR=147\nMINOR=0\nBUILD=7713\nPATCH=0\n"
  },
  {
    "path": "external/pdfium/windows-x64/args.gn",
    "content": "is_component_build = false\nis_debug = false\npdf_enable_v8 = false\npdf_enable_xfa = false\npdf_is_standalone = true\npdf_use_partition_alloc = false\ntarget_cpu = \"x64\"\ntarget_os = \"win\"\ntreat_warnings_as_errors = false\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/cpp/fpdf_deleters.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_DELETERS_H_\n#define PUBLIC_CPP_FPDF_DELETERS_H_\n\n#include \"../fpdf_annot.h\"\n#include \"../fpdf_dataavail.h\"\n#include \"../fpdf_edit.h\"\n#include \"../fpdf_formfill.h\"\n#include \"../fpdf_javascript.h\"\n#include \"../fpdf_structtree.h\"\n#include \"../fpdf_text.h\"\n#include \"../fpdf_transformpage.h\"\n#include \"../fpdfview.h\"\n\n// Custom deleters for using FPDF_* types with std::unique_ptr<>.\n\nstruct FPDFAnnotationDeleter {\n  inline void operator()(FPDF_ANNOTATION annot) { FPDFPage_CloseAnnot(annot); }\n};\n\nstruct FPDFAvailDeleter {\n  inline void operator()(FPDF_AVAIL avail) { FPDFAvail_Destroy(avail); }\n};\n\nstruct FPDFBitmapDeleter {\n  inline void operator()(FPDF_BITMAP bitmap) { FPDFBitmap_Destroy(bitmap); }\n};\n\nstruct FPDFClipPathDeleter {\n  inline void operator()(FPDF_CLIPPATH clip_path) {\n    FPDF_DestroyClipPath(clip_path);\n  }\n};\n\nstruct FPDFDocumentDeleter {\n  inline void operator()(FPDF_DOCUMENT doc) { FPDF_CloseDocument(doc); }\n};\n\nstruct FPDFFontDeleter {\n  inline void operator()(FPDF_FONT font) { FPDFFont_Close(font); }\n};\n\nstruct FPDFFormHandleDeleter {\n  inline void operator()(FPDF_FORMHANDLE form) {\n    FPDFDOC_ExitFormFillEnvironment(form);\n  }\n};\n\nstruct FPDFJavaScriptActionDeleter {\n  inline void operator()(FPDF_JAVASCRIPT_ACTION javascript) {\n    FPDFDoc_CloseJavaScriptAction(javascript);\n  }\n};\n\nstruct FPDFPageDeleter {\n  inline void operator()(FPDF_PAGE page) { FPDF_ClosePage(page); }\n};\n\nstruct FPDFPageLinkDeleter {\n  inline void operator()(FPDF_PAGELINK pagelink) {\n    FPDFLink_CloseWebLinks(pagelink);\n  }\n};\n\nstruct FPDFPageObjectDeleter {\n  inline void operator()(FPDF_PAGEOBJECT object) {\n    FPDFPageObj_Destroy(object);\n  }\n};\n\nstruct FPDFStructTreeDeleter {\n  inline void operator()(FPDF_STRUCTTREE tree) { FPDF_StructTree_Close(tree); }\n};\n\nstruct FPDFTextFindDeleter {\n  inline void operator()(FPDF_SCHHANDLE handle) { FPDFText_FindClose(handle); }\n};\n\nstruct FPDFTextPageDeleter {\n  inline void operator()(FPDF_TEXTPAGE text) { FPDFText_ClosePage(text); }\n};\n\n#endif  // PUBLIC_CPP_FPDF_DELETERS_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/cpp/fpdf_scopers.h",
    "content": "// Copyright 2018 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_CPP_FPDF_SCOPERS_H_\n#define PUBLIC_CPP_FPDF_SCOPERS_H_\n\n#include <memory>\n#include <type_traits>\n\n#include \"fpdf_deleters.h\"\n\n// Versions of FPDF types that clean up the object at scope exit.\n\nusing ScopedFPDFAnnotation =\n    std::unique_ptr<std::remove_pointer<FPDF_ANNOTATION>::type,\n                    FPDFAnnotationDeleter>;\n\nusing ScopedFPDFAvail =\n    std::unique_ptr<std::remove_pointer<FPDF_AVAIL>::type, FPDFAvailDeleter>;\n\nusing ScopedFPDFBitmap =\n    std::unique_ptr<std::remove_pointer<FPDF_BITMAP>::type, FPDFBitmapDeleter>;\n\nusing ScopedFPDFClipPath =\n    std::unique_ptr<std::remove_pointer<FPDF_CLIPPATH>::type,\n                    FPDFClipPathDeleter>;\n\nusing ScopedFPDFDocument =\n    std::unique_ptr<std::remove_pointer<FPDF_DOCUMENT>::type,\n                    FPDFDocumentDeleter>;\n\nusing ScopedFPDFFont =\n    std::unique_ptr<std::remove_pointer<FPDF_FONT>::type, FPDFFontDeleter>;\n\nusing ScopedFPDFFormHandle =\n    std::unique_ptr<std::remove_pointer<FPDF_FORMHANDLE>::type,\n                    FPDFFormHandleDeleter>;\n\nusing ScopedFPDFJavaScriptAction =\n    std::unique_ptr<std::remove_pointer<FPDF_JAVASCRIPT_ACTION>::type,\n                    FPDFJavaScriptActionDeleter>;\n\nusing ScopedFPDFPage =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGE>::type, FPDFPageDeleter>;\n\nusing ScopedFPDFPageLink =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGELINK>::type,\n                    FPDFPageLinkDeleter>;\n\nusing ScopedFPDFPageObject =\n    std::unique_ptr<std::remove_pointer<FPDF_PAGEOBJECT>::type,\n                    FPDFPageObjectDeleter>;\n\nusing ScopedFPDFStructTree =\n    std::unique_ptr<std::remove_pointer<FPDF_STRUCTTREE>::type,\n                    FPDFStructTreeDeleter>;\n\nusing ScopedFPDFTextFind =\n    std::unique_ptr<std::remove_pointer<FPDF_SCHHANDLE>::type,\n                    FPDFTextFindDeleter>;\n\nusing ScopedFPDFTextPage =\n    std::unique_ptr<std::remove_pointer<FPDF_TEXTPAGE>::type,\n                    FPDFTextPageDeleter>;\n\n#endif  // PUBLIC_CPP_FPDF_SCOPERS_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_annot.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ANNOT_H_\n#define PUBLIC_FPDF_ANNOT_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdf_formfill.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n#define FPDF_ANNOT_UNKNOWN 0\n#define FPDF_ANNOT_TEXT 1\n#define FPDF_ANNOT_LINK 2\n#define FPDF_ANNOT_FREETEXT 3\n#define FPDF_ANNOT_LINE 4\n#define FPDF_ANNOT_SQUARE 5\n#define FPDF_ANNOT_CIRCLE 6\n#define FPDF_ANNOT_POLYGON 7\n#define FPDF_ANNOT_POLYLINE 8\n#define FPDF_ANNOT_HIGHLIGHT 9\n#define FPDF_ANNOT_UNDERLINE 10\n#define FPDF_ANNOT_SQUIGGLY 11\n#define FPDF_ANNOT_STRIKEOUT 12\n#define FPDF_ANNOT_STAMP 13\n#define FPDF_ANNOT_CARET 14\n#define FPDF_ANNOT_INK 15\n#define FPDF_ANNOT_POPUP 16\n#define FPDF_ANNOT_FILEATTACHMENT 17\n#define FPDF_ANNOT_SOUND 18\n#define FPDF_ANNOT_MOVIE 19\n#define FPDF_ANNOT_WIDGET 20\n#define FPDF_ANNOT_SCREEN 21\n#define FPDF_ANNOT_PRINTERMARK 22\n#define FPDF_ANNOT_TRAPNET 23\n#define FPDF_ANNOT_WATERMARK 24\n#define FPDF_ANNOT_THREED 25\n#define FPDF_ANNOT_RICHMEDIA 26\n#define FPDF_ANNOT_XFAWIDGET 27\n#define FPDF_ANNOT_REDACT 28\n\n// Refer to PDF Reference (6th edition) table 8.16 for all annotation flags.\n#define FPDF_ANNOT_FLAG_NONE 0\n#define FPDF_ANNOT_FLAG_INVISIBLE (1 << 0)\n#define FPDF_ANNOT_FLAG_HIDDEN (1 << 1)\n#define FPDF_ANNOT_FLAG_PRINT (1 << 2)\n#define FPDF_ANNOT_FLAG_NOZOOM (1 << 3)\n#define FPDF_ANNOT_FLAG_NOROTATE (1 << 4)\n#define FPDF_ANNOT_FLAG_NOVIEW (1 << 5)\n#define FPDF_ANNOT_FLAG_READONLY (1 << 6)\n#define FPDF_ANNOT_FLAG_LOCKED (1 << 7)\n#define FPDF_ANNOT_FLAG_TOGGLENOVIEW (1 << 8)\n\n#define FPDF_ANNOT_APPEARANCEMODE_NORMAL 0\n#define FPDF_ANNOT_APPEARANCEMODE_ROLLOVER 1\n#define FPDF_ANNOT_APPEARANCEMODE_DOWN 2\n#define FPDF_ANNOT_APPEARANCEMODE_COUNT 3\n\n// Refer to PDF Reference version 1.7 table 8.70 for field flags common to all\n// interactive form field types.\n#define FPDF_FORMFLAG_NONE 0\n#define FPDF_FORMFLAG_READONLY (1 << 0)\n#define FPDF_FORMFLAG_REQUIRED (1 << 1)\n#define FPDF_FORMFLAG_NOEXPORT (1 << 2)\n\n// Refer to PDF Reference version 1.7 table 8.77 for field flags specific to\n// interactive form text fields.\n#define FPDF_FORMFLAG_TEXT_MULTILINE (1 << 12)\n#define FPDF_FORMFLAG_TEXT_PASSWORD (1 << 13)\n\n// Refer to PDF Reference version 1.7 table 8.79 for field flags specific to\n// interactive form choice fields.\n#define FPDF_FORMFLAG_CHOICE_COMBO (1 << 17)\n#define FPDF_FORMFLAG_CHOICE_EDIT (1 << 18)\n#define FPDF_FORMFLAG_CHOICE_MULTI_SELECT (1 << 21)\n\n// Additional actions type of form field:\n//   K, on key stroke, JavaScript action.\n//   F, on format, JavaScript action.\n//   V, on validate, JavaScript action.\n//   C, on calculate, JavaScript action.\n#define FPDF_ANNOT_AACTION_KEY_STROKE 12\n#define FPDF_ANNOT_AACTION_FORMAT 13\n#define FPDF_ANNOT_AACTION_VALIDATE 14\n#define FPDF_ANNOT_AACTION_CALCULATE 15\n\ntypedef enum FPDFANNOT_COLORTYPE {\n  FPDFANNOT_COLORTYPE_Color = 0,\n  FPDFANNOT_COLORTYPE_InteriorColor\n} FPDFANNOT_COLORTYPE;\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for creation.\n// Currently supported subtypes:\n//    - circle\n//    - fileattachment\n//    - freetext\n//    - highlight\n//    - ink\n//    - link\n//    - popup\n//    - square,\n//    - squiggly\n//    - stamp\n//    - strikeout\n//    - text\n//    - underline\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Create an annotation in |page| of the subtype |subtype|. If the specified\n// subtype is illegal or unsupported, then a new annotation will not be created.\n// Must call FPDFPage_CloseAnnot() when the annotation returned by this\n// function is no longer needed.\n//\n//   page      - handle to a page.\n//   subtype   - the subtype of the new annotation.\n//\n// Returns a handle to the new annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFPage_CreateAnnot(FPDF_PAGE page, FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Get the number of annotations in |page|.\n//\n//   page   - handle to a page.\n//\n// Returns the number of annotations in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotCount(FPDF_PAGE page);\n\n// Experimental API.\n// Get annotation in |page| at |index|. Must call FPDFPage_CloseAnnot() when the\n// annotation returned by this function is no longer needed.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns a handle to the annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV FPDFPage_GetAnnot(FPDF_PAGE page,\n                                                            int index);\n\n// Experimental API.\n// Get the index of |annot| in |page|. This is the opposite of\n// FPDFPage_GetAnnot().\n//\n//   page  - handle to the page that the annotation is on.\n//   annot - handle to an annotation.\n//\n// Returns the index of |annot|, or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetAnnotIndex(FPDF_PAGE page,\n                                                     FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Close an annotation. Must be called when the annotation returned by\n// FPDFPage_CreateAnnot() or FPDFPage_GetAnnot() is no longer needed. This\n// function does not remove the annotation from the document.\n//\n//   annot  - handle to an annotation.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_CloseAnnot(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Remove the annotation in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of the annotation.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_RemoveAnnot(FPDF_PAGE page,\n                                                         int index);\n\n// Experimental API.\n// Get the subtype of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the annotation subtype.\nFPDF_EXPORT FPDF_ANNOTATION_SUBTYPE FPDF_CALLCONV\nFPDFAnnot_GetSubtype(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Check if an annotation subtype is currently supported for object extraction,\n// update, and removal.\n// Currently supported subtypes: ink and stamp.\n//\n//   subtype   - the subtype to be checked.\n//\n// Returns true if this subtype supported.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsObjectSupportedSubtype(FPDF_ANNOTATION_SUBTYPE subtype);\n\n// Experimental API.\n// Update |obj| in |annot|. |obj| must be in |annot| already and must have\n// been retrieved by FPDFAnnot_GetObject(). Currently, only ink and stamp\n// annotations are supported by this API. Also note that only path, image, and\n// text objects have APIs for modification; see FPDFPath_*(), FPDFText_*(), and\n// FPDFImageObj_*().\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that |annot| needs to update.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_UpdateObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Add a new InkStroke, represented by an array of points, to the InkList of\n// |annot|. The API creates an InkList if one doesn't already exist in |annot|.\n// This API works only for ink annotations. Please refer to ISO 32000-1:2008\n// spec, section 12.5.6.13.\n//\n//   annot       - handle to an annotation.\n//   points      - pointer to a FS_POINTF array representing input points.\n//   point_count - number of elements in |points| array. This should not exceed\n//                 the maximum value that can be represented by an int32_t).\n//\n// Returns the 0-based index at which the new InkStroke is added in the InkList\n// of the |annot|. Returns -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_AddInkStroke(FPDF_ANNOTATION annot,\n                                                     const FS_POINTF* points,\n                                                     size_t point_count);\n\n// Experimental API.\n// Removes an InkList in |annot|.\n// This API works only for ink annotations.\n//\n//   annot  - handle to an annotation.\n//\n// Return true on successful removal of /InkList entry from context of the\n// non-null ink |annot|. Returns false on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveInkList(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add |obj| to |annot|. |obj| must have been created by\n// FPDFPageObj_CreateNew{Path|Rect}() or FPDFPageObj_New{Text|Image}Obj(), and\n// will be owned by |annot|. Note that an |obj| cannot belong to more than one\n// |annot|. Currently, only ink and stamp annotations are supported by this API.\n// Also note that only path, image, and text objects have APIs for creation.\n//\n//   annot  - handle to an annotation.\n//   obj    - handle to the object that is to be added to |annot|.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendObject(FPDF_ANNOTATION annot, FPDF_PAGEOBJECT obj);\n\n// Experimental API.\n// Get the total number of objects in |annot|, including path objects, text\n// objects, external objects, image objects, and shading objects.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of objects in |annot|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetObjectCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object.\n//\n// Return a handle to the object, or NULL on failure.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFAnnot_GetObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Remove the object in |annot| at |index|.\n//\n//   annot  - handle to an annotation.\n//   index  - the index of the object to be removed.\n//\n// Return true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_RemoveObject(FPDF_ANNOTATION annot, int index);\n\n// Experimental API.\n// Set the color of an annotation. Fails when called on annotations with\n// appearance streams already defined; instead use\n// FPDFPageObj_Set{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color to be set.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int R,\n                                                       unsigned int G,\n                                                       unsigned int B,\n                                                       unsigned int A);\n\n// Experimental API.\n// Get the color of an annotation. If no color is specified, default to yellow\n// for highlight annotation, black for all else. Fails when called on\n// annotations with appearance streams already defined; instead use\n// FPDFPageObj_Get{Stroke|Fill}Color().\n//\n//   annot    - handle to an annotation.\n//   type     - type of the color requested.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//   A        - buffer to hold the opacity. Ranges from 0 to 255.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetColor(FPDF_ANNOTATION annot,\n                                                       FPDFANNOT_COLORTYPE type,\n                                                       unsigned int* R,\n                                                       unsigned int* G,\n                                                       unsigned int* B,\n                                                       unsigned int* A);\n\n// Experimental API.\n// Check if the annotation is of a type that has attachment points\n// (i.e. quadpoints). Quadpoints are the vertices of the rectangle that\n// encompasses the texts affected by the annotation. They provide the\n// coordinates in the page where the annotation is attached. Only text markup\n// annotations (i.e. highlight, strikeout, squiggly, and underline) and link\n// annotations have quadpoints.\n//\n//   annot  - handle to an annotation.\n//\n// Returns true if the annotation is of a type that has quadpoints, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_HasAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Replace the attachment points (i.e. quadpoints) set of an annotation at\n// |quad_index|. This index needs to be within the result of\n// FPDFAnnot_CountAttachmentPoints().\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Append to the list of attachment points (i.e. quadpoints) of an annotation.\n// If the annotation's appearance stream is defined and this annotation is of a\n// type with quadpoints, then update the bounding box too if the new quadpoints\n// define a bigger one.\n//\n//   annot       - handle to an annotation.\n//   quad_points - the quadpoints to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_AppendAttachmentPoints(FPDF_ANNOTATION annot,\n                                 const FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Get the number of sets of quadpoints of an annotation.\n//\n//   annot  - handle to an annotation.\n//\n// Returns the number of sets of quadpoints, or 0 on failure.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDFAnnot_CountAttachmentPoints(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the attachment points (i.e. quadpoints) of an annotation.\n//\n//   annot       - handle to an annotation.\n//   quad_index  - index of the set of quadpoints.\n//   quad_points - receives the quadpoints; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetAttachmentPoints(FPDF_ANNOTATION annot,\n                              size_t quad_index,\n                              FS_QUADPOINTSF* quad_points);\n\n// Experimental API.\n// Set the annotation rectangle defining the location of the annotation. If the\n// annotation's appearance stream is defined and this annotation is of a type\n// without quadpoints, then update the bounding box too if the new rectangle\n// defines a bigger one.\n//\n//   annot  - handle to an annotation.\n//   rect   - the annotation rectangle to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetRect(FPDF_ANNOTATION annot,\n                                                      const FS_RECTF* rect);\n\n// Experimental API.\n// Get the annotation rectangle defining the location of the annotation.\n//\n//   annot  - handle to an annotation.\n//   rect   - receives the rectangle; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetRect(FPDF_ANNOTATION annot,\n                                                      FS_RECTF* rect);\n\n// Experimental API.\n// Get the vertices of a polygon or polyline annotation. |buffer| is an array of\n// points of the annotation. If |length| is less than the returned length, or\n// |annot| or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points if the annotation is of type polygon or\n// polyline, 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetVertices(FPDF_ANNOTATION annot,\n                      FS_POINTF* buffer,\n                      unsigned long length);\n\n// Experimental API.\n// Get the number of paths in the ink list of an ink annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//\n// Returns the number of paths in the ink list if the annotation is of type ink,\n// 0 otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListCount(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get a path in the ink list of an ink annotation. |buffer| is an array of\n// points of the path. If |length| is less than the returned length, or |annot|\n// or |buffer| is NULL, |buffer| will not be modified.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   path_index - index of the path\n//   buffer - buffer for holding the points.\n//   length - length of the buffer in points.\n//\n// Returns the number of points of the path if the annotation is of type ink, 0\n// otherwise.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetInkListPath(FPDF_ANNOTATION annot,\n                         unsigned long path_index,\n                         FS_POINTF* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Get the starting and ending coordinates of a line annotation.\n//\n//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()\n//   start - starting point\n//   end - ending point\n//\n// Returns true if the annotation is of type line, |start| and |end| are not\n// NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,\n                                                      FS_POINTF* start,\n                                                      FS_POINTF* end);\n\n// Experimental API.\n// Set the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if setting the border for |annot| succeeds, false otherwise.\n//\n// If |annot| contains an appearance stream that overrides the border values,\n// then the appearance stream will be removed on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetBorder(FPDF_ANNOTATION annot,\n                                                        float horizontal_radius,\n                                                        float vertical_radius,\n                                                        float border_width);\n\n// Experimental API.\n// Get the characteristics of the annotation's border (rounded rectangle).\n//\n//   annot              - handle to an annotation\n//   horizontal_radius  - horizontal corner radius, in default user space units\n//   vertical_radius    - vertical corner radius, in default user space units\n//   border_width       - border width, in default user space units\n//\n// Returns true if |horizontal_radius|, |vertical_radius| and |border_width| are\n// not NULL, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetBorder(FPDF_ANNOTATION annot,\n                    float* horizontal_radius,\n                    float* vertical_radius,\n                    float* border_width);\n\n// Experimental API.\n// Get the JavaScript of an event of the annotation's additional actions.\n// |buffer| is only modified if |buflen| is large enough to hold the whole\n// JavaScript string. If |buflen| is smaller, the total size of the JavaScript\n// is still returned, but nothing is copied.  If there is no JavaScript for\n// |event| in |annot|, an empty string is written to |buf| and 2 is returned,\n// denoting the size of the null terminator in the buffer.  On other errors,\n// nothing is written to |buffer| and 0 is returned.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    event       -   event type, one of the FPDF_ANNOT_AACTION_* values.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes, including the 2-byte\n// null terminator.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormAdditionalActionJavaScript(FPDF_FORMHANDLE hHandle,\n                                            FPDF_ANNOTATION annot,\n                                            int event,\n                                            FPDF_WCHAR* buffer,\n                                            unsigned long buflen);\n\n// Experimental API.\n// Check if |annot|'s dictionary has |key| as a key.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,\n                                                     FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in |annot|'s dictionary.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAnnot_GetValueType(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in |annot|'s dictionary,\n// overwriting the existing value if any. The value type would be\n// FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the dictionary entry to be set, encoded in UTF-8.\n//   value  - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in |annot|'s dictionary. |buffer|\n// is only modified if |buflen| is longer than the length of contents. Note that\n// if |key| does not exist in the dictionary or if |key|'s corresponding value\n// in the dictionary is not a string (i.e. the value is not of type\n// FPDF_OBJECT_STRING or FPDF_OBJECT_NAME), then an empty string would be copied\n// to |buffer| and the return value would be 2. On other errors, nothing would\n// be added to |buffer| and the return value would be 0.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   buffer - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Get the float value corresponding to |key| in |annot|'s dictionary. Writes\n// value to |value| and returns True if |key| exists in the dictionary and\n// |key|'s corresponding value is a number (FPDF_OBJECT_NUMBER), False\n// otherwise.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//   value  - receives the value, must not be NULL.\n//\n// Returns True if value found, False otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetNumberValue(FPDF_ANNOTATION annot,\n                         FPDF_BYTESTRING key,\n                         float* value);\n\n// Experimental API.\n// Set the AP (appearance string) in |annot|'s dictionary for a given\n// |appearanceMode|.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   value          - the string value to be set, encoded in UTF-16LE. If\n//                    nullptr is passed, the AP is cleared for that mode. If the\n//                    mode is Normal, APs for all modes are cleared.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the AP (appearance string) from |annot|'s dictionary for a given\n// |appearanceMode|.\n// |buffer| is only modified if |buflen| is large enough to hold the whole AP\n// string. If |buflen| is smaller, the total size of the AP is still returned,\n// but nothing is copied.\n// If there is no appearance stream for |annot| in |appearanceMode|, an empty\n// string is written to |buf| and 2 is returned.\n// On other errors, nothing is written to |buffer| and 0 is returned.\n//\n//   annot          - handle to an annotation.\n//   appearanceMode - the appearance mode (normal, rollover or down) for which\n//                    to get the AP.\n//   buffer         - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen         - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetAP(FPDF_ANNOTATION annot,\n                FPDF_ANNOT_APPEARANCEMODE appearanceMode,\n                FPDF_WCHAR* buffer,\n                unsigned long buflen);\n\n// Experimental API.\n// Get the annotation corresponding to |key| in |annot|'s dictionary. Common\n// keys for linking annotations include \"IRT\" and \"Popup\". Must call\n// FPDFPage_CloseAnnot() when the annotation returned by this function is no\n// longer needed.\n//\n//   annot  - handle to an annotation.\n//   key    - the key to the requested dictionary entry, encoded in UTF-8.\n//\n// Returns a handle to the linked annotation object, or NULL on failure.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetLinkedAnnot(FPDF_ANNOTATION annot, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//   annot    - handle to an annotation.\n//\n// Returns the annotation flags.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetFlags(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the |annot|'s flags to be of the value |flags|.\n//\n//   annot      - handle to an annotation.\n//   flags      - the flag values to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetFlags(FPDF_ANNOTATION annot,\n                                                       int flags);\n\n// Experimental API.\n// Get the annotation flags of |annot|.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the annotation flags specific to interactive forms.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Sets the form field flags for an interactive form annotation.\n//\n//   handle       -   the handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//   annot        -   handle to an interactive form annotation.\n//   flags        -   the form field flags to be set.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFormFieldFlags(FPDF_FORMHANDLE handle,\n                            FPDF_ANNOTATION annot,\n                            int flags);\n\n// Experimental API.\n// Retrieves an interactive form annotation whose rectangle contains a given\n// point on a page. Must call FPDFPage_CloseAnnot() when the annotation returned\n// is no longer needed.\n//\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    page        -   handle to the page, returned by FPDF_LoadPage function.\n//    point       -   position in PDF \"user space\".\n//\n// Returns the interactive form annotation whose rectangle contains the given\n// coordinates on the page. If there is no such annotation, return NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                              FPDF_PAGE page,\n                              const FS_POINTF* point);\n\n// Experimental API.\n// Gets the name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the name string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldName(FPDF_FORMHANDLE hHandle,\n                           FPDF_ANNOTATION annot,\n                           FPDF_WCHAR* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Gets the alternate name of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the alternate name string, encoded in\n//                    UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldAlternateName(FPDF_FORMHANDLE hHandle,\n                                    FPDF_ANNOTATION annot,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen);\n\n// Experimental API.\n// Gets the form field type of |annot|, which is an interactive form annotation.\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//\n// Returns the type of the form field (one of the FPDF_FORMFIELD_* values) on\n// success. Returns -1 on error.\n// See field types in fpdf_formfill.h.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormFieldType(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the value of |annot|, which is an interactive form annotation.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value will\n// be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldValue(FPDF_FORMHANDLE hHandle,\n                            FPDF_ANNOTATION annot,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen);\n\n// Experimental API.\n// Get the number of options in the |annot|'s \"Opt\" dictionary. Intended for\n// use with listbox and combobox widget annotations.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns the number of options in \"Opt\" dictionary on success. Return value\n// will be -1 if annotation does not have an \"Opt\" dictionary or other error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAnnot_GetOptionCount(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Get the string value for the label of the option at |index| in |annot|'s\n// \"Opt\" dictionary. Intended for use with listbox and combobox widget\n// annotations. |buffer| is only modified if |buflen| is longer than the length\n// of contents. If index is out of range or in case of other error, nothing\n// will be added to |buffer| and the return value will be 0. Note that\n// return value of empty string is 2 for \"\\0\\0\".\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array\n//   buffer  - buffer for holding the value string, encoded in UTF-16LE.\n//   buflen  - length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\n// If |annot| does not have an \"Opt\" array, |index| is out of range or if any\n// other error occurs, returns 0.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,\n                         FPDF_ANNOTATION annot,\n                         int index,\n                         FPDF_WCHAR* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Determine whether or not the option at |index| in |annot|'s \"Opt\" dictionary\n// is selected. Intended for use with listbox and combobox widget annotations.\n//\n//   handle  - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   index   - numeric index of the option in the \"Opt\" array.\n//\n// Returns true if the option at |index| in |annot|'s \"Opt\" dictionary is\n// selected, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,\n                           FPDF_ANNOTATION annot,\n                           int index);\n\n// Experimental API.\n// Get the float value of the font size for an |annot| with variable text.\n// If 0, the font is to be auto-sized: its size is computed as a function of\n// the height of the annotation rectangle.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//   value   - Required. Float which will be set to font size on success.\n//\n// Returns true if the font size was set in |value|, false on error or if\n// |value| not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontSize(FPDF_FORMHANDLE hHandle,\n                      FPDF_ANNOTATION annot,\n                      float* value);\n\n// Experimental API.\n// Set the text color of an annotation.\n//\n//   handle   - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R        - the red component for the text color.\n//   G        - the green component for the text color.\n//   B        - the blue component for the text color.\n//\n// Returns true if successful.\n//\n// Currently supported subtypes: freetext.\n// The range for the color components is 0 to 255.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int R,\n                       unsigned int G,\n                       unsigned int B);\n\n// Experimental API.\n// Get the RGB value of the font color for an |annot| with variable text.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   annot    - handle to an annotation.\n//   R, G, B  - buffer to hold the RGB value of the color. Ranges from 0 to 255.\n//\n// Returns true if the font color was set, false on error or if the font\n// color was not provided.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle,\n                       FPDF_ANNOTATION annot,\n                       unsigned int* R,\n                       unsigned int* G,\n                       unsigned int* B);\n\n// Experimental API.\n// Determine if |annot| is a form widget that is checked. Intended for use with\n// checkbox and radio button widgets.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns true if |annot| is a form widget and is checked, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_IsChecked(FPDF_FORMHANDLE hHandle,\n                                                        FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Set the list of focusable annotation subtypes. Annotations of subtype\n// FPDF_ANNOT_WIDGET are by default focusable. New subtypes set using this API\n// will override the existing subtypes.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - list of annotation subtype which can be tabbed over.\n//   count    - total number of annotation subtype in list.\n// Returns true if list of annotation subtype is set successfully, false\n// otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_SetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               const FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Get the count of focusable annotation subtypes as set by host\n// for a |hHandle|.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n// Returns the count of focusable annotation subtypes or -1 on error.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypesCount(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Get the list of focusable annotation subtype as set by host.\n//\n//   hHandle  - handle to the form fill module, returned by\n//              FPDFDOC_InitFormFillEnvironment.\n//   subtypes - receives the list of annotation subtype which can be tabbed\n//              over. Caller must have allocated |subtypes| more than or\n//              equal to the count obtained from\n//              FPDFAnnot_GetFocusableSubtypesCount() API.\n//   count    - size of |subtypes|.\n// Returns true on success and set list of annotation subtype to |subtypes|,\n// false otherwise.\n// Note : Annotations of type FPDF_ANNOT_WIDGET are by default focusable.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAnnot_GetFocusableSubtypes(FPDF_FORMHANDLE hHandle,\n                               FPDF_ANNOTATION_SUBTYPE* subtypes,\n                               size_t count);\n\n// Experimental API.\n// Gets FPDF_LINK object for |annot|. Intended to use for link annotations.\n//\n//   annot   - handle to an annotation.\n//\n// Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure,\n// if the input annot is NULL or input annot's subtype is not link.\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the count of annotations in the |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns number of controls in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlCount(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the index of |annot| in |annot|'s control group.\n// A group of interactive form annotations is collectively called a form\n// control group. Here, |annot|, an interactive form annotation, should be\n// either a radio button or a checkbox.\n//\n//   hHandle - handle to the form fill module, returned by\n//             FPDFDOC_InitFormFillEnvironment.\n//   annot   - handle to an annotation.\n//\n// Returns index of a given |annot| in its control group or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFAnnot_GetFormControlIndex(FPDF_FORMHANDLE hHandle, FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Gets the export value of |annot| which is an interactive form annotation.\n// Intended for use with radio button and checkbox widget annotations.\n// |buffer| is only modified if |buflen| is longer than the length of contents.\n// In case of error, nothing will be added to |buffer| and the return value\n// will be 0. Note that return value of empty string is 2 for \"\\0\\0\".\n//\n//    hHandle     -   handle to the form fill module, returned by\n//                    FPDFDOC_InitFormFillEnvironment().\n//    annot       -   handle to an interactive form annotation.\n//    buffer      -   buffer for holding the value string, encoded in UTF-16LE.\n//    buflen      -   length of the buffer in bytes.\n//\n// Returns the length of the string value in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAnnot_GetFormFieldExportValue(FPDF_FORMHANDLE hHandle,\n                                  FPDF_ANNOTATION annot,\n                                  FPDF_WCHAR* buffer,\n                                  unsigned long buflen);\n\n// Experimental API.\n// Add a URI action to |annot|, overwriting the existing action, if any.\n//\n//   annot  - handle to a link annotation.\n//   uri    - the URI to be set, encoded in 7-bit ASCII.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_SetURI(FPDF_ANNOTATION annot,\n                                                     const char* uri);\n\n// Experimental API.\n// Get the attachment from |annot|.\n//\n//   annot - handle to a file annotation.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_GetFileAttachment(FPDF_ANNOTATION annot);\n\n// Experimental API.\n// Add an embedded file with |name| to |annot|.\n//\n//   annot    - handle to a file annotation.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFAnnot_AddFileAttachment(FPDF_ANNOTATION annot, FPDF_WIDESTRING name);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ANNOT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_attachment.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_ATTACHMENT_H_\n#define PUBLIC_FPDF_ATTACHMENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of embedded files in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of embedded files in |document|.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Add an embedded file with |name| in |document|. If |name| is empty, or if\n// |name| is the name of a existing embedded file in |document|, or if\n// |document|'s embedded file name tree is too deep (i.e. |document| has too\n// many embedded files already), then a new attachment will not be added.\n//\n//   document - handle to a document.\n//   name     - name of the new attachment.\n//\n// Returns a handle to the new attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name);\n\n// Experimental API.\n// Get the embedded attachment at |index| in |document|. Note that the returned\n// attachment handle is only valid while |document| is open.\n//\n//   document - handle to a document.\n//   index    - the index of the requested embedded file.\n//\n// Returns the handle to the attachment object, or NULL on failure.\nFPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV\nFPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Delete the embedded attachment at |index| in |document|. Note that this does\n// not remove the attachment data from the PDF file; it simply removes the\n// file's entry in the embedded files name tree so that it does not appear in\n// the attachment list. This behavior may change in the future.\n//\n//   document - handle to a document.\n//   index    - the index of the embedded file to be deleted.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Get the name of the |attachment| file. |buffer| is only modified if |buflen|\n// is longer than the length of the file name. On errors, |buffer| is unmodified\n// and the returned length is 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the file name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetName(FPDF_ATTACHMENT attachment,\n                       FPDF_WCHAR* buffer,\n                       unsigned long buflen);\n\n// Experimental API.\n// Check if the params dictionary of |attachment| has |key| as a key.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns true if |key| exists.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the type of the value corresponding to |key| in the params dictionary of\n// the embedded |attachment|.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to look for, encoded in UTF-8.\n//\n// Returns the type of the dictionary value.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key);\n\n// Experimental API.\n// Set the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|, overwriting the existing value if any. The value\n// type should be FPDF_OBJECT_STRING after this function call succeeds.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the dictionary entry, encoded in UTF-8.\n//   value      - the string value to be set, encoded in UTF-16LE.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WIDESTRING value);\n\n// Experimental API.\n// Get the string value corresponding to |key| in the params dictionary of the\n// embedded file |attachment|. |buffer| is only modified if |buflen| is longer\n// than the length of the string value. Note that if |key| does not exist in the\n// dictionary or if |key|'s corresponding value in the dictionary is not a\n// string (i.e. the value is not of type FPDF_OBJECT_STRING or\n// FPDF_OBJECT_NAME), then an empty string would be copied to |buffer| and the\n// return value would be 2. On other errors, nothing would be added to |buffer|\n// and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   key        - the key to the requested string value, encoded in UTF-8.\n//   buffer     - buffer for holding the string value encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the dictionary value string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,\n                              FPDF_BYTESTRING key,\n                              FPDF_WCHAR* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Set the file data of |attachment|, overwriting the existing file data if any.\n// The creation date and checksum will be updated, while all other dictionary\n// entries will be deleted. Note that only contents with |len| smaller than\n// INT_MAX is supported.\n//\n//   attachment - handle to an attachment.\n//   contents   - buffer holding the file data to write to |attachment|.\n//   len        - length of file data in bytes.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,\n                       FPDF_DOCUMENT document,\n                       const void* contents,\n                       unsigned long len);\n\n// Experimental API.\n// Get the file data of |attachment|.\n// When the attachment file data is readable, true is returned, and |out_buflen|\n// is updated to indicate the file data size. |buffer| is only modified if\n// |buflen| is non-null and long enough to contain the entire file data. Callers\n// must check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data.\n//\n// Otherwise, when the attachment file data is unreadable or when |out_buflen|\n// is null, false is returned and |buffer| and |out_buflen| remain unmodified.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the file data from |attachment|.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to the variable that will receive the minimum buffer\n//                size to contain the file data of |attachment|.\n//\n// Returns true on success, false otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,\n                       void* buffer,\n                       unsigned long buflen,\n                       unsigned long* out_buflen);\n\n// Experimental API.\n// Get the MIME type (Subtype) of the embedded file |attachment|. |buffer| is\n// only modified if |buflen| is longer than the length of the MIME type string.\n// If the Subtype is not found or if there is no file stream, an empty string\n// would be copied to |buffer| and the return value would be 2. On other errors,\n// nothing would be added to |buffer| and the return value would be 0.\n//\n//   attachment - handle to an attachment.\n//   buffer     - buffer for holding the MIME type string encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the MIME type string in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAttachment_GetSubtype(FPDF_ATTACHMENT attachment,\n                          FPDF_WCHAR* buffer,\n                          unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_ATTACHMENT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_catalog.h",
    "content": "// Copyright 2017 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_CATALOG_H_\n#define PUBLIC_FPDF_CATALOG_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n//\n// Determine if |document| represents a tagged PDF.\n//\n// For the definition of tagged PDF, See (see 10.7 \"Tagged PDF\" in PDF\n// Reference 1.7).\n//\n//   document - handle to a document.\n//\n// Returns |true| iff |document| is a tagged PDF.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_IsTagged(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Gets the language of |document| from the catalog's /Lang entry.\n//\n//   document - handle to a document.\n//   buffer   - a buffer for the language string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the language string, including the\n// trailing NUL character. The number of bytes is returned regardless of the\n// |buffer| and |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE\n// encoding. The string is terminated by a UTF16 NUL character. If\n// |buflen| is less than the required length, or |buffer| is NULL,\n// |buffer| will not be modified.\n//\n// If |document| has no /Lang entry, an empty string is written to |buffer| and\n// 2 is returned. On error, nothing is written to |buffer| and 0 is returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFCatalog_GetLanguage(FPDF_DOCUMENT document,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen);\n\n// Experimental API.\n// Sets the language of |document| to |language|.\n//\n// document - handle to a document.\n// language - the language to set to.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFCatalog_SetLanguage(FPDF_DOCUMENT document, FPDF_WIDESTRING language);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_CATALOG_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_dataavail.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DATAAVAIL_H_\n#define PUBLIC_FPDF_DATAAVAIL_H_\n\n#include <stddef.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#define PDF_LINEARIZATION_UNKNOWN -1\n#define PDF_NOT_LINEARIZED 0\n#define PDF_LINEARIZED 1\n\n#define PDF_DATA_ERROR -1\n#define PDF_DATA_NOTAVAIL 0\n#define PDF_DATA_AVAIL 1\n\n#define PDF_FORM_ERROR -1\n#define PDF_FORM_NOTAVAIL 0\n#define PDF_FORM_AVAIL 1\n#define PDF_FORM_NOTEXIST 2\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Interface for checking whether sections of the file are available.\ntypedef struct _FX_FILEAVAIL {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Reports if the specified data section is currently available. A section is\n  // available if all bytes in the section are available.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the data section in the file.\n  //   size   - the size of the data section.\n  //\n  // Returns true if the specified data section at |offset| of |size|\n  // is available.\n  FPDF_BOOL (*IsDataAvail)(struct _FX_FILEAVAIL* pThis,\n                           size_t offset,\n                           size_t size);\n} FX_FILEAVAIL;\n\n// Create a document availability provider.\n//\n//   file_avail - pointer to file availability interface.\n//   file       - pointer to a file access interface.\n//\n// Returns a handle to the document availability provider, or NULL on error.\n//\n// FPDFAvail_Destroy() must be called when done with the availability provider.\nFPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL* file_avail,\n                                                      FPDF_FILEACCESS* file);\n\n// Destroy the |avail| document availability provider.\n//\n//   avail - handle to document availability provider to be destroyed.\nFPDF_EXPORT void FPDF_CALLCONV FPDFAvail_Destroy(FPDF_AVAIL avail);\n\n// Download hints interface. Used to receive hints for further downloading.\ntypedef struct _FX_DOWNLOADHINTS {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Add a section to be downloaded.\n  //\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis  - pointer to the interface structure.\n  //   offset - the offset of the hint reported to be downloaded.\n  //   size   - the size of the hint reported to be downloaded.\n  //\n  // The |offset| and |size| of the section may not be unique. Part of the\n  // section might be already available. The download manager must deal with\n  // overlapping sections.\n  void (*AddSegment)(struct _FX_DOWNLOADHINTS* pThis,\n                     size_t offset,\n                     size_t size);\n} FX_DOWNLOADHINTS;\n\n// Checks if the document is ready for loading, if not, gets download hints.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// Applications should call this function whenever new data arrives, and process\n// all the generated download hints, if any, until the function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|.\n// if hints is nullptr, the function just check current document availability.\n//\n// Once all data is available, call FPDFAvail_GetDocument() to get a document\n// handle.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsDocAvail(FPDF_AVAIL avail,\n                                                   FX_DOWNLOADHINTS* hints);\n\n// Get document from the availability provider.\n//\n//   avail    - handle to document availability provider.\n//   password - password for decrypting the PDF file. Optional.\n//\n// Returns a handle to the document.\n//\n// When FPDFAvail_IsDocAvail() returns TRUE, call FPDFAvail_GetDocument() to\n// retrieve the document handle.\n// See the comments for FPDF_LoadDocument() regarding the encoding for\n// |password|.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDFAvail_GetDocument(FPDF_AVAIL avail, FPDF_BYTESTRING password);\n\n// Get the page number for the first available page in a linearized PDF.\n//\n//   doc - document handle.\n//\n// Returns the zero-based index for the first available page.\n//\n// For most linearized PDFs, the first available page will be the first page,\n// however, some PDFs might make another page the first available page.\n// For non-linearized PDFs, this function will always return zero.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_GetFirstPageNum(FPDF_DOCUMENT doc);\n\n// Check if |page_index| is ready for loading, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail      - handle to document availability provider.\n//   page_index - index number of the page. Zero for the first page.\n//   hints      - pointer to a download hints interface. Populated if\n//                |page_index| is not available.\n//\n// Returns one of:\n//   PDF_DATA_ERROR: A common error is returned. Data availability unknown.\n//   PDF_DATA_NOTAVAIL: Data not yet available.\n//   PDF_DATA_AVAIL: Data available.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// Applications should call this function whenever new data arrives and process\n// all the generated download |hints|, if any, until this function returns\n// |PDF_DATA_ERROR| or |PDF_DATA_AVAIL|. Applications can then perform page\n// loading.\n// if hints is nullptr, the function just check current availability of\n// specified page.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsPageAvail(FPDF_AVAIL avail,\n                                                    int page_index,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check if form data is ready for initialization, if not, get the\n// |FX_DOWNLOADHINTS|.\n//\n//   avail - handle to document availability provider.\n//   hints - pointer to a download hints interface. Populated if form is not\n//           ready for initialization.\n//\n// Returns one of:\n//   PDF_FORM_ERROR: A common eror, in general incorrect parameters.\n//   PDF_FORM_NOTAVAIL: Data not available.\n//   PDF_FORM_AVAIL: Data available.\n//   PDF_FORM_NOTEXIST: No form data.\n//\n// This function can be called only after FPDFAvail_GetDocument() is called.\n// The application should call this function whenever new data arrives and\n// process all the generated download |hints|, if any, until the function\n// |PDF_FORM_ERROR|, |PDF_FORM_AVAIL| or |PDF_FORM_NOTEXIST|.\n// if hints is nullptr, the function just check current form availability.\n//\n// Applications can then perform page loading. It is recommend to call\n// FPDFDOC_InitFormFillEnvironment() when |PDF_FORM_AVAIL| is returned.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsFormAvail(FPDF_AVAIL avail,\n                                                    FX_DOWNLOADHINTS* hints);\n\n// Check whether a document is a linearized PDF.\n//\n//   avail - handle to document availability provider.\n//\n// Returns one of:\n//   PDF_LINEARIZED\n//   PDF_NOT_LINEARIZED\n//   PDF_LINEARIZATION_UNKNOWN\n//\n// FPDFAvail_IsLinearized() will return |PDF_LINEARIZED| or |PDF_NOT_LINEARIZED|\n// when we have 1k  of data. If the files size less than 1k, it returns\n// |PDF_LINEARIZATION_UNKNOWN| as there is insufficient information to determine\n// if the PDF is linearlized.\nFPDF_EXPORT int FPDF_CALLCONV FPDFAvail_IsLinearized(FPDF_AVAIL avail);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DATAAVAIL_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_doc.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_DOC_H_\n#define PUBLIC_FPDF_DOC_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported action type.\n#define PDFACTION_UNSUPPORTED 0\n// Go to a destination within current document.\n#define PDFACTION_GOTO 1\n// Go to a destination within another document.\n#define PDFACTION_REMOTEGOTO 2\n// URI, including web pages and other Internet resources.\n#define PDFACTION_URI 3\n// Launch an application or open a file.\n#define PDFACTION_LAUNCH 4\n// Go to a destination in an embedded file.\n#define PDFACTION_EMBEDDEDGOTO 5\n\n// View destination fit types. See pdfmark reference v9, page 48.\n#define PDFDEST_VIEW_UNKNOWN_MODE 0\n#define PDFDEST_VIEW_XYZ 1\n#define PDFDEST_VIEW_FIT 2\n#define PDFDEST_VIEW_FITH 3\n#define PDFDEST_VIEW_FITV 4\n#define PDFDEST_VIEW_FITR 5\n#define PDFDEST_VIEW_FITB 6\n#define PDFDEST_VIEW_FITBH 7\n#define PDFDEST_VIEW_FITBV 8\n\n// The file identifier entry type. See section 14.4 \"File Identifiers\" of the\n// ISO 32000-1:2008 spec.\ntypedef enum {\n  FILEIDTYPE_PERMANENT = 0,\n  FILEIDTYPE_CHANGING = 1\n} FPDF_FILEIDTYPE;\n\n// Get the first child of |bookmark|, or the first top-level bookmark item.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark. Pass NULL for the first top\n//              level item.\n//\n// Returns a handle to the first child of |bookmark| or the first top-level\n// bookmark item. NULL if no child or top-level bookmark found.\n// Note that another name for the bookmarks is the document outline, as\n// described in ISO 32000-1:2008, section 12.3.3.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the next sibling of |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the current bookmark.\n//\n// Returns a handle to the next sibling of |bookmark|, or NULL if this is the\n// last bookmark at this level.\n//\n// Note that the caller is responsible for handling circular bookmark\n// references, as may arise from malformed documents.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the title of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//   buffer   - buffer for the title. May be NULL.\n//   buflen   - the length of the buffer in bytes. May be 0.\n//\n// Returns the number of bytes in the title, including the terminating NUL\n// character. The number of bytes is returned regardless of the |buffer| and\n// |buflen| parameters.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |buflen| is less than the\n// required length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFBookmark_GetTitle(FPDF_BOOKMARK bookmark,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Experimental API.\n// Get the number of chlidren of |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns a signed integer that represents the number of sub-items the given\n// bookmark has. If the value is positive, child items shall be shown by default\n// (open state). If the value is negative, child items shall be hidden by\n// default (closed state). Please refer to PDF 32000-1:2008, Table 153.\n// Returns 0 if the bookmark has no children or is invalid.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBookmark_GetCount(FPDF_BOOKMARK bookmark);\n\n// Find the bookmark with |title| in |document|.\n//\n//   document - handle to the document.\n//   title    - the UTF-16LE encoded Unicode title for which to search.\n//\n// Returns the handle to the bookmark, or NULL if |title| can't be found.\n//\n// FPDFBookmark_Find() will always return the first bookmark found even if\n// multiple bookmarks have the same |title|.\nFPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV\nFPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title);\n\n// Get the destination associated with |bookmark|.\n//\n//   document - handle to the document.\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the destination data, or NULL if no destination is\n// associated with |bookmark|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK bookmark);\n\n// Get the action associated with |bookmark|.\n//\n//   bookmark - handle to the bookmark.\n//\n// Returns the handle to the action data, or NULL if no action is associated\n// with |bookmark|.\n// If this function returns a valid handle, it is valid as long as |bookmark| is\n// valid.\n// If this function returns NULL, FPDFBookmark_GetDest() should be called to get\n// the |bookmark| destination data.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV\nFPDFBookmark_GetAction(FPDF_BOOKMARK bookmark);\n\n// Get the type of |action|.\n//\n//   action - handle to the action.\n//\n// Returns one of:\n//   PDFACTION_UNSUPPORTED\n//   PDFACTION_GOTO\n//   PDFACTION_REMOTEGOTO\n//   PDFACTION_URI\n//   PDFACTION_LAUNCH\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION action);\n\n// Get the destination of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. |action| must be a |PDFACTION_GOTO| or\n//              |PDFACTION_REMOTEGOTO|.\n//\n// Returns a handle to the destination data, or NULL on error, typically\n// because the arguments were bad or the action was of the wrong type.\n//\n// In the case of |PDFACTION_REMOTEGOTO|, you must first call\n// FPDFAction_GetFilePath(), then load the document at that path, then pass\n// the document handle from that document as |document| to FPDFAction_GetDest().\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document,\n                                                       FPDF_ACTION action);\n\n// Get the file path of |action|.\n//\n//   action - handle to the action. |action| must be a |PDFACTION_LAUNCH| or\n//            |PDFACTION_REMOTEGOTO|.\n//   buffer - a buffer for output the path string. May be NULL.\n//   buflen - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetFilePath(FPDF_ACTION action, void* buffer, unsigned long buflen);\n\n// Get the URI path of |action|.\n//\n//   document - handle to the document.\n//   action   - handle to the action. Must be a |PDFACTION_URI|.\n//   buffer   - a buffer for the path string. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the URI path, including the trailing NUL\n// character, or 0 on error, typically because the arguments were bad or the\n// action was of the wrong type.\n//\n// The |buffer| may contain badly encoded data. The caller should validate the\n// output. e.g. Check to see if it is UTF-8.\n//\n// If |buflen| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\n//\n// Historically, the documentation for this API claimed |buffer| is always\n// encoded in 7-bit ASCII, but did not actually enforce it.\n// https://pdfium.googlesource.com/pdfium.git/+/d609e84cee2e14a18333247485af91df48a40592\n// added that enforcement, but that did not work well for real world PDFs that\n// used UTF-8. As of this writing, this API reverted back to its original\n// behavior prior to commit d609e84cee.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFAction_GetURIPath(FPDF_DOCUMENT document,\n                      FPDF_ACTION action,\n                      void* buffer,\n                      unsigned long buflen);\n\n// Get the page index of |dest|.\n//\n//   document - handle to the document.\n//   dest     - handle to the destination.\n//\n// Returns the 0-based page index containing |dest|. Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document,\n                                                        FPDF_DEST dest);\n\n// Experimental API.\n// Get the view (fit type) specified by |dest|.\n//\n//   dest         - handle to the destination.\n//   pNumParams   - receives the number of view parameters, which is at most 4.\n//   pParams      - buffer to write the view parameters. Must be at least 4\n//                  FS_FLOATs long.\n// Returns one of the PDFDEST_VIEW_* constants, PDFDEST_VIEW_UNKNOWN_MODE if\n// |dest| does not specify a view.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFDest_GetView(FPDF_DEST dest, unsigned long* pNumParams, FS_FLOAT* pParams);\n\n// Get the (x, y, zoom) location of |dest| in the destination page, if the\n// destination is in [page /XYZ x y zoom] syntax.\n//\n//   dest       - handle to the destination.\n//   hasXVal    - out parameter; true if the x value is not null\n//   hasYVal    - out parameter; true if the y value is not null\n//   hasZoomVal - out parameter; true if the zoom value is not null\n//   x          - out parameter; the x coordinate, in page coordinates.\n//   y          - out parameter; the y coordinate, in page coordinates.\n//   zoom       - out parameter; the zoom value.\n// Returns TRUE on successfully reading the /XYZ value.\n//\n// Note the [x, y, zoom] values are only set if the corresponding hasXVal,\n// hasYVal or hasZoomVal flags are true.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFDest_GetLocationInPage(FPDF_DEST dest,\n                           FPDF_BOOL* hasXVal,\n                           FPDF_BOOL* hasYVal,\n                           FPDF_BOOL* hasZoomVal,\n                           FS_FLOAT* x,\n                           FS_FLOAT* y,\n                           FS_FLOAT* zoom);\n\n// Find a link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns a handle to the link, or NULL if no link found at the given point.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Find the Z-order of link at point (|x|,|y|) on |page|.\n//\n//   page - handle to the document page.\n//   x    - the x coordinate, in the page coordinate system.\n//   y    - the y coordinate, in the page coordinate system.\n//\n// Returns the Z-order of the link, or -1 if no link found at the given point.\n// Larger Z-order numbers are closer to the front.\n//\n// You can convert coordinates from screen coordinates to page coordinates using\n// FPDF_DeviceToPage().\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page,\n                                                            double x,\n                                                            double y);\n\n// Get destination info for |link|.\n//\n//   document - handle to the document.\n//   link     - handle to the link.\n//\n// Returns a handle to the destination, or NULL if there is no destination\n// associated with the link. In this case, you should call FPDFLink_GetAction()\n// to retrieve the action associated with |link|.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document,\n                                                     FPDF_LINK link);\n\n// Get action info for |link|.\n//\n//   link - handle to the link.\n//\n// Returns a handle to the action associated to |link|, or NULL if no action.\n// If this function returns a valid handle, it is valid as long as |link| is\n// valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK link);\n\n// Enumerates all the link annotations in |page|.\n//\n//   page       - handle to the page.\n//   start_pos  - the start position, should initially be 0 and is updated with\n//                the next start position on return.\n//   link_annot - the link handle for |startPos|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page,\n                                                       int* start_pos,\n                                                       FPDF_LINK* link_annot);\n\n// Experimental API.\n// Gets FPDF_ANNOTATION object for |link_annot|.\n//\n//   page       - handle to the page in which FPDF_LINK object is present.\n//   link_annot - handle to link annotation.\n//\n// Returns FPDF_ANNOTATION from the FPDF_LINK and NULL on failure,\n// if the input link annot or page is NULL.\nFPDF_EXPORT FPDF_ANNOTATION FPDF_CALLCONV\nFPDFLink_GetAnnot(FPDF_PAGE page, FPDF_LINK link_annot);\n\n// Get the rectangle for |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//   rect       - the annotation rectangle.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot,\n                                                          FS_RECTF* rect);\n\n// Get the count of quadrilateral points to the |link_annot|.\n//\n//   link_annot - handle to the link annotation.\n//\n// Returns the count of quadrilateral points.\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot);\n\n// Get the quadrilateral points for the specified |quad_index| in |link_annot|.\n//\n//   link_annot  - handle to the link annotation.\n//   quad_index  - the specified quad point index.\n//   quad_points - receives the quadrilateral points.\n//\n// Returns true on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetQuadPoints(FPDF_LINK link_annot,\n                       int quad_index,\n                       FS_QUADPOINTSF* quad_points);\n\n// Experimental API\n// Gets an additional-action from |page|.\n//\n//   page      - handle to the page, as returned by FPDF_LoadPage().\n//   aa_type   - the type of the page object's addtional-action, defined\n//               in public/fpdf_formfill.h\n//\n//   Returns the handle to the action data, or NULL if there is no\n//   additional-action of type |aa_type|.\n//   If this function returns a valid handle, it is valid as long as |page| is\n//   valid.\nFPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDF_GetPageAAction(FPDF_PAGE page,\n                                                          int aa_type);\n\n// Experimental API.\n// Get the file identifer defined in the trailer of |document|.\n//\n//   document - handle to the document.\n//   id_type  - the file identifier type to retrieve.\n//   buffer   - a buffer for the file identifier. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the file identifier, including the NUL\n// terminator.\n//\n// The |buffer| is always a byte string. The |buffer| is followed by a NUL\n// terminator.  If |buflen| is less than the returned length, or |buffer| is\n// NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetFileIdentifier(FPDF_DOCUMENT document,\n                       FPDF_FILEIDTYPE id_type,\n                       void* buffer,\n                       unsigned long buflen);\n\n// Get meta-data |tag| content from |document|.\n//\n//   document - handle to the document.\n//   tag      - the tag to retrieve. The tag can be one of:\n//                Title, Author, Subject, Keywords, Creator, Producer,\n//                CreationDate, or ModDate.\n//              For detailed explanations of these tags and their respective\n//              values, please refer to PDF Reference 1.6, section 10.2.1,\n//              'Document Information Dictionary'.\n//   buffer   - a buffer for the tag. May be NULL.\n//   buflen   - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the tag, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// For linearized files, FPDFAvail_IsFormAvail must be called before this, and\n// it must have returned PDF_FORM_AVAIL or PDF_FORM_NOTEXIST. Before that, there\n// is no guarantee the metadata has been loaded.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document,\n                                                         FPDF_BYTESTRING tag,\n                                                         void* buffer,\n                                                         unsigned long buflen);\n\n// Get the page label for |page_index| from |document|.\n//\n//   document    - handle to the document.\n//   page_index  - the 0-based index of the page.\n//   buffer      - a buffer for the page label. May be NULL.\n//   buflen      - the length of the buffer, in bytes. May be 0.\n//\n// Returns the number of bytes in the page label, including trailing zeros.\n//\n// The |buffer| is always encoded in UTF-16LE. The |buffer| is followed by two\n// bytes of zeros indicating the end of the string.  If |buflen| is less than\n// the returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetPageLabel(FPDF_DOCUMENT document,\n                  int page_index,\n                  void* buffer,\n                  unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_DOC_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_edit.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EDIT_H_\n#define PUBLIC_FPDF_EDIT_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n#define FPDF_ARGB(a, r, g, b)                                      \\\n  ((uint32_t)(((uint32_t)(b)&0xff) | (((uint32_t)(g)&0xff) << 8) | \\\n              (((uint32_t)(r)&0xff) << 16) | (((uint32_t)(a)&0xff) << 24)))\n#define FPDF_GetBValue(argb) ((uint8_t)(argb))\n#define FPDF_GetGValue(argb) ((uint8_t)(((uint16_t)(argb)) >> 8))\n#define FPDF_GetRValue(argb) ((uint8_t)((argb) >> 16))\n#define FPDF_GetAValue(argb) ((uint8_t)((argb) >> 24))\n\n// Refer to PDF Reference version 1.7 table 4.12 for all color space families.\n#define FPDF_COLORSPACE_UNKNOWN 0\n#define FPDF_COLORSPACE_DEVICEGRAY 1\n#define FPDF_COLORSPACE_DEVICERGB 2\n#define FPDF_COLORSPACE_DEVICECMYK 3\n#define FPDF_COLORSPACE_CALGRAY 4\n#define FPDF_COLORSPACE_CALRGB 5\n#define FPDF_COLORSPACE_LAB 6\n#define FPDF_COLORSPACE_ICCBASED 7\n#define FPDF_COLORSPACE_SEPARATION 8\n#define FPDF_COLORSPACE_DEVICEN 9\n#define FPDF_COLORSPACE_INDEXED 10\n#define FPDF_COLORSPACE_PATTERN 11\n\n// The page object constants.\n#define FPDF_PAGEOBJ_UNKNOWN 0\n#define FPDF_PAGEOBJ_TEXT 1\n#define FPDF_PAGEOBJ_PATH 2\n#define FPDF_PAGEOBJ_IMAGE 3\n#define FPDF_PAGEOBJ_SHADING 4\n#define FPDF_PAGEOBJ_FORM 5\n\n// The path segment constants.\n#define FPDF_SEGMENT_UNKNOWN -1\n#define FPDF_SEGMENT_LINETO 0\n#define FPDF_SEGMENT_BEZIERTO 1\n#define FPDF_SEGMENT_MOVETO 2\n\n#define FPDF_FILLMODE_NONE 0\n#define FPDF_FILLMODE_ALTERNATE 1\n#define FPDF_FILLMODE_WINDING 2\n\n#define FPDF_FONT_TYPE1 1\n#define FPDF_FONT_TRUETYPE 2\n\n#define FPDF_LINECAP_BUTT 0\n#define FPDF_LINECAP_ROUND 1\n#define FPDF_LINECAP_PROJECTING_SQUARE 2\n\n#define FPDF_LINEJOIN_MITER 0\n#define FPDF_LINEJOIN_ROUND 1\n#define FPDF_LINEJOIN_BEVEL 2\n\n// See FPDF_SetPrintMode() for descriptions.\n#define FPDF_PRINTMODE_EMF 0\n#define FPDF_PRINTMODE_TEXTONLY 1\n#define FPDF_PRINTMODE_POSTSCRIPT2 2\n#define FPDF_PRINTMODE_POSTSCRIPT3 3\n#define FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH 4\n#define FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH 5\n#define FPDF_PRINTMODE_EMF_IMAGE_MASKS 6\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 7\n#define FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH 8\n\ntypedef struct FPDF_IMAGEOBJ_METADATA {\n  // The image width in pixels.\n  unsigned int width;\n  // The image height in pixels.\n  unsigned int height;\n  // The image's horizontal pixel-per-inch.\n  float horizontal_dpi;\n  // The image's vertical pixel-per-inch.\n  float vertical_dpi;\n  // The number of bits used to represent each pixel.\n  unsigned int bits_per_pixel;\n  // The image's colorspace. See above for the list of FPDF_COLORSPACE_*.\n  int colorspace;\n  // The image's marked content ID. Useful for pairing with associated alt-text.\n  // A value of -1 indicates no ID.\n  int marked_content_id;\n} FPDF_IMAGEOBJ_METADATA;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Create a new PDF document.\n//\n// Returns a handle to a new document, or NULL on failure.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument();\n\n// Create a new PDF page.\n//\n//   document   - handle to document.\n//   page_index - suggested 0-based index of the page to create. If it is larger\n//                than document's current last index(L), the created page index\n//                is the next available index -- L+1.\n//   width      - the page width in points.\n//   height     - the page height in points.\n//\n// Returns the handle to the new page or NULL on failure.\n//\n// The page should be closed with FPDF_ClosePage() when finished as\n// with any other page in the document.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDFPage_New(FPDF_DOCUMENT document,\n                                                 int page_index,\n                                                 double width,\n                                                 double height);\n\n// Delete the page at |page_index|.\n//\n//   document   - handle to document.\n//   page_index - the index of the page to delete.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_Delete(FPDF_DOCUMENT document,\n                                               int page_index);\n\n// Experimental API.\n// Move the given pages to a new index position.\n//\n//  page_indices     - the ordered list of pages to move. No duplicates allowed.\n//  page_indices_len - the number of elements in |page_indices|\n//  dest_page_index  - the new index position to which the pages in\n//                     |page_indices| are moved.\n//\n// Returns TRUE on success. If it returns FALSE, the document may be left in an\n// indeterminate state.\n//\n// Example: The PDF document starts out with pages [A, B, C, D], with indices\n// [0, 1, 2, 3].\n//\n// >  Move(doc, [3, 2], 2, 1); // returns true\n// >  // The document has pages [A, D, C, B].\n// >\n// >  Move(doc, [0, 4, 3], 3, 1); // returns false\n// >  // Returned false because index 4 is out of range.\n// >\n// >  Move(doc, [0, 3, 1], 3, 2); // returns false\n// >  // Returned false because index 2 is out of range for 3 page indices.\n// >\n// >  Move(doc, [2, 2], 2, 0); // returns false\n// >  // Returned false because [2, 2] contains duplicates.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_MovePages(FPDF_DOCUMENT document,\n               const int* page_indices,\n               unsigned long page_indices_len,\n               int dest_page_index);\n\n// Get the rotation of |page|.\n//\n//   page - handle to a page\n//\n// Returns one of the following indicating the page rotation:\n//   0 - No rotation.\n//   1 - Rotated 90 degrees clockwise.\n//   2 - Rotated 180 degrees clockwise.\n//   3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_GetRotation(FPDF_PAGE page);\n\n// Set rotation for |page|.\n//\n//   page   - handle to a page.\n//   rotate - the rotation value, one of:\n//              0 - No rotation.\n//              1 - Rotated 90 degrees clockwise.\n//              2 - Rotated 180 degrees clockwise.\n//              3 - Rotated 270 degrees clockwise.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetRotation(FPDF_PAGE page, int rotate);\n\n// Insert |page_object| into |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object. The |page_object| will be\n//                 automatically freed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPage_InsertObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Insert |page_object| into |page| at the specified |index|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object as previously obtained by\n//                 FPDFPageObj_CreateNew{Path|Rect}() or\n//                 FPDFPageObj_New{Text|Image}Obj(). Ownership of the object\n//                 is transferred back to PDFium.\n//   index       - the index position to insert the object at. If index equals\n//                 the current object count, the object will be appended to the\n//                 end. If index is greater than the object count, the function\n//                 will fail and return false.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_InsertObjectAtIndex(FPDF_PAGE page,\n                             FPDF_PAGEOBJECT page_object,\n                             size_t index);\n\n// Experimental API.\n// Remove |page_object| from |page|.\n//\n//   page        - handle to a page\n//   page_object - handle to a page object to be removed.\n//\n// Returns TRUE on success.\n//\n// Ownership is transferred to the caller. Call FPDFPageObj_Destroy() to free\n// it.\n// Note that when removing a |page_object| of type FPDF_PAGEOBJ_TEXT, all\n// FPDF_TEXTPAGE handles for |page| are no longer valid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_RemoveObject(FPDF_PAGE page, FPDF_PAGEOBJECT page_object);\n\n// Get number of page objects inside |page|.\n//\n//   page - handle to a page.\n//\n// Returns the number of objects in |page|.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_CountObjects(FPDF_PAGE page);\n\n// Get object in |page| at |index|.\n//\n//   page  - handle to a page.\n//   index - the index of a page object.\n//\n// Returns the handle to the page object, or NULL on failed.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPage_GetObject(FPDF_PAGE page,\n                                                             int index);\n\n// Checks if |page| contains transparency.\n//\n//   page - handle to a page.\n//\n// Returns TRUE if |page| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_HasTransparency(FPDF_PAGE page);\n\n// Generate the content of |page|.\n//\n//   page - handle to a page.\n//\n// Returns TRUE on success.\n//\n// Before you save the page to a file, or reload the page, you must call\n// |FPDFPage_GenerateContent| or any changes to |page| will be lost.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GenerateContent(FPDF_PAGE page);\n\n// Destroy |page_object| by releasing its resources. |page_object| must have\n// been created by FPDFPageObj_CreateNew{Path|Rect}() or\n// FPDFPageObj_New{Text|Image}Obj(). This function must be called on\n// newly-created objects if they are not added to a page through\n// FPDFPage_InsertObject() or to an annotation through FPDFAnnot_AppendObject().\n//\n//   page_object - handle to a page object.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_Destroy(FPDF_PAGEOBJECT page_object);\n\n// Checks if |page_object| contains transparency.\n//\n//   page_object - handle to a page object.\n//\n// Returns TRUE if |page_object| contains transparency.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_HasTransparency(FPDF_PAGEOBJECT page_object);\n\n// Get type of |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns one of the FPDF_PAGEOBJ_* values on success, FPDF_PAGEOBJ_UNKNOWN on\n// error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPageObj_GetType(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Gets active state for |page_object| within page.\n//\n//   page_object - handle to a page object.\n//   active      - pointer to variable that will receive if the page object is\n//                 active. This is a required parameter. Not filled if FALSE\n//                 is returned.\n//\n// For page objects where |active| is filled with FALSE, the |page_object| is\n// treated as if it wasn't in the document even though it is still held\n// internally.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL* active);\n\n// Experimental API.\n// Sets if |page_object| is active within page.\n//\n//   page_object - handle to a page object.\n//   active      - a boolean specifying if the object is active.\n//\n// Returns TRUE on success.\n//\n// Page objects all start in the active state by default, and remain in that\n// state unless this function is called.\n//\n// When |active| is false, this makes the |page_object| be treated as if it\n// wasn't in the document even though it is still held internally.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetIsActive(FPDF_PAGEOBJECT page_object, FPDF_BOOL active);\n\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   a           - matrix value.\n//   b           - matrix value.\n//   c           - matrix value.\n//   d           - matrix value.\n//   e           - matrix value.\n//   f           - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page_object|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_Transform(FPDF_PAGEOBJECT page_object,\n                      double a,\n                      double b,\n                      double c,\n                      double d,\n                      double e,\n                      double f);\n\n// Experimental API.\n// Transform |page_object| by the given matrix.\n//\n//   page_object - handle to a page object.\n//   matrix      - the transform matrix.\n//\n// Returns TRUE on success.\n//\n// This can be used to scale, rotate, shear and translate the |page_object|.\n// It is an improved version of FPDFPageObj_Transform() that does not do\n// unnecessary double to float conversions, and only uses 1 parameter for the\n// matrix. It also returns whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_TransformF(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Experimental API.\n// Get the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct to receive the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and used to scale, rotate, shear and translate the page object.\n//\n// For page objects outside form objects, the matrix values are relative to the\n// page that contains it.\n// For page objects inside form objects, the matrix values are relative to the\n// form that contains it.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetMatrix(FPDF_PAGEOBJECT page_object, FS_MATRIX* matrix);\n\n// Experimental API.\n// Set the transform matrix of a page object.\n//\n//   page_object - handle to a page object.\n//   matrix      - pointer to struct with the matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the page object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetMatrix(FPDF_PAGEOBJECT page_object, const FS_MATRIX* matrix);\n\n// Transform all annotations in |page|.\n//\n//   page - handle to a page.\n//   a    - matrix value.\n//   b    - matrix value.\n//   c    - matrix value.\n//   d    - matrix value.\n//   e    - matrix value.\n//   f    - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |page| annotations.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_TransformAnnots(FPDF_PAGE page,\n                                                        double a,\n                                                        double b,\n                                                        double c,\n                                                        double d,\n                                                        double e,\n                                                        double f);\n\n// Create a new image object.\n//\n//   document - handle to a document.\n//\n// Returns a handle to a new image object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewImageObj(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the marked content ID for the object.\n//\n//   page_object - handle to a page object.\n//\n// Returns the page object's marked content ID, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetMarkedContentID(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of content marks in |page_object|.\n//\n//   page_object - handle to a page object.\n//\n// Returns the number of content marks in |page_object|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_CountMarks(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get content mark in |page_object| at |index|.\n//\n//   page_object - handle to a page object.\n//   index       - the index of a page object.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_GetMark(FPDF_PAGEOBJECT page_object, unsigned long index);\n\n// Experimental API.\n// Add a new content mark to a |page_object|.\n//\n//   page_object - handle to a page object.\n//   name        - the name (tag) of the mark.\n//\n// Returns the handle to the content mark, or NULL on failure. The handle is\n// still owned by the library, and it should not be freed directly. It becomes\n// invalid if the page object is destroyed, either directly or indirectly by\n// unloading the page.\nFPDF_EXPORT FPDF_PAGEOBJECTMARK FPDF_CALLCONV\nFPDFPageObj_AddMark(FPDF_PAGEOBJECT page_object, FPDF_BYTESTRING name);\n\n// Experimental API.\n// Removes a content |mark| from a |page_object|.\n// The mark handle will be invalid after the removal.\n//\n//   page_object - handle to a page object.\n//   mark        - handle to a content mark in that object to remove.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_RemoveMark(FPDF_PAGEOBJECT page_object, FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the name of a content mark.\n//\n//   mark       - handle to a content mark.\n//   buffer     - buffer for holding the returned name in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the name.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation succeeded, FALSE if it failed.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetName(FPDF_PAGEOBJECTMARK mark,\n                        FPDF_WCHAR* buffer,\n                        unsigned long buflen,\n                        unsigned long* out_buflen);\n\n// Experimental API.\n// Get the number of key/value pair parameters in |mark|.\n//\n//   mark   - handle to a content mark.\n//\n// Returns the number of key/value pair parameters |mark|, or -1 in case of\n// failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObjMark_CountParams(FPDF_PAGEOBJECTMARK mark);\n\n// Experimental API.\n// Get the key of a property in a content mark.\n//\n//   mark       - handle to a content mark.\n//   index      - index of the property.\n//   buffer     - buffer for holding the returned key in UTF-16LE. This is only\n//                modified if |buflen| is large enough to store the key.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamKey(FPDF_PAGEOBJECTMARK mark,\n                            unsigned long index,\n                            FPDF_WCHAR* buffer,\n                            unsigned long buflen,\n                            unsigned long* out_buflen);\n\n// Experimental API.\n// Get the type of the value of a property in a content mark by key.\n//\n//   mark   - handle to a content mark.\n//   key    - string key of the property.\n//\n// Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of failure.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDFPageObjMark_GetParamValueType(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as int.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamIntValue(FPDF_PAGEOBJECTMARK mark,\n                                 FPDF_BYTESTRING key,\n                                 int* out_value);\n\n// Experimental API.\n// Get the value of a number property in a content mark by key as float.\n// FPDFPageObjMark_GetParamValueType() should have returned FPDF_OBJECT_NUMBER\n// for this property.\n//\n//   mark      - handle to a content mark.\n//   key       - string key of the property.\n//   out_value - pointer to variable that will receive the value. Not filled if\n//               false is returned.\n//\n// Returns TRUE if the key maps to a number value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamFloatValue(FPDF_PAGEOBJECTMARK mark,\n                                   FPDF_BYTESTRING key,\n                                   float* out_value);\n\n// Experimental API.\n// Get the value of a string property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value in UTF-16LE. This is\n//                only modified if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamStringValue(FPDF_PAGEOBJECTMARK mark,\n                                    FPDF_BYTESTRING key,\n                                    FPDF_WCHAR* buffer,\n                                    unsigned long buflen,\n                                    unsigned long* out_buflen);\n\n// Experimental API.\n// Get the value of a blob property in a content mark by key.\n//\n//   mark       - handle to a content mark.\n//   key        - string key of the property.\n//   buffer     - buffer for holding the returned value. This is only modified\n//                if |buflen| is large enough to store the value.\n//                Optional, pass null to just retrieve the size of the buffer\n//                needed.\n//   buflen     - length of the buffer in bytes.\n//   out_buflen - pointer to variable that will receive the minimum buffer size\n//                in bytes to contain the name. This is a required parameter.\n//                Not filled if FALSE is returned.\n//\n// Returns TRUE if the key maps to a string/blob value, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_GetParamBlobValue(FPDF_PAGEOBJECTMARK mark,\n                                  FPDF_BYTESTRING key,\n                                  unsigned char* buffer,\n                                  unsigned long buflen,\n                                  unsigned long* out_buflen);\n\n// Experimental API.\n// Set the value of an int property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - int value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetIntParam(FPDF_DOCUMENT document,\n                            FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key,\n                            int value);\n\n// Experimental API.\n// Set the value of a float property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - float value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetFloatParam(FPDF_DOCUMENT document,\n                              FPDF_PAGEOBJECT page_object,\n                              FPDF_PAGEOBJECTMARK mark,\n                              FPDF_BYTESTRING key,\n                              float value);\n\n// Experimental API.\n// Set the value of a string property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - string value to set.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetStringParam(FPDF_DOCUMENT document,\n                               FPDF_PAGEOBJECT page_object,\n                               FPDF_PAGEOBJECTMARK mark,\n                               FPDF_BYTESTRING key,\n                               FPDF_BYTESTRING value);\n\n// Experimental API.\n// Set the value of a blob property in a content mark by key. If a parameter\n// with key |key| exists, its value is set to |value|. Otherwise, it is added as\n// a new parameter.\n//\n//   document    - handle to the document.\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//   value       - pointer to blob value to set.\n//   value_len   - size in bytes of |value|.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_SetBlobParam(FPDF_DOCUMENT document,\n                             FPDF_PAGEOBJECT page_object,\n                             FPDF_PAGEOBJECTMARK mark,\n                             FPDF_BYTESTRING key,\n                             const unsigned char* value,\n                             unsigned long value_len);\n\n// Experimental API.\n// Removes a property from a content mark by key.\n//\n//   page_object - handle to the page object with the mark.\n//   mark        - handle to a content mark.\n//   key         - string key of the property.\n//\n// Returns TRUE if the operation succeeded, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObjMark_RemoveParam(FPDF_PAGEOBJECT page_object,\n                            FPDF_PAGEOBJECTMARK mark,\n                            FPDF_BYTESTRING key);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFile(FPDF_PAGE* pages,\n                          int count,\n                          FPDF_PAGEOBJECT image_object,\n                          FPDF_FILEACCESS* file_access);\n\n// Load an image from a JPEG image file and then set it into |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   file_access  - file access handler which specifies the JPEG image file.\n//\n// Returns TRUE on success.\n//\n// The image object might already have an associated image, which is shared and\n// cached by the loaded pages. In that case, we need to clear the cached image\n// for all the loaded pages. Pass |pages| and page count (|count|) to this API\n// to clear the image cache. If the image is not previously shared, or NULL is a\n// valid |pages| value. This function loads the JPEG image inline, so the image\n// content is copied to the file. This allows |file_access| and its associated\n// data to be deleted after this function returns.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_LoadJpegFileInline(FPDF_PAGE* pages,\n                                int count,\n                                FPDF_PAGEOBJECT image_object,\n                                FPDF_FILEACCESS* file_access);\n\n// TODO(thestig): Start deprecating this once FPDFPageObj_SetMatrix() is stable.\n//\n// Set the transform matrix of |image_object|.\n//\n//   image_object - handle to an image object.\n//   a            - matrix value.\n//   b            - matrix value.\n//   c            - matrix value.\n//   d            - matrix value.\n//   e            - matrix value.\n//   f            - matrix value.\n//\n// The matrix is composed as:\n//   |a c e|\n//   |b d f|\n// and can be used to scale, rotate, shear and translate the |image_object|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetMatrix(FPDF_PAGEOBJECT image_object,\n                       double a,\n                       double b,\n                       double c,\n                       double d,\n                       double e,\n                       double f);\n\n// Set |bitmap| to |image_object|.\n//\n//   pages        - pointer to the start of all loaded pages, may be NULL.\n//   count        - number of |pages|, may be 0.\n//   image_object - handle to an image object.\n//   bitmap       - handle of the bitmap.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_SetBitmap(FPDF_PAGE* pages,\n                       int count,\n                       FPDF_PAGEOBJECT image_object,\n                       FPDF_BITMAP bitmap);\n\n// Get a bitmap rasterization of |image_object|. FPDFImageObj_GetBitmap() only\n// operates on |image_object| and does not take the associated image mask into\n// account. It also ignores the matrix for |image_object|.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   image_object - handle to an image object.\n//\n// Returns the bitmap.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetBitmap(FPDF_PAGEOBJECT image_object);\n\n// Experimental API.\n// Get a bitmap rasterization of |image_object| that takes the image mask and\n// image matrix into account. To render correctly, the caller must provide the\n// |document| associated with |image_object|. If there is a |page| associated\n// with |image_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document     - handle to a document associated with |image_object|.\n//   page         - handle to an optional page associated with |image_object|.\n//   image_object - handle to an image object.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFImageObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                               FPDF_PAGE page,\n                               FPDF_PAGEOBJECT image_object);\n\n// Get the decoded image data of |image_object|. The decoded data is the\n// uncompressed image data, i.e. the raw image data after having all filters\n// applied. |buffer| is only modified if |buflen| is longer than the length of\n// the decoded image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the decoded image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the decoded image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataDecoded(FPDF_PAGEOBJECT image_object,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Get the raw image data of |image_object|. The raw data is the image data as\n// stored in the PDF without applying any filters. |buffer| is only modified if\n// |buflen| is longer than the length of the raw image data.\n//\n//   image_object - handle to an image object.\n//   buffer       - buffer for holding the raw image data.\n//   buflen       - length of the buffer in bytes.\n//\n// Returns the length of the raw image data.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageDataRaw(FPDF_PAGEOBJECT image_object,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Get the number of filters (i.e. decoders) of the image in |image_object|.\n//\n//   image_object - handle to an image object.\n//\n// Returns the number of |image_object|'s filters.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFImageObj_GetImageFilterCount(FPDF_PAGEOBJECT image_object);\n\n// Get the filter at |index| of |image_object|'s list of filters. Note that the\n// filters need to be applied in order, i.e. the first filter should be applied\n// first, then the second, etc. |buffer| is only modified if |buflen| is longer\n// than the length of the filter string.\n//\n//   image_object - handle to an image object.\n//   index        - the index of the filter requested.\n//   buffer       - buffer for holding filter string, encoded in UTF-8.\n//   buflen       - length of the buffer.\n//\n// Returns the length of the filter string.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFImageObj_GetImageFilter(FPDF_PAGEOBJECT image_object,\n                            int index,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Get the image metadata of |image_object|, including dimension, DPI, bits per\n// pixel, and colorspace. If the |image_object| is not an image object or if it\n// does not have an image, then the return value will be false. Otherwise,\n// failure to retrieve any specific parameter would result in its value being 0.\n//\n//   image_object - handle to an image object.\n//   page         - handle to the page that |image_object| is on. Required for\n//                  retrieving the image's bits per pixel and colorspace.\n//   metadata     - receives the image metadata; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImageMetadata(FPDF_PAGEOBJECT image_object,\n                              FPDF_PAGE page,\n                              FPDF_IMAGEOBJ_METADATA* metadata);\n\n// Experimental API.\n// Get the image size in pixels. Faster method to get only image size.\n//\n//   image_object - handle to an image object.\n//   width        - receives the image width in pixels; must not be NULL.\n//   height       - receives the image height in pixels; must not be NULL.\n//\n// Returns true if successful.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetImagePixelSize(FPDF_PAGEOBJECT image_object,\n                               unsigned int* width,\n                               unsigned int* height);\n\n// Experimental API.\n// Get ICC profile decoded data of |image_object|. If the |image_object| is not\n// an image object or if it does not have an image, then the return value will\n// be false. It also returns false if the |image_object| has no ICC profile.\n// |buffer| is only modified if ICC profile exists and |buflen| is longer than\n// the length of the ICC profile decoded data.\n//\n//   image_object - handle to an image object; must not be NULL.\n//   page         - handle to the page containing |image_object|; must not be\n//                  NULL. Required for retrieving the image's colorspace.\n//   buffer       - Buffer to receive ICC profile data; may be NULL if querying\n//                  required size via |out_buflen|.\n//   buflen       - Length of the buffer in bytes. Ignored if |buffer| is NULL.\n//   out_buflen   - Pointer to receive the ICC profile data size in bytes; must\n//                  not be NULL. Will be set if this API returns true.\n//\n// Returns true if |out_buflen| is not null and an ICC profile exists for the\n// given |image_object|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFImageObj_GetIccProfileDataDecoded(FPDF_PAGEOBJECT image_object,\n                                      FPDF_PAGE page,\n                                      uint8_t* buffer,\n                                      size_t buflen,\n                                      size_t* out_buflen);\n\n// Create a new path object at an initial position.\n//\n//   x - initial horizontal position.\n//   y - initial vertical position.\n//\n// Returns a handle to a new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,\n                                                                    float y);\n\n// Create a closed path consisting of a rectangle.\n//\n//   x - horizontal position for the left boundary of the rectangle.\n//   y - vertical position for the bottom boundary of the rectangle.\n//   w - width of the rectangle.\n//   h - height of the rectangle.\n//\n// Returns a handle to the new path object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,\n                                                                    float y,\n                                                                    float w,\n                                                                    float h);\n\n// Get the bounding box of |page_object|.\n//\n// page_object  - handle to a page object.\n// left         - pointer where the left coordinate will be stored\n// bottom       - pointer where the bottom coordinate will be stored\n// right        - pointer where the right coordinate will be stored\n// top          - pointer where the top coordinate will be stored\n//\n// On success, returns TRUE and fills in the 4 coordinates.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetBounds(FPDF_PAGEOBJECT page_object,\n                      float* left,\n                      float* bottom,\n                      float* right,\n                      float* top);\n\n// Experimental API.\n// Get the quad points that bounds |page_object|.\n//\n// page_object  - handle to a page object.\n// quad_points  - pointer where the quadrilateral points will be stored.\n//\n// On success, returns TRUE and fills in |quad_points|.\n//\n// Similar to FPDFPageObj_GetBounds(), this returns the bounds of a page\n// object. When the object is rotated by a non-multiple of 90 degrees, this API\n// returns a tighter bound that cannot be represented with just the 4 sides of\n// a rectangle.\n//\n// Currently only works the following |page_object| types: FPDF_PAGEOBJ_TEXT and\n// FPDF_PAGEOBJ_IMAGE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetRotatedBounds(FPDF_PAGEOBJECT page_object,\n                             FS_QUADPOINTSF* quad_points);\n\n// Set the blend mode of |page_object|.\n//\n// page_object  - handle to a page object.\n// blend_mode   - string containing the blend mode.\n//\n// Blend mode can be one of following: Color, ColorBurn, ColorDodge, Darken,\n// Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal,\n// Overlay, Saturation, Screen, SoftLight\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_SetBlendMode(FPDF_PAGEOBJECT page_object,\n                         FPDF_BYTESTRING blend_mode);\n\n// Set the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's stroke color.\n// G            - the green component for the object's stroke color.\n// B            - the blue component for the object's stroke color.\n// A            - the stroke alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int R,\n                           unsigned int G,\n                           unsigned int B,\n                           unsigned int A);\n\n// Get the stroke RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the path stroke color.\n// G            - the green component of the object's stroke color.\n// B            - the blue component of the object's stroke color.\n// A            - the stroke alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,\n                           unsigned int* R,\n                           unsigned int* G,\n                           unsigned int* B,\n                           unsigned int* A);\n\n// Set the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width);\n\n// Get the stroke width of a page object.\n//\n// path   - the handle to the page object.\n// width  - the width of the stroke.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetStrokeWidth(FPDF_PAGEOBJECT page_object, float* width);\n\n// Get the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n//\n// Returns the line join, or -1 on failure.\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineJoin(FPDF_PAGEOBJECT page_object);\n\n// Set the line join of |page_object|.\n//\n// page_object  - handle to a page object.\n// line_join    - line join\n//\n// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,\n// FPDF_LINEJOIN_BEVEL\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join);\n\n// Get the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line cap, or -1 on failure.\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetLineCap(FPDF_PAGEOBJECT page_object);\n\n// Set the line cap of |page_object|.\n//\n// page_object - handle to a page object.\n// line_cap    - line cap\n//\n// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,\n// FPDF_LINECAP_PROJECTING_SQUARE\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap);\n\n// Set the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component for the object's fill color.\n// G            - the green component for the object's fill color.\n// B            - the blue component for the object's fill color.\n// A            - the fill alpha for the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int R,\n                         unsigned int G,\n                         unsigned int B,\n                         unsigned int A);\n\n// Get the fill RGBA of a page object. Range of values: 0 - 255.\n//\n// page_object  - the handle to the page object.\n// R            - the red component of the object's fill color.\n// G            - the green component of the object's fill color.\n// B            - the blue component of the object's fill color.\n// A            - the fill alpha of the object.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,\n                         unsigned int* R,\n                         unsigned int* G,\n                         unsigned int* B,\n                         unsigned int* A);\n\n// Experimental API.\n// Get the line dash |phase| of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - pointer where the dashing phase will be stored.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashPhase(FPDF_PAGEOBJECT page_object, float* phase);\n\n// Experimental API.\n// Set the line dash phase of |page_object|.\n//\n// page_object - handle to a page object.\n// phase - line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashPhase(FPDF_PAGEOBJECT page_object, float phase);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n//\n// Returns the line dash array size or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPageObj_GetDashCount(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - pointer where the dashing array will be stored.\n// dash_count - number of elements in |dash_array|.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_GetDashArray(FPDF_PAGEOBJECT page_object,\n                         float* dash_array,\n                         size_t dash_count);\n\n// Experimental API.\n// Set the line dash array of |page_object|.\n//\n// page_object - handle to a page object.\n// dash_array - the dash array.\n// dash_count - number of elements in |dash_array|.\n// phase - the line dash phase.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPageObj_SetDashArray(FPDF_PAGEOBJECT page_object,\n                         const float* dash_array,\n                         size_t dash_count,\n                         float phase);\n\n// Get number of segments inside |path|.\n//\n//   path - handle to a path.\n//\n// A segment is a command, created by e.g. FPDFPath_MoveTo(),\n// FPDFPath_LineTo() or FPDFPath_BezierTo().\n//\n// Returns the number of objects in |path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path);\n\n// Get segment in |path| at |index|.\n//\n//   path  - handle to a path.\n//   index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index);\n\n// Get coordinates of |segment|.\n//\n//   segment  - handle to a segment.\n//   x      - the horizontal position of the segment.\n//   y      - the vertical position of the segment.\n//\n// Returns TRUE on success, otherwise |x| and |y| is not set.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y);\n\n// Get type of |segment|.\n//\n//   segment - handle to a segment.\n//\n// Returns one of the FPDF_SEGMENT_* values on success,\n// FPDF_SEGMENT_UNKNOWN on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment);\n\n// Gets if the |segment| closes the current subpath of a given path.\n//\n//   segment - handle to a segment.\n//\n// Returns close flag for non-NULL segment, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment);\n\n// Move a path's current point.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new current point.\n// y      - the vertical position of the new current point.\n//\n// Note that no line will be created between the previous current point and the\n// new one.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a line between the current point and a new point in the path.\n//\n// path   - the handle to the path object.\n// x      - the horizontal position of the new point.\n// y      - the vertical position of the new point.\n//\n// The path's current point is changed to (x, y).\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,\n                                                    float x,\n                                                    float y);\n\n// Add a cubic Bezier curve to the given path, starting at the current point.\n//\n// path   - the handle to the path object.\n// x1     - the horizontal position of the first Bezier control point.\n// y1     - the vertical position of the first Bezier control point.\n// x2     - the horizontal position of the second Bezier control point.\n// y2     - the vertical position of the second Bezier control point.\n// x3     - the horizontal position of the ending point of the Bezier curve.\n// y3     - the vertical position of the ending point of the Bezier curve.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,\n                                                      float x1,\n                                                      float y1,\n                                                      float x2,\n                                                      float y2,\n                                                      float x3,\n                                                      float y3);\n\n// Close the current subpath of a given path.\n//\n// path   - the handle to the path object.\n//\n// This will add a line between the current point and the initial point of the\n// subpath, thus terminating the current subpath.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path);\n\n// Set the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode to be set: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path should be stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int fillmode,\n                                                         FPDF_BOOL stroke);\n\n// Get the drawing mode of a path.\n//\n// path     - the handle to the path object.\n// fillmode - the filling mode of the path: one of the FPDF_FILLMODE_* flags.\n// stroke   - a boolean specifying if the path is stroked or not.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetDrawMode(FPDF_PAGEOBJECT path,\n                                                         int* fillmode,\n                                                         FPDF_BOOL* stroke);\n\n// Create a new text object using one of the standard PDF fonts.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_NewTextObj(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING font,\n                       float font_size);\n\n// Set the text for a text object. If it had text, it will be replaced.\n//\n// text_object  - handle to the text object.\n// text         - the UTF-16LE encoded string containing the text to be added.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text);\n\n// Experimental API.\n// Set the text using charcodes for a text object. If it had text, it will be\n// replaced.\n//\n// text_object  - handle to the text object.\n// charcodes    - pointer to an array of charcodes to be added.\n// count        - number of elements in |charcodes|.\n//\n// Returns TRUE on success\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,\n                      const uint32_t* charcodes,\n                      size_t count);\n\n// Returns a font object loaded from a stream of data. The font is loaded\n// into the document. Various font data structures, such as the ToUnicode data,\n// are auto-generated based on the inputs.\n//\n// document  - handle to the document.\n// data      - the stream of font data, which will be copied by the font object.\n// size      - the size of the font data, in bytes.\n// font_type - FPDF_FONT_TYPE1 or FPDF_FONT_TRUETYPE depending on the font type.\n// cid       - a boolean specifying if the font is a CID font or not.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,\n                                                      const uint8_t* data,\n                                                      uint32_t size,\n                                                      int font_type,\n                                                      FPDF_BOOL cid);\n\n// Experimental API.\n// Loads one of the standard 14 fonts per PDF spec 1.7 page 416. The preferred\n// way of using font style is using a dash to separate the name from the style,\n// for example 'Helvetica-BoldItalic'.\n//\n// document   - handle to the document.\n// font       - string containing the font name, without spaces.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadStandardFont(FPDF_DOCUMENT document, FPDF_BYTESTRING font);\n\n// Experimental API.\n// Returns a font object loaded from a stream of data for a type 2 CID font. The\n// font is loaded into the document. Unlike FPDFText_LoadFont(), the ToUnicode\n// data and the CIDToGIDMap data are caller provided, instead of auto-generated.\n//\n// document                 - handle to the document.\n// font_data                - the stream of font data, which will be copied by\n//                            the font object.\n// font_data_size           - the size of the font data, in bytes.\n// to_unicode_cmap          - the ToUnicode data.\n// cid_to_gid_map_data      - the stream of CIDToGIDMap data.\n// cid_to_gid_map_data_size - the size of the CIDToGIDMap data, in bytes.\n//\n// The loaded font can be closed using FPDFFont_Close().\n//\n// Returns NULL on failure.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV\nFPDFText_LoadCidType2Font(FPDF_DOCUMENT document,\n                          const uint8_t* font_data,\n                          uint32_t font_data_size,\n                          FPDF_BYTESTRING to_unicode_cmap,\n                          const uint8_t* cid_to_gid_map_data,\n                          uint32_t cid_to_gid_map_data_size);\n\n// Get the font size of a text object.\n//\n//   text - handle to a text.\n//   size - pointer to the font size of the text object, measured in points\n//   (about 1/72 inch)\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_GetFontSize(FPDF_PAGEOBJECT text, float* size);\n\n// Close a loaded PDF font.\n//\n// font   - Handle to the loaded font.\nFPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font);\n\n// Create a new text object using a loaded font.\n//\n// document   - handle to the document.\n// font       - handle to the font object.\n// font_size  - the font size for the new text object.\n//\n// Returns a handle to a new text object, or NULL on failure\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFPageObj_CreateTextObj(FPDF_DOCUMENT document,\n                          FPDF_FONT font,\n                          float font_size);\n\n// Get the text rendering mode of a text object.\n//\n// text     - the handle to the text object.\n//\n// Returns one of the known FPDF_TEXT_RENDERMODE enum values on success,\n// FPDF_TEXTRENDERMODE_UNKNOWN on error.\nFPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV\nFPDFTextObj_GetTextRenderMode(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Set the text rendering mode of a text object.\n//\n// text         - the handle to the text object.\n// render_mode  - the FPDF_TEXT_RENDERMODE enum value to be set (cannot set to\n//                FPDF_TEXTRENDERMODE_UNKNOWN).\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFTextObj_SetTextRenderMode(FPDF_PAGEOBJECT text,\n                              FPDF_TEXT_RENDERMODE render_mode);\n\n// Get the text of a text object.\n//\n// text_object      - the handle to the text object.\n// text_page        - the handle to the text page.\n// buffer           - the address of a buffer that receives the text.\n// length           - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the text (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFTextObj_GetText(FPDF_PAGEOBJECT text_object,\n                    FPDF_TEXTPAGE text_page,\n                    FPDF_WCHAR* buffer,\n                    unsigned long length);\n\n// Experimental API.\n// Get a bitmap rasterization of |text_object|. To render correctly, the caller\n// must provide the |document| associated with |text_object|. If there is a\n// |page| associated with |text_object|, the caller should provide that as well.\n// The returned bitmap will be owned by the caller, and FPDFBitmap_Destroy()\n// must be called on the returned bitmap when it is no longer needed.\n//\n//   document    - handle to a document associated with |text_object|.\n//   page        - handle to an optional page associated with |text_object|.\n//   text_object - handle to a text object.\n//   scale       - the scaling factor, which must be greater than 0.\n//\n// Returns the bitmap or NULL on failure.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFTextObj_GetRenderedBitmap(FPDF_DOCUMENT document,\n                              FPDF_PAGE page,\n                              FPDF_PAGEOBJECT text_object,\n                              float scale);\n\n// Experimental API.\n// Get the font of a text object.\n//\n// text - the handle to the text object.\n//\n// Returns a handle to the font object held by |text| which retains ownership.\nFPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFTextObj_GetFont(FPDF_PAGEOBJECT text);\n\n// Experimental API.\n// Get the base name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the base font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the base name (including the trailing NUL\n// character) on success, 0 on error. The base name is typically the font's\n// PostScript name. See descriptions of \"BaseFont\" in ISO 32000-1:2008 spec.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetBaseFontName(FPDF_FONT font,\n                                                          char* buffer,\n                                                          size_t length);\n\n// Experimental API.\n// Get the family name of a font.\n//\n// font   - the handle to the font object.\n// buffer - the address of a buffer that receives the font name.\n// length - the size, in bytes, of |buffer|.\n//\n// Returns the number of bytes in the family name (including the trailing NUL\n// character) on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-8 encoding.\n// If |length| is less than the returned length, or |buffer| is NULL, |buffer|\n// will not be modified.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDFFont_GetFamilyName(FPDF_FONT font,\n                                                        char* buffer,\n                                                        size_t length);\n\n// Experimental API.\n// Get the decoded data from the |font| object.\n//\n// font       - The handle to the font object. (Required)\n// buffer     - The address of a buffer that receives the font data.\n// buflen     - Length of the buffer.\n// out_buflen - Pointer to variable that will receive the minimum buffer size\n//              to contain the font data. Not filled if the return value is\n//              FALSE. (Required)\n//\n// Returns TRUE on success. In which case, |out_buflen| will be filled, and\n// |buffer| will be filled if it is large enough. Returns FALSE if any of the\n// required parameters are null.\n//\n// The decoded data is the uncompressed font data. i.e. the raw font data after\n// having all stream filters applied, when the data is embedded.\n//\n// If the font is not embedded, then this API will instead return the data for\n// the substitution font it is using.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetFontData(FPDF_FONT font,\n                                                         uint8_t* buffer,\n                                                         size_t buflen,\n                                                         size_t* out_buflen);\n\n// Experimental API.\n// Get whether |font| is embedded or not.\n//\n// font - the handle to the font object.\n//\n// Returns 1 if the font is embedded, 0 if it not, and -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetIsEmbedded(FPDF_FONT font);\n\n// Experimental API.\n// Get the descriptor flags of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the bit flags specifying various characteristics of the font as\n// defined in ISO 32000-1:2008, table 123, -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetFlags(FPDF_FONT font);\n\n// Experimental API.\n// Get the font weight of a font.\n//\n// font - the handle to the font object.\n//\n// Returns the font weight, -1 on failure.\n// Typical values are 400 (normal) and 700 (bold).\nFPDF_EXPORT int FPDF_CALLCONV FPDFFont_GetWeight(FPDF_FONT font);\n\n// Experimental API.\n// Get the italic angle of a font.\n//\n// font  - the handle to the font object.\n// angle - pointer where the italic angle will be stored\n//\n// The italic angle of a |font| is defined as degrees counterclockwise\n// from vertical. For a font that slopes to the right, this will be negative.\n//\n// Returns TRUE on success; |angle| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetItalicAngle(FPDF_FONT font,\n                                                            int* angle);\n\n// Experimental API.\n// Get ascent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// ascent     - pointer where the font ascent will be stored\n//\n// Ascent is the maximum distance in points above the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |ascent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetAscent(FPDF_FONT font,\n                                                       float font_size,\n                                                       float* ascent);\n\n// Experimental API.\n// Get descent distance of a font.\n//\n// font       - the handle to the font object.\n// font_size  - the size of the |font|.\n// descent    - pointer where the font descent will be stored\n//\n// Descent is the maximum distance in points below the baseline reached by the\n// glyphs of the |font|. One point is 1/72 inch (around 0.3528 mm).\n//\n// Returns TRUE on success; |descent| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetDescent(FPDF_FONT font,\n                                                        float font_size,\n                                                        float* descent);\n\n// Experimental API.\n// Get the width of a glyph in a font.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph.\n// font_size  - the size of the font.\n// width      - pointer where the glyph width will be stored\n//\n// Glyph width is the distance from the end of the prior glyph to the next\n// glyph. This will be the vertical distance for vertical writing.\n//\n// Returns TRUE on success; |width| unmodified on failure.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFFont_GetGlyphWidth(FPDF_FONT font,\n                                                           uint32_t glyph,\n                                                           float font_size,\n                                                           float* width);\n\n// Experimental API.\n// Get the glyphpath describing how to draw a font glyph.\n//\n// font       - the handle to the font object.\n// glyph      - the glyph being drawn.\n// font_size  - the size of the font.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_GLYPHPATH FPDF_CALLCONV FPDFFont_GetGlyphPath(FPDF_FONT font,\n                                                               uint32_t glyph,\n                                                               float font_size);\n\n// Experimental API.\n// Get number of segments inside glyphpath.\n//\n// glyphpath - handle to a glyph path.\n//\n// Returns the number of objects in |glyphpath| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFGlyphPath_CountGlyphSegments(FPDF_GLYPHPATH glyphpath);\n\n// Experimental API.\n// Get segment in glyphpath at index.\n//\n// glyphpath  - handle to a glyph path.\n// index      - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on faiure.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFGlyphPath_GetGlyphPathSegment(FPDF_GLYPHPATH glyphpath, int index);\n\n// Get number of page objects inside |form_object|.\n//\n//   form_object - handle to a form object.\n//\n// Returns the number of objects in |form_object| on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFFormObj_CountObjects(FPDF_PAGEOBJECT form_object);\n\n// Get page object in |form_object| at |index|.\n//\n//   form_object - handle to a form object.\n//   index       - the 0-based index of a page object.\n//\n// Returns the handle to the page object, or NULL on error.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index);\n\n// Experimental API.\n//\n// Remove |page_object| from |form_object|.\n//\n//   form_object - handle to a form object.\n//   page_object - handle to a page object to be removed from the form.\n//\n// Returns TRUE on success.\n//\n// Ownership of the removed |page_object| is transferred to the caller.\n// Call FPDFPageObj_Destroy() on the removed page_object to free it.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFFormObj_RemoveObject(FPDF_PAGEOBJECT form_object,\n                         FPDF_PAGEOBJECT page_object);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EDIT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_ext.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_EXT_H_\n#define PUBLIC_FPDF_EXT_H_\n\n#include <time.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Unsupported XFA form.\n#define FPDF_UNSP_DOC_XFAFORM 1\n// Unsupported portable collection.\n#define FPDF_UNSP_DOC_PORTABLECOLLECTION 2\n// Unsupported attachment.\n#define FPDF_UNSP_DOC_ATTACHMENT 3\n// Unsupported security.\n#define FPDF_UNSP_DOC_SECURITY 4\n// Unsupported shared review.\n#define FPDF_UNSP_DOC_SHAREDREVIEW 5\n// Unsupported shared form, acrobat.\n#define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT 6\n// Unsupported shared form, filesystem.\n#define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM 7\n// Unsupported shared form, email.\n#define FPDF_UNSP_DOC_SHAREDFORM_EMAIL 8\n// Unsupported 3D annotation.\n#define FPDF_UNSP_ANNOT_3DANNOT 11\n// Unsupported movie annotation.\n#define FPDF_UNSP_ANNOT_MOVIE 12\n// Unsupported sound annotation.\n#define FPDF_UNSP_ANNOT_SOUND 13\n// Unsupported screen media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_MEDIA 14\n// Unsupported screen rich media annotation.\n#define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA 15\n// Unsupported attachment annotation.\n#define FPDF_UNSP_ANNOT_ATTACHMENT 16\n// Unsupported signature annotation.\n#define FPDF_UNSP_ANNOT_SIG 17\n\n// Interface for unsupported feature notifications.\ntypedef struct _UNSUPPORT_INFO {\n  // Version number of the interface. Must be 1.\n  int version;\n\n  // Unsupported object notification function.\n  // Interface Version: 1\n  // Implementation Required: Yes\n  //\n  //   pThis - pointer to the interface structure.\n  //   nType - the type of unsupported object. One of the |FPDF_UNSP_*| entries.\n  void (*FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO* pThis, int nType);\n} UNSUPPORT_INFO;\n\n// Setup an unsupported object handler.\n//\n//   unsp_info - Pointer to an UNSUPPORT_INFO structure.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info);\n\n// Set replacement function for calls to time().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of time(), or\n//          NULL to restore to actual time() call itself.\nFPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t (*func)());\n\n// Set replacement function for calls to localtime().\n//\n// This API is intended to be used only for testing, thus may cause PDFium to\n// behave poorly in production environments.\n//\n//   func - Function pointer to alternate implementation of localtime(), or\n//          NULL to restore to actual localtime() call itself.\nFPDF_EXPORT void FPDF_CALLCONV\nFSDK_SetLocaltimeFunction(struct tm* (*func)(const time_t*));\n\n// Unknown page mode.\n#define PAGEMODE_UNKNOWN -1\n// Document outline, and thumbnails hidden.\n#define PAGEMODE_USENONE 0\n// Document outline visible.\n#define PAGEMODE_USEOUTLINES 1\n// Thumbnail images visible.\n#define PAGEMODE_USETHUMBS 2\n// Full-screen mode, no menu bar, window controls, or other decorations visible.\n#define PAGEMODE_FULLSCREEN 3\n// Optional content group panel visible.\n#define PAGEMODE_USEOC 4\n// Attachments panel visible.\n#define PAGEMODE_USEATTACHMENTS 5\n\n// Get the document's PageMode.\n//\n//   doc - Handle to document.\n//\n// Returns one of the |PAGEMODE_*| flags defined above.\n//\n// The page mode defines how the document should be initially displayed.\nFPDF_EXPORT int FPDF_CALLCONV FPDFDoc_GetPageMode(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_EXT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_flatten.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FLATTEN_H_\n#define PUBLIC_FPDF_FLATTEN_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flatten operation failed.\n#define FLATTEN_FAIL 0\n// Flatten operation succeed.\n#define FLATTEN_SUCCESS 1\n// Nothing to be flattened.\n#define FLATTEN_NOTHINGTODO 2\n\n// Flatten for normal display.\n#define FLAT_NORMALDISPLAY 0\n// Flatten for print.\n#define FLAT_PRINT 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Flatten annotations and form fields into the page contents.\n//\n//   page  - handle to the page.\n//   nFlag - One of the |FLAT_*| values denoting the page usage.\n//\n// Returns one of the |FLATTEN_*| values.\n//\n// Currently, all failures return |FLATTEN_FAIL| with no indication of the\n// cause.\nFPDF_EXPORT int FPDF_CALLCONV FPDFPage_Flatten(FPDF_PAGE page, int nFlag);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FLATTEN_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_formfill.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FORMFILL_H_\n#define PUBLIC_FPDF_FORMFILL_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include_directory)\n#include \"fpdfview.h\"\n\n// These values are return values for a public API, so should not be changed\n// other than the count when adding new values.\n#define FORMTYPE_NONE 0            // Document contains no forms\n#define FORMTYPE_ACRO_FORM 1       // Forms are specified using AcroForm spec\n#define FORMTYPE_XFA_FULL 2        // Forms are specified using entire XFA spec\n#define FORMTYPE_XFA_FOREGROUND 3  // Forms are specified using the XFAF subset\n                                   // of XFA spec\n#define FORMTYPE_COUNT 4           // The number of form types\n\n#define JSPLATFORM_ALERT_BUTTON_OK 0           // OK button\n#define JSPLATFORM_ALERT_BUTTON_OKCANCEL 1     // OK & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNO 2        // Yes & No buttons\n#define JSPLATFORM_ALERT_BUTTON_YESNOCANCEL 3  // Yes, No & Cancel buttons\n#define JSPLATFORM_ALERT_BUTTON_DEFAULT JSPLATFORM_ALERT_BUTTON_OK\n\n#define JSPLATFORM_ALERT_ICON_ERROR 0     // Error\n#define JSPLATFORM_ALERT_ICON_WARNING 1   // Warning\n#define JSPLATFORM_ALERT_ICON_QUESTION 2  // Question\n#define JSPLATFORM_ALERT_ICON_STATUS 3    // Status\n#define JSPLATFORM_ALERT_ICON_ASTERISK 4  // Asterisk\n#define JSPLATFORM_ALERT_ICON_DEFAULT JSPLATFORM_ALERT_ICON_ERROR\n\n#define JSPLATFORM_ALERT_RETURN_OK 1      // OK\n#define JSPLATFORM_ALERT_RETURN_CANCEL 2  // Cancel\n#define JSPLATFORM_ALERT_RETURN_NO 3      // No\n#define JSPLATFORM_ALERT_RETURN_YES 4     // Yes\n\n#define JSPLATFORM_BEEP_ERROR 0           // Error\n#define JSPLATFORM_BEEP_WARNING 1         // Warning\n#define JSPLATFORM_BEEP_QUESTION 2        // Question\n#define JSPLATFORM_BEEP_STATUS 3          // Status\n#define JSPLATFORM_BEEP_DEFAULT 4         // Default\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _IPDF_JsPlatform {\n  // Version number of the interface. Currently must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: app_alert\n  //       Pop up a dialog to show warning or hint.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       Msg         -   A string containing the message to be displayed.\n  //       Title       -   The title of the dialog.\n  //       Type        -   The type of button group, one of the\n  //                       JSPLATFORM_ALERT_BUTTON_* values above.\n  //       nIcon       -   The type of the icon, one of the\n  //                       JSPLATFORM_ALERT_ICON_* above.\n  // Return Value:\n  //       Option selected by user in dialogue, one of the\n  //       JSPLATFORM_ALERT_RETURN_* values above.\n  int (*app_alert)(struct _IPDF_JsPlatform* pThis,\n                   FPDF_WIDESTRING Msg,\n                   FPDF_WIDESTRING Title,\n                   int Type,\n                   int Icon);\n\n  // Method: app_beep\n  //       Causes the system to play a sound.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nType       -   The sound type, see JSPLATFORM_BEEP_TYPE_*\n  //                       above.\n  // Return Value:\n  //       None\n  void (*app_beep)(struct _IPDF_JsPlatform* pThis, int nType);\n\n  // Method: app_response\n  //       Displays a dialog box containing a question and an entry field for\n  //       the user to reply to the question.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       Question    -   The question to be posed to the user.\n  //       Title       -   The title of the dialog box.\n  //       Default     -   A default value for the answer to the question. If\n  //                       not specified, no default value is presented.\n  //       cLabel      -   A short string to appear in front of and on the\n  //                       same line as the edit text field.\n  //       bPassword   -   If true, indicates that the user's response should\n  //                       be shown as asterisks (*) or bullets (?) to mask\n  //                       the response, which might be sensitive information.\n  //       response    -   A string buffer allocated by PDFium, to receive the\n  //                       user's response.\n  //       length      -   The length of the buffer in bytes. Currently, it is\n  //                       always 2048.\n  // Return Value:\n  //       Number of bytes the complete user input would actually require, not\n  //       including trailing zeros, regardless of the value of the length\n  //       parameter or the presence of the response buffer.\n  // Comments:\n  //       No matter on what platform, the response buffer should be always\n  //       written using UTF-16LE encoding. If a response buffer is\n  //       present and the size of the user input exceeds the capacity of the\n  //       buffer as specified by the length parameter, only the\n  //       first \"length\" bytes of the user input are to be written to the\n  //       buffer.\n  int (*app_response)(struct _IPDF_JsPlatform* pThis,\n                      FPDF_WIDESTRING Question,\n                      FPDF_WIDESTRING Title,\n                      FPDF_WIDESTRING Default,\n                      FPDF_WIDESTRING cLabel,\n                      FPDF_BOOL bPassword,\n                      void* response,\n                      int length);\n\n  // Method: Doc_getFilePath\n  //       Get the file path of the current document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       filePath    -   The string buffer to receive the file path. Can\n  //                       be NULL.\n  //       length      -   The length of the buffer, number of bytes. Can\n  //                       be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in the local encoding.\n  //       The return value always indicated number of bytes required for\n  //       the buffer, even when there is no buffer specified, or the buffer\n  //       size is less than required. In this case, the buffer will not\n  //       be modified.\n  int (*Doc_getFilePath)(struct _IPDF_JsPlatform* pThis,\n                         void* filePath,\n                         int length);\n\n  // Method: Doc_mail\n  //       Mails the data buffer as an attachment to all recipients, with or\n  //       without user interaction.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       mailData    -   Pointer to the data buffer to be sent. Can be NULL.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       mailData parameter. Can be 0.\n  //       bUI         -   If true, the rest of the parameters are used in a\n  //                       compose-new-message window that is displayed to the\n  //                       user. If false, the cTo parameter is required and\n  //                       all others are optional.\n  //       To          -   A semicolon-delimited list of recipients for the\n  //                       message.\n  //       Subject     -   The subject of the message. The length limit is\n  //                       64 KB.\n  //       CC          -   A semicolon-delimited list of CC recipients for\n  //                       the message.\n  //       BCC         -   A semicolon-delimited list of BCC recipients for\n  //                       the message.\n  //       Msg         -   The content of the message. The length limit is\n  //                       64 KB.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       If the parameter mailData is NULL or length is 0, the current\n  //       document will be mailed as an attachment to all recipients.\n  void (*Doc_mail)(struct _IPDF_JsPlatform* pThis,\n                   void* mailData,\n                   int length,\n                   FPDF_BOOL bUI,\n                   FPDF_WIDESTRING To,\n                   FPDF_WIDESTRING Subject,\n                   FPDF_WIDESTRING CC,\n                   FPDF_WIDESTRING BCC,\n                   FPDF_WIDESTRING Msg);\n\n  // Method: Doc_print\n  //       Prints all or a specific number of pages of the document.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis         -   Pointer to the interface structure itself.\n  //       bUI           -   If true, will cause a UI to be presented to the\n  //                         user to obtain printing information and confirm\n  //                         the action.\n  //       nStart        -   A 0-based index that defines the start of an\n  //                         inclusive range of pages.\n  //       nEnd          -   A 0-based index that defines the end of an\n  //                         inclusive page range.\n  //       bSilent       -   If true, suppresses the cancel dialog box while\n  //                         the document is printing. The default is false.\n  //       bShrinkToFit  -   If true, the page is shrunk (if necessary) to\n  //                         fit within the imageable area of the printed page.\n  //       bPrintAsImage -   If true, print pages as an image.\n  //       bReverse      -   If true, print from nEnd to nStart.\n  //       bAnnotations  -   If true (the default), annotations are\n  //                         printed.\n  // Return Value:\n  //       None.\n  void (*Doc_print)(struct _IPDF_JsPlatform* pThis,\n                    FPDF_BOOL bUI,\n                    int nStart,\n                    int nEnd,\n                    FPDF_BOOL bSilent,\n                    FPDF_BOOL bShrinkToFit,\n                    FPDF_BOOL bPrintAsImage,\n                    FPDF_BOOL bReverse,\n                    FPDF_BOOL bAnnotations);\n\n  // Method: Doc_submitForm\n  //       Send the form data to a specified URL.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       formData    -   Pointer to the data buffer to be sent.\n  //       length      -   The size,in bytes, of the buffer pointed by\n  //                       formData parameter.\n  //       URL         -   The URL to send to.\n  // Return Value:\n  //       None.\n  void (*Doc_submitForm)(struct _IPDF_JsPlatform* pThis,\n                         void* formData,\n                         int length,\n                         FPDF_WIDESTRING URL);\n\n  // Method: Doc_gotoPage\n  //       Jump to a specified page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  //       nPageNum    -   The specified page number, zero for the first page.\n  // Return Value:\n  //       None.\n  void (*Doc_gotoPage)(struct _IPDF_JsPlatform* pThis, int nPageNum);\n\n  // Method: Field_browse\n  //       Show a file selection dialog, and return the selected file path.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       filePath    -   Pointer to the data buffer to receive the file\n  //                       path. Can be NULL.\n  //       length      -   The length of the buffer, in bytes. Can be 0.\n  // Return Value:\n  //       Number of bytes the filePath consumes, including trailing zeros.\n  // Comments:\n  //       The filePath should always be provided in local encoding.\n  int (*Field_browse)(struct _IPDF_JsPlatform* pThis,\n                      void* filePath,\n                      int length);\n\n  // Pointer for embedder-specific data. Unused by PDFium, and despite\n  // its name, can be any data the embedder desires, though traditionally\n  // a FPDF_FORMFILLINFO interface.\n  void* m_pFormfillinfo;\n\n  // Version 2.\n\n  void* m_isolate;               // Unused in v3, retain for compatibility.\n  unsigned int m_v8EmbedderSlot; // Unused in v3, retain for compatibility.\n\n  // Version 3.\n  // Version 3 moves m_Isolate and m_v8EmbedderSlot to FPDF_LIBRARY_CONFIG.\n} IPDF_JSPLATFORM;\n\n// Flags for Cursor type\n#define FXCT_ARROW 0\n#define FXCT_NESW 1\n#define FXCT_NWSE 2\n#define FXCT_VBEAM 3\n#define FXCT_HBEAM 4\n#define FXCT_HAND 5\n\n// Function signature for the callback function passed to the FFI_SetTimer\n// method.\n// Parameters:\n//          idEvent     -   Identifier of the timer.\n// Return value:\n//          None.\ntypedef void (*TimerCallback)(int idEvent);\n\n// Declares of a struct type to the local system time.\ntypedef struct _FPDF_SYSTEMTIME {\n  unsigned short wYear;         // years since 1900\n  unsigned short wMonth;        // months since January - [0,11]\n  unsigned short wDayOfWeek;    // days since Sunday - [0,6]\n  unsigned short wDay;          // day of the month - [1,31]\n  unsigned short wHour;         // hours since midnight - [0,23]\n  unsigned short wMinute;       // minutes after the hour - [0,59]\n  unsigned short wSecond;       // seconds after the minute - [0,59]\n  unsigned short wMilliseconds; // milliseconds after the second - [0,999]\n} FPDF_SYSTEMTIME;\n\n#ifdef PDF_ENABLE_XFA\n\n// Pageview event flags\n#define FXFA_PAGEVIEWEVENT_POSTADDED 1    // After a new pageview is added.\n#define FXFA_PAGEVIEWEVENT_POSTREMOVED 3  // After a pageview is removed.\n\n// Definitions for Right Context Menu Features Of XFA Fields\n#define FXFA_MENU_COPY 1\n#define FXFA_MENU_CUT 2\n#define FXFA_MENU_SELECTALL 4\n#define FXFA_MENU_UNDO 8\n#define FXFA_MENU_REDO 16\n#define FXFA_MENU_PASTE 32\n\n// Definitions for File Type.\n#define FXFA_SAVEAS_XML 1\n#define FXFA_SAVEAS_XDP 2\n\n#endif  // PDF_ENABLE_XFA\n\ntypedef struct _FPDF_FORMFILLINFO {\n  // Version number of the interface.\n  // Version 1 contains stable interfaces. Version 2 has additional\n  // experimental interfaces.\n  // When PDFium is built without the XFA module, version can be 1 or 2.\n  // With version 1, only stable interfaces are called. With version 2,\n  // additional experimental interfaces are also called.\n  // When PDFium is built with the XFA module, version must be 2.\n  // All the XFA related interfaces are experimental. If PDFium is built with\n  // the XFA module and version 1 then none of the XFA related interfaces\n  // would be called. When PDFium is built with XFA module then the version\n  // must be 2.\n  int version;\n\n  // Version 1.\n\n  // Method: Release\n  //       Give the implementation a chance to release any resources after the\n  //       interface is no longer used.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Comments:\n  //       Called by PDFium during the final cleanup process.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //       None\n  void (*Release)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_Invalidate\n  //       Invalidate the client area within the specified rectangle.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage().\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       All positions are measured in PDF \"user space\".\n  //       Implementation should call FPDF_RenderPageBitmap() for repainting\n  //       the specified page area.\n  void (*FFI_Invalidate)(struct _FPDF_FORMFILLINFO* pThis,\n                         FPDF_PAGE page,\n                         double left,\n                         double top,\n                         double right,\n                         double bottom);\n\n  // Method: FFI_OutputSelectedRect\n  //       When the user selects text in form fields with the mouse, this\n  //       callback function will be invoked with the selected areas.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to the page. Returned by FPDF_LoadPage()/\n  //       left        -   Left position of the client area in PDF page\n  //                       coordinates.\n  //       top         -   Top position of the client area in PDF page\n  //                       coordinates.\n  //       right       -   Right position of the client area in PDF page\n  //                       coordinates.\n  //       bottom      -   Bottom position of the client area in PDF page\n  //                       coordinates.\n  // Return Value:\n  //       None.\n  // Comments:\n  //       This callback function is useful for implementing special text\n  //       selection effects. An implementation should first record the\n  //       returned rectangles, then draw them one by one during the next\n  //       painting period. Lastly, it should remove all the recorded\n  //       rectangles when finished painting.\n  void (*FFI_OutputSelectedRect)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_PAGE page,\n                                 double left,\n                                 double top,\n                                 double right,\n                                 double bottom);\n\n  // Method: FFI_SetCursor\n  //       Set the Cursor shape.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nCursorType -   Cursor type, see Flags for Cursor type for details.\n  // Return value:\n  //       None.\n  void (*FFI_SetCursor)(struct _FPDF_FORMFILLINFO* pThis, int nCursorType);\n\n  // Method: FFI_SetTimer\n  //       This method installs a system timer. An interval value is specified,\n  //       and every time that interval elapses, the system must call into the\n  //       callback function with the timer ID as returned by this function.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       uElapse     -   Specifies the time-out value, in milliseconds.\n  //       lpTimerFunc -   A pointer to the callback function-TimerCallback.\n  // Return value:\n  //       The timer identifier of the new timer if the function is successful.\n  //       An application passes this value to the FFI_KillTimer method to kill\n  //       the timer. Nonzero if it is successful; otherwise, it is zero.\n  int (*FFI_SetTimer)(struct _FPDF_FORMFILLINFO* pThis,\n                      int uElapse,\n                      TimerCallback lpTimerFunc);\n\n  // Method: FFI_KillTimer\n  //       This method uninstalls a system timer, as set by an earlier call to\n  //       FFI_SetTimer.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       nTimerID    -   The timer ID returned by FFI_SetTimer function.\n  // Return value:\n  //       None.\n  void (*FFI_KillTimer)(struct _FPDF_FORMFILLINFO* pThis, int nTimerID);\n\n  // Method: FFI_GetLocalTime\n  //       This method receives the current local time on the system.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       The local time. See FPDF_SYSTEMTIME above for details.\n  // Note: Unused.\n  FPDF_SYSTEMTIME (*FFI_GetLocalTime)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_OnChange\n  //       This method will be invoked to notify the implementation when the\n  //       value of any FormField on the document had been changed.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  // Return value:\n  //       None.\n  void (*FFI_OnChange)(struct _FPDF_FORMFILLINFO* pThis);\n\n  // Method: FFI_GetPage\n  //       This method receives the page handle associated with a specified\n  //       page index.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  //       nPageIndex  -   Index number of the page. 0 for the first page.\n  // Return value:\n  //       Handle to the page, as previously returned to the implementation by\n  //       FPDF_LoadPage().\n  // Comments:\n  //       The implementation is expected to keep track of the page handles it\n  //       receives from PDFium, and their mappings to page numbers. In some\n  //       cases, the document-level JavaScript action may refer to a page\n  //       which hadn't been loaded yet. To successfully run the Javascript\n  //       action, the implementation needs to load the page.\n  FPDF_PAGE (*FFI_GetPage)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_DOCUMENT document,\n                           int nPageIndex);\n\n  // Method: FFI_GetCurrentPage\n  //       This method receives the handle to the current page.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       Yes when V8 support is present, otherwise unused.\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       document    -   Handle to document. Returned by FPDF_LoadDocument().\n  // Return value:\n  //       Handle to the page. Returned by FPDF_LoadPage().\n  // Comments:\n  //       PDFium doesn't keep keep track of the \"current page\" (e.g. the one\n  //       that is most visible on screen), so it must ask the embedder for\n  //       this information.\n  FPDF_PAGE (*FFI_GetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_DOCUMENT document);\n\n  // Method: FFI_GetRotation\n  //       This method receives currently rotation of the page view.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis       -   Pointer to the interface structure itself.\n  //       page        -   Handle to page, as returned by FPDF_LoadPage().\n  // Return value:\n  //       A number to indicate the page rotation in 90 degree increments\n  //       in a clockwise direction:\n  //         0 - 0 degrees\n  //         1 - 90 degrees\n  //         2 - 180 degrees\n  //         3 - 270 degrees\n  // Note: Unused.\n  int (*FFI_GetRotation)(struct _FPDF_FORMFILLINFO* pThis, FPDF_PAGE page);\n\n  // Method: FFI_ExecuteNamedAction\n  //       This method will execute a named action.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       yes\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       namedAction     -   A byte string which indicates the named action,\n  //                           terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       See ISO 32000-1:2008, section 12.6.4.11 for descriptions of the\n  //       standard named actions, but note that a document may supply any\n  //       name of its choosing.\n  void (*FFI_ExecuteNamedAction)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_BYTESTRING namedAction);\n  // Method: FFI_SetTextFieldFocus\n  //       Called when a text field is getting or losing focus.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       no\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       value           -   The string value of the form field, in UTF-16LE\n  //                           format.\n  //       valueLen        -   The length of the string value. This is the\n  //                           number of characters, not bytes.\n  //       is_focus        -   True if the form field is getting focus, false\n  //                           if the form field is losing focus.\n  // Return value:\n  //       None.\n  // Comments:\n  //       Only supports text fields and combobox fields.\n  void (*FFI_SetTextFieldFocus)(struct _FPDF_FORMFILLINFO* pThis,\n                                FPDF_WIDESTRING value,\n                                FPDF_DWORD valueLen,\n                                FPDF_BOOL is_focus);\n\n  // Method: FFI_DoURIAction\n  //       Ask the implementation to navigate to a uniform resource identifier.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       bsURI           -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder is version 2 or higher and have implementation for\n  //       FFI_DoURIActionWithKeyboardModifier, then\n  //       FFI_DoURIActionWithKeyboardModifier takes precedence over\n  //       FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void (*FFI_DoURIAction)(struct _FPDF_FORMFILLINFO* pThis,\n                          FPDF_BYTESTRING bsURI);\n\n  // Method: FFI_DoGoToAction\n  //       This action changes the view to a specified destination.\n  // Interface Version:\n  //       1\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       nPageIndex      -   The index of the PDF page.\n  //       zoomMode        -   The zoom mode for viewing page. See below.\n  //       fPosArray       -   The float array which carries the position info.\n  //       sizeofArray     -   The size of float array.\n  // PDFZoom values:\n  //         - XYZ = 1\n  //         - FITPAGE = 2\n  //         - FITHORZ = 3\n  //         - FITVERT = 4\n  //         - FITRECT = 5\n  //         - FITBBOX = 6\n  //         - FITBHORZ = 7\n  //         - FITBVERT = 8\n  // Return value:\n  //       None.\n  // Comments:\n  //       See the Destinations description of <<PDF Reference, version 1.7>>\n  //       in 8.2.1 for more details.\n  void (*FFI_DoGoToAction)(struct _FPDF_FORMFILLINFO* pThis,\n                           int nPageIndex,\n                           int zoomMode,\n                           float* fPosArray,\n                           int sizeofArray);\n\n  // Pointer to IPDF_JSPLATFORM interface.\n  // Unused if PDFium is built without V8 support. Otherwise, if NULL, then\n  // JavaScript will be prevented from executing while rendering the document.\n  IPDF_JSPLATFORM* m_pJsPlatform;\n\n  // Version 2 - Experimental.\n\n  // Whether the XFA module is disabled when built with the XFA module.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  FPDF_BOOL xfa_disabled;\n\n  // Method: FFI_DisplayCaret\n  //       This method will show the caret at specified position.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   Left position of the client area in PDF page\n  //                           coordinates.\n  //       top             -   Top position of the client area in PDF page\n  //                           coordinates.\n  //       right           -   Right position of the client area in PDF page\n  //                           coordinates.\n  //       bottom          -   Bottom position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       None.\n  void (*FFI_DisplayCaret)(struct _FPDF_FORMFILLINFO* pThis,\n                           FPDF_PAGE page,\n                           FPDF_BOOL bVisible,\n                           double left,\n                           double top,\n                           double right,\n                           double bottom);\n\n  // Method: FFI_GetCurrentPageIndex\n  //       This method will get the current page index.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  // Return value:\n  //       The index of current page.\n  int (*FFI_GetCurrentPageIndex)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_DOCUMENT document);\n\n  // Method: FFI_SetCurrentPage\n  //       This method will set the current page.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       document        -   Handle to document from FPDF_LoadDocument().\n  //       iCurPage        -   The index of the PDF page.\n  // Return value:\n  //       None.\n  void (*FFI_SetCurrentPage)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_DOCUMENT document,\n                             int iCurPage);\n\n // Method: FFI_GotoURL\n //       This method will navigate to the specified URL.\n // Interface Version:\n //       Ignored if |version| < 2.\n // Implementation Required:\n //       Required for XFA, otherwise set to NULL.\n // Parameters:\n //       pThis            -   Pointer to the interface structure itself.\n //       document         -   Handle to document from FPDF_LoadDocument().\n //       wsURL            -   The string value of the URL, in UTF-16LE format.\n // Return value:\n //       None.\n  void (*FFI_GotoURL)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_DOCUMENT document,\n                      FPDF_WIDESTRING wsURL);\n\n  // Method: FFI_GetPageViewRect\n  //       This method will get the current page view rectangle.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       left            -   The pointer to receive left position of the page\n  //                           view area in PDF page coordinates.\n  //       top             -   The pointer to receive top position of the page\n  //                           view area in PDF page coordinates.\n  //       right           -   The pointer to receive right position of the\n  //                           page view area in PDF page coordinates.\n  //       bottom          -   The pointer to receive bottom position of the\n  //                           page view area in PDF page coordinates.\n  // Return value:\n  //     None.\n  void (*FFI_GetPageViewRect)(struct _FPDF_FORMFILLINFO* pThis,\n                              FPDF_PAGE page,\n                              double* left,\n                              double* top,\n                              double* right,\n                              double* bottom);\n\n  // Method: FFI_PageEvent\n  //       This method fires when pages have been added to or deleted from\n  //       the XFA document.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page_count      -   The number of pages to be added or deleted.\n  //       event_type      -   See FXFA_PAGEVIEWEVENT_* above.\n  // Return value:\n  //       None.\n  // Comments:\n  //       The pages to be added or deleted always start from the last page\n  //       of document. This means that if parameter page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTADDED, 2 new pages have been\n  //       appended to the tail of document; If page_count is 2 and\n  //       event type is FXFA_PAGEVIEWEVENT_POSTREMOVED, the last 2 pages\n  //       have been deleted.\n  void (*FFI_PageEvent)(struct _FPDF_FORMFILLINFO* pThis,\n                        int page_count,\n                        FPDF_DWORD event_type);\n\n  // Method: FFI_PopupMenu\n  //       This method will track the right context menu for XFA fields.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       page            -   Handle to page. Returned by FPDF_LoadPage().\n  //       hWidget         -   Always null, exists for compatibility.\n  //       menuFlag        -   The menu flags. Please refer to macro definition\n  //                           of FXFA_MENU_XXX and this can be one or a\n  //                           combination of these macros.\n  //       x               -   X position of the client area in PDF page\n  //                           coordinates.\n  //       y               -   Y position of the client area in PDF page\n  //                           coordinates.\n  // Return value:\n  //       TRUE indicates success; otherwise false.\n  FPDF_BOOL (*FFI_PopupMenu)(struct _FPDF_FORMFILLINFO* pThis,\n                             FPDF_PAGE page,\n                             FPDF_WIDGET hWidget,\n                             int menuFlag,\n                             float x,\n                             float y);\n\n  // Method: FFI_OpenFile\n  //       This method will open the specified file with the specified mode.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       wsURL           -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  //       mode            -   The mode for open file, e.g. \"rb\" or \"wb\".\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_OpenFile)(struct _FPDF_FORMFILLINFO* pThis,\n                                    int fileFlag,\n                                    FPDF_WIDESTRING wsURL,\n                                    const char* mode);\n\n  // Method: FFI_EmailTo\n  //       This method will email the specified file stream to the specified\n  //       contact.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       pTo             -   A semicolon-delimited list of recipients for the\n  //                           message,in UTF-16LE format.\n  //       pSubject        -   The subject of the message,in UTF-16LE format.\n  //       pCC             -   A semicolon-delimited list of CC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pBcc            -   A semicolon-delimited list of BCC recipients for\n  //                           the message,in UTF-16LE format.\n  //       pMsg            -   Pointer to the data buffer to be sent.Can be\n  //                           NULL,in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_EmailTo)(struct _FPDF_FORMFILLINFO* pThis,\n                      FPDF_FILEHANDLER* fileHandler,\n                      FPDF_WIDESTRING pTo,\n                      FPDF_WIDESTRING pSubject,\n                      FPDF_WIDESTRING pCC,\n                      FPDF_WIDESTRING pBcc,\n                      FPDF_WIDESTRING pMsg);\n\n  // Method: FFI_UploadTo\n  //       This method will upload the specified file stream to the\n  //       specified URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       pFileHandler    -   Handle to the FPDF_FILEHANDLER.\n  //       fileFlag        -   The file flag. Please refer to macro definition\n  //                           of FXFA_SAVEAS_XXX and use one of these macros.\n  //       uploadTo        -   Pointer to the URL path, in UTF-16LE format.\n  // Return value:\n  //       None.\n  void (*FFI_UploadTo)(struct _FPDF_FORMFILLINFO* pThis,\n                       FPDF_FILEHANDLER* fileHandler,\n                       int fileFlag,\n                       FPDF_WIDESTRING uploadTo);\n\n  // Method: FFI_GetPlatform\n  //       This method will get the current platform.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       platform        -   Pointer to the data buffer to receive the\n  //                           platform,in UTF-16LE format. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetPlatform)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* platform,\n                         int length);\n\n  // Method: FFI_GetLanguage\n  //       This method will get the current language.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       language        -   Pointer to the data buffer to receive the\n  //                           current language. Can be NULL.\n  //       length          -   The length of the buffer in bytes. Can be\n  //                           0 to query the required size.\n  // Return value:\n  //       The length of the buffer, number of bytes.\n  int (*FFI_GetLanguage)(struct _FPDF_FORMFILLINFO* pThis,\n                         void* language,\n                         int length);\n\n  // Method: FFI_DownloadFromURL\n  //       This method will download the specified file from the URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       URL             -   The string value of the file URL, in UTF-16LE\n  //                           format.\n  // Return value:\n  //       The handle to FPDF_FILEHANDLER.\n  FPDF_FILEHANDLER* (*FFI_DownloadFromURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                           FPDF_WIDESTRING URL);\n  // Method: FFI_PostRequestURL\n  //       This method will post the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The post data,in UTF-16LE format.\n  //       wsContentType   -   The content type of the request data, in\n  //                           UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTF-16LE format.\n  //       wsHeader        -   The request header,in UTF-16LE format.\n  //       response        -   Pointer to the FPDF_BSTR to receive the response\n  //                           data from the server, in UTF-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PostRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                  FPDF_WIDESTRING wsURL,\n                                  FPDF_WIDESTRING wsData,\n                                  FPDF_WIDESTRING wsContentType,\n                                  FPDF_WIDESTRING wsEncode,\n                                  FPDF_WIDESTRING wsHeader,\n                                  FPDF_BSTR* response);\n\n  // Method: FFI_PutRequestURL\n  //       This method will put the request to the server URL.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       Required for XFA, otherwise set to NULL.\n  // Parameters:\n  //       pThis           -   Pointer to the interface structure itself.\n  //       wsURL           -   The string value of the server URL, in UTF-16LE\n  //                           format.\n  //       wsData          -   The put data, in UTF-16LE format.\n  //       wsEncode        -   The encode type, in UTR-16LE format.\n  // Return value:\n  //       TRUE indicates success, otherwise FALSE.\n  FPDF_BOOL (*FFI_PutRequestURL)(struct _FPDF_FORMFILLINFO* pThis,\n                                 FPDF_WIDESTRING wsURL,\n                                 FPDF_WIDESTRING wsData,\n                                 FPDF_WIDESTRING wsEncode);\n\n  // Method: FFI_OnFocusChange\n  //     Called when the focused annotation is updated.\n  // Interface Version:\n  //     Ignored if |version| < 2.\n  // Implementation Required:\n  //     No\n  // Parameters:\n  //     param           -   Pointer to the interface structure itself.\n  //     annot           -   The focused annotation.\n  //     page_index      -   Index number of the page which contains the\n  //                         focused annotation. 0 for the first page.\n  // Return value:\n  //     None.\n  // Comments:\n  //     This callback function is useful for implementing any view based\n  //     action such as scrolling the annotation rect into view. The\n  //     embedder should not copy and store the annot as its scope is\n  //     limited to this call only.\n  void (*FFI_OnFocusChange)(struct _FPDF_FORMFILLINFO* param,\n                            FPDF_ANNOTATION annot,\n                            int page_index);\n\n  // Method: FFI_DoURIActionWithKeyboardModifier\n  //       Ask the implementation to navigate to a uniform resource identifier\n  //       with the specified modifiers.\n  // Interface Version:\n  //       Ignored if |version| < 2.\n  // Implementation Required:\n  //       No\n  // Parameters:\n  //       param           -   Pointer to the interface structure itself.\n  //       uri             -   A byte string which indicates the uniform\n  //                           resource identifier, terminated by 0.\n  //       modifiers       -   Keyboard modifier that indicates which of\n  //                           the virtual keys are down, if any.\n  // Return value:\n  //       None.\n  // Comments:\n  //       If the embedder who is version 2 and does not implement this API,\n  //       then a call will be redirected to FFI_DoURIAction.\n  //       See the URI actions description of <<PDF Reference, version 1.7>>\n  //       for more details.\n  void(*FFI_DoURIActionWithKeyboardModifier)(struct _FPDF_FORMFILLINFO* param,\n      FPDF_BYTESTRING uri,\n      int modifiers);\n} FPDF_FORMFILLINFO;\n\n// Function: FPDFDOC_InitFormFillEnvironment\n//       Initialize form fill environment.\n// Parameters:\n//       document        -   Handle to document from FPDF_LoadDocument().\n//       formInfo        -   Pointer to a FPDF_FORMFILLINFO structure.\n// Return Value:\n//       Handle to the form fill module, or NULL on failure.\n// Comments:\n//       This function should be called before any form fill operation.\n//       The FPDF_FORMFILLINFO passed in via |formInfo| must remain valid until\n//       the returned FPDF_FORMHANDLE is closed.\nFPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV\nFPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,\n                                FPDF_FORMFILLINFO* formInfo);\n\n// Function: FPDFDOC_ExitFormFillEnvironment\n//       Take ownership of |hHandle| and exit form fill environment.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This function is a no-op when |hHandle| is null.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnAfterLoadPage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked after user successfully loaded a\n//       PDF page, and FPDFDOC_InitFormFillEnvironment() has been invoked.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,\n                                                    FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_OnBeforeClosePage\n//       This method is required for implementing all the form related\n//       functions. Should be invoked before user closes the PDF page.\n// Parameters:\n//        page        -   Handle to the page, as returned by FPDF_LoadPage().\n//        hHandle     -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//        None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page,\n                                                      FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentJSAction\n//       This method is required for performing document-level JavaScript\n//       actions. It should be invoked after the PDF document has been loaded.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       If there is document-level JavaScript action embedded in the\n//       document, this method will execute the JavaScript action. Otherwise,\n//       the method will do nothing.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle);\n\n// Function: FORM_DoDocumentOpenAction\n//       This method is required for performing open-action when the document\n//       is opened.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there are no open-actions embedded\n//       in the document.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle);\n\n// Additional actions type of document:\n//   WC, before closing document, JavaScript action.\n//   WS, before saving document, JavaScript action.\n//   DS, after saving document, JavaScript action.\n//   WP, before printing document, JavaScript action.\n//   DP, after printing document, JavaScript action.\n#define FPDFDOC_AACTION_WC 0x10\n#define FPDFDOC_AACTION_WS 0x11\n#define FPDFDOC_AACTION_DS 0x12\n#define FPDFDOC_AACTION_WP 0x13\n#define FPDFDOC_AACTION_DP 0x14\n\n// Function: FORM_DoDocumentAAction\n//       This method is required for performing the document's\n//       additional-action.\n// Parameters:\n//       hHandle     -   Handle to the form fill module. Returned by\n//                       FPDFDOC_InitFormFillEnvironment.\n//       aaType      -   The type of the additional-actions which defined\n//                       above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if there is no document\n//       additional-action corresponding to the specified |aaType|.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,\n                                                      int aaType);\n\n// Additional-action types of page object:\n//   OPEN (/O) -- An action to be performed when the page is opened\n//   CLOSE (/C) -- An action to be performed when the page is closed\n#define FPDFPAGE_AACTION_OPEN 0\n#define FPDFPAGE_AACTION_CLOSE 1\n\n// Function: FORM_DoPageAAction\n//       This method is required for performing the page object's\n//       additional-action when opened or closed.\n// Parameters:\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       aaType      -   The type of the page object's additional-actions\n//                       which defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This method will do nothing if no additional-action corresponding\n//       to the specified |aaType| exists.\nFPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page,\n                                                  FPDF_FORMHANDLE hHandle,\n                                                  int aaType);\n\n// Function: FORM_OnMouseMove\n//       Call this member function when the mouse cursor moves.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Experimental API\n// Function: FORM_OnMouseWheel\n//       Call this member function when the user scrolls the mouse wheel.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_coord  -   Specifies the coordinates of the cursor in PDF user\n//                       space.\n//       delta_x     -   Specifies the amount of wheel movement on the x-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean left.\n//       delta_y     -   Specifies the amount of wheel movement on the y-axis,\n//                       in units of platform-agnostic wheel deltas. Negative\n//                       values mean down.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       For |delta_x| and |delta_y|, the caller must normalize\n//       platform-specific wheel deltas. e.g. On Windows, a delta value of 240\n//       for a WM_MOUSEWHEEL event normalizes to 2, since Windows defines\n//       WHEEL_DELTA as 120.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel(\n    FPDF_FORMHANDLE hHandle,\n    FPDF_PAGE page,\n    int modifier,\n    const FS_POINTF* page_coord,\n    int delta_x,\n    int delta_y);\n\n// Function: FORM_OnFocus\n//       This function focuses the form annotation at a given point. If the\n//       annotation at the point already has focus, nothing happens. If there\n//       is no annotation at the point, removes form focus.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True if there is an annotation at the given point and it has focus.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int modifier,\n                                                 double page_x,\n                                                 double page_y);\n\n// Function: FORM_OnLButtonDown\n//       Call this member function when the user presses the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n\n// Function: FORM_OnRButtonDown\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle,\n                                                       FPDF_PAGE page,\n                                                       int modifier,\n                                                       double page_x,\n                                                       double page_y);\n// Function: FORM_OnLButtonUp\n//       Call this member function when the user releases the left\n//       mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in device.\n//       page_y      -   Specifies the y-coordinate of the cursor in device.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnRButtonUp\n//       Same as above, execpt for the right mouse button.\n// Comments:\n//       At the present time, has no effect except in XFA builds, but is\n//       included for the sake of symmetry.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     int modifier,\n                                                     double page_x,\n                                                     double page_y);\n\n// Function: FORM_OnLButtonDoubleClick\n//       Call this member function when the user double clicks the\n//       left mouse button.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       modifier    -   Indicates whether various virtual keys are down.\n//       page_x      -   Specifies the x-coordinate of the cursor in PDF user\n//                       space.\n//       page_y      -   Specifies the y-coordinate of the cursor in PDF user\n//                       space.\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle,\n                          FPDF_PAGE page,\n                          int modifier,\n                          double page_x,\n                          double page_y);\n\n// Function: FORM_OnKeyDown\n//       Call this member function when a nonsystem key is pressed.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, aseturned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle,\n                                                   FPDF_PAGE page,\n                                                   int nKeyCode,\n                                                   int modifier);\n\n// Function: FORM_OnKeyUp\n//       Call this member function when a nonsystem key is released.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nKeyCode    -   The virtual-key code of the given key (see\n//                       fpdf_fwlevent.h for virtual key codes).\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       Currently unimplemented and always returns false. PDFium reserves this\n//       API and may implement it in the future on an as-needed basis.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page,\n                                                 int nKeyCode,\n                                                 int modifier);\n\n// Function: FORM_OnChar\n//       Call this member function when a keystroke translates to a\n//       nonsystem character.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       nChar       -   The character code value itself.\n//       modifier    -   Mask of key flags (see fpdf_fwlevent.h for key\n//                       flag values).\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle,\n                                                FPDF_PAGE page,\n                                                int nChar,\n                                                int modifier);\n\n// Experimental API\n// Function: FORM_GetFocusedText\n//       Call this function to obtain the text within the current focused\n//       field, if any.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the form text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the form text string, |buffer| is\n//                       not modified.\n// Return Value:\n//       Length in bytes for the text in the focused field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetFocusedText(FPDF_FORMHANDLE hHandle,\n                    FPDF_PAGE page,\n                    void* buffer,\n                    unsigned long buflen);\n\n// Function: FORM_GetSelectedText\n//       Call this function to obtain selected text within a form text\n//       field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n//       buffer      -   Buffer for holding the selected text, encoded in\n//                       UTF-16LE. If NULL, |buffer| is not modified.\n//       buflen      -   Length of |buffer| in bytes. If |buflen| is less\n//                       than the length of the selected text string,\n//                       |buffer| is not modified.\n// Return Value:\n//       Length in bytes of selected text in form text field or form combobox\n//       text field.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFORM_GetSelectedText(FPDF_FORMHANDLE hHandle,\n                     FPDF_PAGE page,\n                     void* buffer,\n                     unsigned long buflen);\n\n// Experimental API\n// Function: FORM_ReplaceAndKeepSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the inserted text\n//       will be selected.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             FPDF_WIDESTRING wsText);\n\n// Function: FORM_ReplaceSelection\n//       Call this function to replace the selected text in a form\n//       text field or user-editable form combobox text field with another\n//       text string (which can be empty or non-empty). If there is no\n//       selected text, this function will append the replacement text after\n//       the current caret position. After the insertion, the selection range\n//       will be set to empty.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as Returned by FPDF_LoadPage().\n//       wsText      -   The text to be inserted, in UTF-16LE format.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle,\n                                                     FPDF_PAGE page,\n                                                     FPDF_WIDESTRING wsText);\n\n// Experimental API\n// Function: FORM_SelectAllText\n//       Call this function to select all the text within the currently focused\n//       form text field or form combobox text field.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       Whether the operation succeeded or not.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page);\n\n// Function: FORM_CanUndo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to undo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_CanRedo\n//       Find out if it is possible for the current focused widget in a given\n//       form to perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if it is possible to redo.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle,\n                                                 FPDF_PAGE page);\n\n// Function: FORM_Undo\n//       Make the current focused widget perform an undo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the undo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_Redo\n//       Make the current focused widget perform a redo operation.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return Value:\n//       True if the redo operation succeeded.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle,\n                                              FPDF_PAGE page);\n\n// Function: FORM_ForceToKillFocus.\n//       Call this member function to force to kill the focus of the form\n//       field which has focus. If it would kill the focus of a form field,\n//       save the value of form field if was changed by theuser.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       True indicates success; otherwise false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle);\n\n// Experimental API.\n// Function: FORM_GetFocusedAnnot.\n//       Call this member function to get the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       page_index  -   Buffer to hold the index number of the page which\n//                       contains the focused annotation. 0 for the first page.\n//                       Can't be NULL.\n//       annot       -   Buffer to hold the focused annotation. Can't be NULL.\n// Return Value:\n//       On success, return true and write to the out parameters. Otherwise\n//       return false and leave the out parameters unmodified.\n// Comments:\n//       Not currently supported for XFA forms - will report no focused\n//       annotation.\n//       Must call FPDFPage_CloseAnnot() when the annotation returned in |annot|\n//       by this function is no longer needed.\n//       This will return true and set |page_index| to -1 and |annot| to NULL,\n//       if there is no focused annotation.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_GetFocusedAnnot(FPDF_FORMHANDLE handle,\n                     int* page_index,\n                     FPDF_ANNOTATION* annot);\n\n// Experimental API.\n// Function: FORM_SetFocusedAnnot.\n//       Call this member function to set the currently focused annotation.\n// Parameters:\n//       handle      -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       annot       -   Handle to an annotation.\n// Return Value:\n//       True indicates success; otherwise false.\n// Comments:\n//       |annot| can't be NULL. To kill focus, use FORM_ForceToKillFocus()\n//       instead.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot);\n\n// Form Field Types\n// The names of the defines are stable, but the specific values associated with\n// them are not, so do not hardcode their values.\n#define FPDF_FORMFIELD_UNKNOWN 0      // Unknown.\n#define FPDF_FORMFIELD_PUSHBUTTON 1   // push button type.\n#define FPDF_FORMFIELD_CHECKBOX 2     // check box type.\n#define FPDF_FORMFIELD_RADIOBUTTON 3  // radio button type.\n#define FPDF_FORMFIELD_COMBOBOX 4     // combo box type.\n#define FPDF_FORMFIELD_LISTBOX 5      // list box type.\n#define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.\n#define FPDF_FORMFIELD_SIGNATURE 7    // text field type.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_XFA 8              // Generic XFA type.\n#define FPDF_FORMFIELD_XFA_CHECKBOX 9     // XFA check box type.\n#define FPDF_FORMFIELD_XFA_COMBOBOX 10    // XFA combo box type.\n#define FPDF_FORMFIELD_XFA_IMAGEFIELD 11  // XFA image field type.\n#define FPDF_FORMFIELD_XFA_LISTBOX 12     // XFA list box type.\n#define FPDF_FORMFIELD_XFA_PUSHBUTTON 13  // XFA push button type.\n#define FPDF_FORMFIELD_XFA_SIGNATURE 14   // XFA signture field type.\n#define FPDF_FORMFIELD_XFA_TEXTFIELD 15   // XFA text field type.\n#endif                                    // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 16\n#else  // PDF_ENABLE_XFA\n#define FPDF_FORMFIELD_COUNT 8\n#endif  // PDF_ENABLE_XFA\n\n#ifdef PDF_ENABLE_XFA\n#define IS_XFA_FORMFIELD(type)                  \\\n  (((type) == FPDF_FORMFIELD_XFA) ||            \\\n   ((type) == FPDF_FORMFIELD_XFA_CHECKBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_COMBOBOX) ||   \\\n   ((type) == FPDF_FORMFIELD_XFA_IMAGEFIELD) || \\\n   ((type) == FPDF_FORMFIELD_XFA_LISTBOX) ||    \\\n   ((type) == FPDF_FORMFIELD_XFA_PUSHBUTTON) || \\\n   ((type) == FPDF_FORMFIELD_XFA_SIGNATURE) ||  \\\n   ((type) == FPDF_FORMFIELD_XFA_TEXTFIELD))\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDFPage_HasFormFieldAtPoint\n//     Get the form field type by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the type of the form field; -1 indicates no field.\n//     See field types above.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,\n                             FPDF_PAGE page,\n                             double page_x,\n                             double page_y);\n\n// Function: FPDFPage_FormFieldZOrderAtPoint\n//     Get the form field z-order by point.\n// Parameters:\n//     hHandle     -   Handle to the form fill module. Returned by\n//                     FPDFDOC_InitFormFillEnvironment().\n//     page        -   Handle to the page. Returned by FPDF_LoadPage().\n//     page_x      -   X position in PDF \"user space\".\n//     page_y      -   Y position in PDF \"user space\".\n// Return Value:\n//     Return the z-order of the form field; -1 indicates no field.\n//     Higher numbers are closer to the front.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,\n                                FPDF_PAGE page,\n                                double page_x,\n                                double page_y);\n\n// Function: FPDF_SetFormFieldHighlightColor\n//       Set the highlight color of the specified (or all) form fields\n//       in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returned by\n//                       FPDF_LoadDocument().\n//       fieldType   -   A 32-bit integer indicating the type of a form\n//                       field (defined above).\n//       color       -   The highlight color of the form field. Constructed by\n//                       0xxxrrggbb.\n// Return Value:\n//       None.\n// Comments:\n//       When the parameter fieldType is set to FPDF_FORMFIELD_UNKNOWN, the\n//       highlight color will be applied to all the form fields in the\n//       document.\n//       Please refresh the client window to show the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle,\n                                int fieldType,\n                                unsigned long color);\n\n// Function: FPDF_SetFormFieldHighlightAlpha\n//       Set the transparency of the form field highlight color in the\n//       document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n//       doc         -   Handle to the document, as returaned by\n//                       FPDF_LoadDocument().\n//       alpha       -   The transparency of the form field highlight color,\n//                       between 0-255.\n// Return Value:\n//       None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha);\n\n// Function: FPDF_RemoveFormFieldHighlight\n//       Remove the form field highlight color in the document.\n// Parameters:\n//       hHandle     -   Handle to the form fill module, as returned by\n//                       FPDFDOC_InitFormFillEnvironment().\n// Return Value:\n//       None.\n// Comments:\n//       Please refresh the client window to remove the highlight immediately\n//       if necessary.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle);\n\n// Function: FPDF_FFLDraw\n//       Render FormFields and popup window on a page to a device independent\n//       bitmap.\n// Parameters:\n//       hHandle      -   Handle to the form fill module, as returned by\n//                        FPDFDOC_InitFormFillEnvironment().\n//       bitmap       -   Handle to the device independent bitmap (as the\n//                        output buffer). Bitmap handles can be created by\n//                        FPDFBitmap_Create().\n//       page         -   Handle to the page, as returned by FPDF_LoadPage().\n//       start_x      -   Left pixel position of the display area in the\n//                        device coordinates.\n//       start_y      -   Top pixel position of the display area in the device\n//                        coordinates.\n//       size_x       -   Horizontal size (in pixels) for displaying the page.\n//       size_y       -   Vertical size (in pixels) for displaying the page.\n//       rotate       -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                        clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                        degrees counter-clockwise).\n//       flags        -   0 for normal display, or combination of flags\n//                        defined above.\n// Return Value:\n//       None.\n// Comments:\n//       This function is designed to render annotations that are\n//       user-interactive, which are widget annotations (for FormFields) and\n//       popup annotations.\n//       With the FPDF_ANNOT flag, this function will render a popup annotation\n//       when users mouse-hover on a non-widget annotation. Regardless of\n//       FPDF_ANNOT flag, this function will always render widget annotations\n//       for FormFields.\n//       In order to implement the FormFill functions, implementation should\n//       call this function after rendering functions, such as\n//       FPDF_RenderPageBitmap() or FPDF_RenderPageBitmap_Start(), have\n//       finished rendering the page contents.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle,\n                                            FPDF_BITMAP bitmap,\n                                            FPDF_PAGE page,\n                                            int start_x,\n                                            int start_y,\n                                            int size_x,\n                                            int size_y,\n                                            int rotate,\n                                            int flags);\n\n#if defined(PDF_USE_SKIA)\nFPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,\n                                                FPDF_SKIA_CANVAS canvas,\n                                                FPDF_PAGE page,\n                                                int start_x,\n                                                int start_y,\n                                                int size_x,\n                                                int size_y,\n                                                int rotate,\n                                                int flags);\n#endif\n\n// Experimental API\n// Function: FPDF_GetFormType\n//           Returns the type of form contained in the PDF document.\n// Parameters:\n//           document - Handle to document.\n// Return Value:\n//           Integer value representing one of the FORMTYPE_ values.\n// Comments:\n//           If |document| is NULL, then the return value is FORMTYPE_NONE.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetFormType(FPDF_DOCUMENT document);\n\n// Experimental API\n// Function: FORM_SetIndexSelected\n//           Selects/deselects the value at the given |index| of the focused\n//           annotation.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based index of value to be set as\n//                           selected/unselected\n//           selected    -   true to select, false to deselect\n// Return Value:\n//           TRUE if the operation succeeded.\n//           FALSE if the operation failed or widget is not a supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Comboboxes\n//           have at most a single value selected at a time which cannot be\n//           deselected. Deselect on a combobox is a no-op that returns false.\n//           Default implementation is a no-op that will return false for\n//           other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_SetIndexSelected(FPDF_FORMHANDLE hHandle,\n                      FPDF_PAGE page,\n                      int index,\n                      FPDF_BOOL selected);\n\n// Experimental API\n// Function: FORM_IsIndexSelected\n//           Returns whether or not the value at |index| of the focused\n//           annotation is currently selected.\n// Parameters:\n//           hHandle     -   Handle to the form fill module. Returned by\n//                           FPDFDOC_InitFormFillEnvironment.\n//           page        -   Handle to the page. Returned by FPDF_LoadPage\n//           index       -   0-based Index of value to check\n// Return Value:\n//           TRUE if value at |index| is currently selected.\n//           FALSE if value at |index| is not selected or widget is not a\n//           supported type.\n// Comments:\n//           Intended for use with listbox/combobox widget types. Default\n//           implementation is a no-op that will return false for other types.\n//           Not currently supported for XFA forms - will return false.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index);\n\n// Function: FPDF_LoadXFA\n//          If the document consists of XFA fields, call this method to\n//          attempt to load XFA fields.\n// Parameters:\n//          document     -   Handle to document from FPDF_LoadDocument().\n// Return Value:\n//          TRUE upon success, otherwise FALSE. If XFA support is not built\n//          into PDFium, performs no action and always returns FALSE.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_LoadXFA(FPDF_DOCUMENT document);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_FORMFILL_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_fwlevent.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_FWLEVENT_H_\n#define PUBLIC_FPDF_FWLEVENT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Key flags.\ntypedef enum {\n  FWL_EVENTFLAG_ShiftKey = 1 << 0,\n  FWL_EVENTFLAG_ControlKey = 1 << 1,\n  FWL_EVENTFLAG_AltKey = 1 << 2,\n  FWL_EVENTFLAG_MetaKey = 1 << 3,\n  FWL_EVENTFLAG_KeyPad = 1 << 4,\n  FWL_EVENTFLAG_AutoRepeat = 1 << 5,\n  FWL_EVENTFLAG_LeftButtonDown = 1 << 6,\n  FWL_EVENTFLAG_MiddleButtonDown = 1 << 7,\n  FWL_EVENTFLAG_RightButtonDown = 1 << 8,\n} FWL_EVENTFLAG;\n\n// Virtual keycodes.\ntypedef enum {\n  FWL_VKEY_Back = 0x08,\n  FWL_VKEY_Tab = 0x09,\n  FWL_VKEY_NewLine = 0x0A,\n  FWL_VKEY_Clear = 0x0C,\n  FWL_VKEY_Return = 0x0D,\n  FWL_VKEY_Shift = 0x10,\n  FWL_VKEY_Control = 0x11,\n  FWL_VKEY_Menu = 0x12,\n  FWL_VKEY_Pause = 0x13,\n  FWL_VKEY_Capital = 0x14,\n  FWL_VKEY_Kana = 0x15,\n  FWL_VKEY_Hangul = 0x15,\n  FWL_VKEY_Junja = 0x17,\n  FWL_VKEY_Final = 0x18,\n  FWL_VKEY_Hanja = 0x19,\n  FWL_VKEY_Kanji = 0x19,\n  FWL_VKEY_Escape = 0x1B,\n  FWL_VKEY_Convert = 0x1C,\n  FWL_VKEY_NonConvert = 0x1D,\n  FWL_VKEY_Accept = 0x1E,\n  FWL_VKEY_ModeChange = 0x1F,\n  FWL_VKEY_Space = 0x20,\n  FWL_VKEY_Prior = 0x21,\n  FWL_VKEY_Next = 0x22,\n  FWL_VKEY_End = 0x23,\n  FWL_VKEY_Home = 0x24,\n  FWL_VKEY_Left = 0x25,\n  FWL_VKEY_Up = 0x26,\n  FWL_VKEY_Right = 0x27,\n  FWL_VKEY_Down = 0x28,\n  FWL_VKEY_Select = 0x29,\n  FWL_VKEY_Print = 0x2A,\n  FWL_VKEY_Execute = 0x2B,\n  FWL_VKEY_Snapshot = 0x2C,\n  FWL_VKEY_Insert = 0x2D,\n  FWL_VKEY_Delete = 0x2E,\n  FWL_VKEY_Help = 0x2F,\n  FWL_VKEY_0 = 0x30,\n  FWL_VKEY_1 = 0x31,\n  FWL_VKEY_2 = 0x32,\n  FWL_VKEY_3 = 0x33,\n  FWL_VKEY_4 = 0x34,\n  FWL_VKEY_5 = 0x35,\n  FWL_VKEY_6 = 0x36,\n  FWL_VKEY_7 = 0x37,\n  FWL_VKEY_8 = 0x38,\n  FWL_VKEY_9 = 0x39,\n  FWL_VKEY_A = 0x41,\n  FWL_VKEY_B = 0x42,\n  FWL_VKEY_C = 0x43,\n  FWL_VKEY_D = 0x44,\n  FWL_VKEY_E = 0x45,\n  FWL_VKEY_F = 0x46,\n  FWL_VKEY_G = 0x47,\n  FWL_VKEY_H = 0x48,\n  FWL_VKEY_I = 0x49,\n  FWL_VKEY_J = 0x4A,\n  FWL_VKEY_K = 0x4B,\n  FWL_VKEY_L = 0x4C,\n  FWL_VKEY_M = 0x4D,\n  FWL_VKEY_N = 0x4E,\n  FWL_VKEY_O = 0x4F,\n  FWL_VKEY_P = 0x50,\n  FWL_VKEY_Q = 0x51,\n  FWL_VKEY_R = 0x52,\n  FWL_VKEY_S = 0x53,\n  FWL_VKEY_T = 0x54,\n  FWL_VKEY_U = 0x55,\n  FWL_VKEY_V = 0x56,\n  FWL_VKEY_W = 0x57,\n  FWL_VKEY_X = 0x58,\n  FWL_VKEY_Y = 0x59,\n  FWL_VKEY_Z = 0x5A,\n  FWL_VKEY_LWin = 0x5B,\n  FWL_VKEY_Command = 0x5B,\n  FWL_VKEY_RWin = 0x5C,\n  FWL_VKEY_Apps = 0x5D,\n  FWL_VKEY_Sleep = 0x5F,\n  FWL_VKEY_NumPad0 = 0x60,\n  FWL_VKEY_NumPad1 = 0x61,\n  FWL_VKEY_NumPad2 = 0x62,\n  FWL_VKEY_NumPad3 = 0x63,\n  FWL_VKEY_NumPad4 = 0x64,\n  FWL_VKEY_NumPad5 = 0x65,\n  FWL_VKEY_NumPad6 = 0x66,\n  FWL_VKEY_NumPad7 = 0x67,\n  FWL_VKEY_NumPad8 = 0x68,\n  FWL_VKEY_NumPad9 = 0x69,\n  FWL_VKEY_Multiply = 0x6A,\n  FWL_VKEY_Add = 0x6B,\n  FWL_VKEY_Separator = 0x6C,\n  FWL_VKEY_Subtract = 0x6D,\n  FWL_VKEY_Decimal = 0x6E,\n  FWL_VKEY_Divide = 0x6F,\n  FWL_VKEY_F1 = 0x70,\n  FWL_VKEY_F2 = 0x71,\n  FWL_VKEY_F3 = 0x72,\n  FWL_VKEY_F4 = 0x73,\n  FWL_VKEY_F5 = 0x74,\n  FWL_VKEY_F6 = 0x75,\n  FWL_VKEY_F7 = 0x76,\n  FWL_VKEY_F8 = 0x77,\n  FWL_VKEY_F9 = 0x78,\n  FWL_VKEY_F10 = 0x79,\n  FWL_VKEY_F11 = 0x7A,\n  FWL_VKEY_F12 = 0x7B,\n  FWL_VKEY_F13 = 0x7C,\n  FWL_VKEY_F14 = 0x7D,\n  FWL_VKEY_F15 = 0x7E,\n  FWL_VKEY_F16 = 0x7F,\n  FWL_VKEY_F17 = 0x80,\n  FWL_VKEY_F18 = 0x81,\n  FWL_VKEY_F19 = 0x82,\n  FWL_VKEY_F20 = 0x83,\n  FWL_VKEY_F21 = 0x84,\n  FWL_VKEY_F22 = 0x85,\n  FWL_VKEY_F23 = 0x86,\n  FWL_VKEY_F24 = 0x87,\n  FWL_VKEY_NunLock = 0x90,\n  FWL_VKEY_Scroll = 0x91,\n  FWL_VKEY_LShift = 0xA0,\n  FWL_VKEY_RShift = 0xA1,\n  FWL_VKEY_LControl = 0xA2,\n  FWL_VKEY_RControl = 0xA3,\n  FWL_VKEY_LMenu = 0xA4,\n  FWL_VKEY_RMenu = 0xA5,\n  FWL_VKEY_BROWSER_Back = 0xA6,\n  FWL_VKEY_BROWSER_Forward = 0xA7,\n  FWL_VKEY_BROWSER_Refresh = 0xA8,\n  FWL_VKEY_BROWSER_Stop = 0xA9,\n  FWL_VKEY_BROWSER_Search = 0xAA,\n  FWL_VKEY_BROWSER_Favorites = 0xAB,\n  FWL_VKEY_BROWSER_Home = 0xAC,\n  FWL_VKEY_VOLUME_Mute = 0xAD,\n  FWL_VKEY_VOLUME_Down = 0xAE,\n  FWL_VKEY_VOLUME_Up = 0xAF,\n  FWL_VKEY_MEDIA_NEXT_Track = 0xB0,\n  FWL_VKEY_MEDIA_PREV_Track = 0xB1,\n  FWL_VKEY_MEDIA_Stop = 0xB2,\n  FWL_VKEY_MEDIA_PLAY_Pause = 0xB3,\n  FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4,\n  FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5,\n  FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6,\n  FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7,\n  FWL_VKEY_OEM_1 = 0xBA,\n  FWL_VKEY_OEM_Plus = 0xBB,\n  FWL_VKEY_OEM_Comma = 0xBC,\n  FWL_VKEY_OEM_Minus = 0xBD,\n  FWL_VKEY_OEM_Period = 0xBE,\n  FWL_VKEY_OEM_2 = 0xBF,\n  FWL_VKEY_OEM_3 = 0xC0,\n  FWL_VKEY_OEM_4 = 0xDB,\n  FWL_VKEY_OEM_5 = 0xDC,\n  FWL_VKEY_OEM_6 = 0xDD,\n  FWL_VKEY_OEM_7 = 0xDE,\n  FWL_VKEY_OEM_8 = 0xDF,\n  FWL_VKEY_OEM_102 = 0xE2,\n  FWL_VKEY_ProcessKey = 0xE5,\n  FWL_VKEY_Packet = 0xE7,\n  FWL_VKEY_Attn = 0xF6,\n  FWL_VKEY_Crsel = 0xF7,\n  FWL_VKEY_Exsel = 0xF8,\n  FWL_VKEY_Ereof = 0xF9,\n  FWL_VKEY_Play = 0xFA,\n  FWL_VKEY_Zoom = 0xFB,\n  FWL_VKEY_NoName = 0xFC,\n  FWL_VKEY_PA1 = 0xFD,\n  FWL_VKEY_OEM_Clear = 0xFE,\n  FWL_VKEY_Unknown = 0,\n} FWL_VKEYCODE;\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_FWLEVENT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_javascript.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_JAVASCRIPT_H_\n#define PUBLIC_FPDF_JAVASCRIPT_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Get the number of JavaScript actions in |document|.\n//\n//   document - handle to a document.\n//\n// Returns the number of JavaScript actions in |document| or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFDoc_GetJavaScriptActionCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Get the JavaScript action at |index| in |document|.\n//\n//   document - handle to a document.\n//   index    - the index of the requested JavaScript action.\n//\n// Returns the handle to the JavaScript action, or NULL on failure.\n// Caller owns the returned handle and must close it with\n// FPDFDoc_CloseJavaScriptAction().\nFPDF_EXPORT FPDF_JAVASCRIPT_ACTION FPDF_CALLCONV\nFPDFDoc_GetJavaScriptAction(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Close a loaded FPDF_JAVASCRIPT_ACTION object.\n\n//   javascript - Handle to a JavaScript action.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFDoc_CloseJavaScriptAction(FPDF_JAVASCRIPT_ACTION javascript);\n\n// Experimental API.\n// Get the name from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the name. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetName(FPDF_JAVASCRIPT_ACTION javascript,\n                             FPDF_WCHAR* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Get the script from the |javascript| handle. |buffer| is only modified if\n// |buflen| is longer than the length of the script. On errors, |buffer| is\n// unmodified and the returned length is 0.\n//\n//   javascript - handle to an JavaScript action.\n//   buffer     - buffer for holding the name, encoded in UTF-16LE.\n//   buflen     - length of the buffer in bytes.\n//\n// Returns the length of the JavaScript action name in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFJavaScriptAction_GetScript(FPDF_JAVASCRIPT_ACTION javascript,\n                               FPDF_WCHAR* buffer,\n                               unsigned long buflen);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_JAVASCRIPT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_ppo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PPO_H_\n#define PUBLIC_FPDF_PPO_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc     - The destination document for the pages.\n//   src_doc      - The document to be imported.\n//   page_indices - An array of page indices to be imported. The first page is\n//                  zero. If |page_indices| is NULL, all pages from |src_doc|\n//                  are imported.\n//   length       - The length of the |page_indices| array.\n//   index        - The page index at which to insert the first imported page\n//                  into |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |page_indices| is\n// invalid.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        const int* page_indices,\n                        unsigned long length,\n                        int index);\n\n// Import pages to a FPDF_DOCUMENT.\n//\n//   dest_doc  - The destination document for the pages.\n//   src_doc   - The document to be imported.\n//   pagerange - A page range string, Such as \"1,3,5-7\". The first page is one.\n//               If |pagerange| is NULL, all pages from |src_doc| are imported.\n//   index     - The page index at which to insert the first imported page into\n//               |dest_doc|. The first page is zero.\n//\n// Returns TRUE on success. Returns FALSE if any pages in |pagerange| is\n// invalid or if |pagerange| cannot be read.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,\n                                                     FPDF_DOCUMENT src_doc,\n                                                     FPDF_BYTESTRING pagerange,\n                                                     int index);\n\n// Experimental API.\n// Create a new document from |src_doc|.  The pages of |src_doc| will be\n// combined to provide |num_pages_on_x_axis x num_pages_on_y_axis| pages per\n// |output_doc| page.\n//\n//   src_doc             - The document to be imported.\n//   output_width        - The output page width in PDF \"user space\" units.\n//   output_height       - The output page height in PDF \"user space\" units.\n//   num_pages_on_x_axis - The number of pages on X Axis.\n//   num_pages_on_y_axis - The number of pages on Y Axis.\n//\n// Return value:\n//   A handle to the created document, or NULL on failure.\n//\n// Comments:\n//   number of pages per page = num_pages_on_x_axis * num_pages_on_y_axis\n//\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,\n                       float output_width,\n                       float output_height,\n                       size_t num_pages_on_x_axis,\n                       size_t num_pages_on_y_axis);\n\n// Experimental API.\n// Create a template to generate form xobjects from |src_doc|'s page at\n// |src_page_index|, for use in |dest_doc|.\n//\n// Returns a handle on success, or NULL on failure. Caller owns the newly\n// created object.\nFPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV\nFPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,\n                        FPDF_DOCUMENT src_doc,\n                        int src_page_index);\n\n// Experimental API.\n// Close an FPDF_XOBJECT handle created by FPDF_NewXObjectFromPage().\n// FPDF_PAGEOBJECTs created from the FPDF_XOBJECT handle are not affected.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject);\n\n// Experimental API.\n// Create a new form object from an FPDF_XOBJECT object.\n//\n// Returns a new form object on success, or NULL on failure. Caller owns the\n// newly created object.\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject);\n\n// Copy the viewer preferences from |src_doc| into |dest_doc|.\n//\n//   dest_doc - Document to write the viewer preferences into.\n//   src_doc  - Document to read the viewer preferences from.\n//\n// Returns TRUE on success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_PPO_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_progressive.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_PROGRESSIVE_H_\n#define PUBLIC_FPDF_PROGRESSIVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Flags for progressive process status.\n#define FPDF_RENDER_READY 0\n#define FPDF_RENDER_TOBECONTINUED 1\n#define FPDF_RENDER_DONE 2\n#define FPDF_RENDER_FAILED 3\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// IFPDF_RENDERINFO interface.\ntypedef struct _IFSDK_PAUSE {\n  // Version number of the interface. Currently must be 1.\n  int version;\n\n  // Method: NeedToPauseNow\n  //           Check if we need to pause a progressive process now.\n  // Interface Version:\n  //           1\n  // Implementation Required:\n  //           yes\n  // Parameters:\n  //           pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //           Non-zero for pause now, 0 for continue.\n  FPDF_BOOL (*NeedToPauseNow)(struct _IFSDK_PAUSE* pThis);\n\n  // A user defined data pointer, used by user's application. Can be NULL.\n  void* user;\n} IFSDK_PAUSE;\n\n// Experimental API.\n// Function: FPDF_RenderPageBitmapWithColorScheme_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively with a specified color scheme for the content.\n// Parameters:\n//          bitmap       -   Handle to the device independent bitmap (as the\n//                           output buffer). Bitmap handle can be created by\n//                           FPDFBitmap_Create function.\n//          page         -   Handle to the page as returned by FPDF_LoadPage\n//                           function.\n//          start_x      -   Left pixel position of the display area in the\n//                           bitmap coordinate.\n//          start_y      -   Top pixel position of the display area in the\n//                           bitmap coordinate.\n//          size_x       -   Horizontal size (in pixels) for displaying the\n//                           page.\n//          size_y       -   Vertical size (in pixels) for displaying the page.\n//          rotate       -   Page orientation: 0 (normal), 1 (rotated 90\n//                           degrees clockwise), 2 (rotated 180 degrees),\n//                           3 (rotated 90 degrees counter-clockwise).\n//          flags        -   0 for normal display, or combination of flags\n//                           defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                           renders all annotations that does not require\n//                           user-interaction, which are all annotations except\n//                           widget and popup annotations.\n//          color_scheme -   Color scheme to be used in rendering the |page|.\n//                           If null, this function will work similar to\n//                           FPDF_RenderPageBitmap_Start().\n//          pause        -   The IFSDK_PAUSE interface. A callback mechanism\n//                           allowing the page rendering process.\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_RenderPageBitmapWithColorScheme_Start(FPDF_BITMAP bitmap,\n                                           FPDF_PAGE page,\n                                           int start_x,\n                                           int start_y,\n                                           int size_x,\n                                           int size_y,\n                                           int rotate,\n                                           int flags,\n                                           const FPDF_COLORSCHEME* color_scheme,\n                                           IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPageBitmap_Start\n//          Start to render page contents to a device independent bitmap\n//          progressively.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). Bitmap handle can be created by\n//                          FPDFBitmap_Create().\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          start_x     -   Left pixel position of the display area in the\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in the bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation: 0 (normal), 1 (rotated 90 degrees\n//                          clockwise), 2 (rotated 180 degrees), 3 (rotated 90\n//                          degrees counter-clockwise).\n//          flags       -   0 for normal display, or combination of flags\n//                          defined in fpdfview.h. With FPDF_ANNOT flag, it\n//                          renders all annotations that does not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n//          pause       -   The IFSDK_PAUSE interface.A callback mechanism\n//                          allowing the page rendering process\n// Return value:\n//          Rendering Status. See flags for progressive process status for the\n//          details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,\n                                                          FPDF_PAGE page,\n                                                          int start_x,\n                                                          int start_y,\n                                                          int size_x,\n                                                          int size_y,\n                                                          int rotate,\n                                                          int flags,\n                                                          IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Continue\n//          Continue rendering a PDF page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n//          pause       -   The IFSDK_PAUSE interface (a callback mechanism\n//                          allowing the page rendering process to be paused\n//                          before it's finished). This can be NULL if you\n//                          don't want to pause.\n// Return value:\n//          The rendering status. See flags for progressive process status for\n//          the details.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPage_Continue(FPDF_PAGE page,\n                                                       IFSDK_PAUSE* pause);\n\n// Function: FPDF_RenderPage_Close\n//          Release the resource allocate during page rendering. Need to be\n//          called after finishing rendering or\n//          cancel the rendering.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_PROGRESSIVE_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_save.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SAVE_H_\n#define PUBLIC_FPDF_SAVE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Structure for custom file write\ntypedef struct FPDF_FILEWRITE_ {\n  //\n  // Version number of the interface. Currently must be 1.\n  //\n  int version;\n\n  // Method: WriteBlock\n  //          Output a block of data in your custom way.\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          Yes\n  // Comments:\n  //          Called by function FPDF_SaveDocument\n  // Parameters:\n  //          self        -   Pointer to the structure itself\n  //          data        -   Pointer to a buffer to output\n  //          size        -   The size of the buffer.\n  // Return value:\n  //          Should be non-zero if successful, zero for error.\n  int (*WriteBlock)(struct FPDF_FILEWRITE_* self,\n                    const void* data,\n                    unsigned long size);\n} FPDF_FILEWRITE;\n\n// Flags for FPDF_SaveAsCopy().\n// FPDF_INCREMENTAL and FPDF_NO_INCREMENTAL cannot be used together.\n#define FPDF_INCREMENTAL (1 << 0)\n#define FPDF_NO_INCREMENTAL (1 << 1)\n // Deprecated. Use FPDF_REMOVE_SECURITY instead.\n // TODO(crbug.com/42270430): Remove FPDF_REMOVE_SECURITY_DEPRECATED.\n#define FPDF_REMOVE_SECURITY_DEPRECATED 3\n#define FPDF_REMOVE_SECURITY (1 << 2)\n// Experimental. Subsets any embedded font files for new text objects added to\n// the document.\n#define FPDF_SUBSET_NEW_FONTS (1 << 3)\n\n// Function: FPDF_SaveAsCopy\n//          Saves the copy of specified document in custom way.\n// Parameters:\n//          document        -   Handle to document, as returned by\n//                              FPDF_LoadDocument() or FPDF_CreateNewDocument().\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   Flags above that affect how the PDF gets saved.\n//                              Pass in 0 when there are no flags.\n// Return value:\n//          TRUE for succeed, FALSE for failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SaveAsCopy(FPDF_DOCUMENT document,\n                                                    FPDF_FILEWRITE* file_write,\n                                                    FPDF_DWORD flags);\n\n// Function: FPDF_SaveWithVersion\n//          Same as FPDF_SaveAsCopy(), except the file version of the\n//          saved document can be specified by the caller.\n// Parameters:\n//          document        -   Handle to document.\n//          file_write      -   A pointer to a custom file write structure.\n//          flags           -   The creating flags.\n//          file_version    -   The PDF file version. File version: 14 for 1.4,\n//                              15 for 1.5, ...\n// Return value:\n//          TRUE if succeed, FALSE if failed.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_SaveWithVersion(FPDF_DOCUMENT document,\n                     FPDF_FILEWRITE* file_write,\n                     FPDF_DWORD flags,\n                     int file_version);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SAVE_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_searchex.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SEARCHEX_H_\n#define PUBLIC_FPDF_SEARCHEX_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Get the character index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nTextIndex - index of the text returned from FPDFText_GetText().\n//\n// Returns the index of the character in internal character list. -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexFromTextIndex(FPDF_TEXTPAGE text_page, int nTextIndex);\n\n// Get the text index in |text_page| internal character list.\n//\n//   text_page  - a text page information structure.\n//   nCharIndex - index of the character in internal character list.\n//\n// Returns the index of the text returned from FPDFText_GetText(). -1 for error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetTextIndexFromCharIndex(FPDF_TEXTPAGE text_page, int nCharIndex);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SEARCHEX_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_signature.h",
    "content": "// Copyright 2020 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_SIGNATURE_H_\n#define PUBLIC_FPDF_SIGNATURE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // __cplusplus\n\n// Experimental API.\n// Function: FPDF_GetSignatureCount\n//          Get total number of signatures in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n// Return value:\n//          Total number of signatures in the document on success, -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetSignatureCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetSignatureObject\n//          Get the Nth signature of the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          index       -   Index into the array of signatures of the document.\n// Return value:\n//          Returns the handle to the signature, or NULL on failure. The caller\n//          does not take ownership of the returned FPDF_SIGNATURE. Instead, it\n//          remains valid until FPDF_CloseDocument() is called for the document.\nFPDF_EXPORT FPDF_SIGNATURE FPDF_CALLCONV\nFPDF_GetSignatureObject(FPDF_DOCUMENT document, int index);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetContents\n//          Get the contents of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the contents.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the contents on success, 0 on error.\n//\n// For public-key signatures, |buffer| is either a DER-encoded PKCS#1 binary or\n// a DER-encoded PKCS#7 binary. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetContents(FPDF_SIGNATURE signature,\n                             void* buffer,\n                             unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetByteRange\n//          Get the byte range of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the\n//                          byte range.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the byte range on\n//          success, 0 on error.\n//\n// |buffer| is an array of pairs of integers (starting byte offset,\n// length in bytes) that describes the exact byte range for the digest\n// calculation. If |length| is less than the returned length, or\n// |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetByteRange(FPDF_SIGNATURE signature,\n                              int* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetSubFilter\n//          Get the encoding of the value of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the encoding.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetSubFilter(FPDF_SIGNATURE signature,\n                              char* buffer,\n                              unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetReason\n//          Get the reason (comment) of the signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the reason.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the reason on success, 0 on error.\n//\n// Regardless of the platform, the |buffer| is always in UTF-16LE encoding. The\n// string is terminated by a UTF16 NUL character. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetReason(FPDF_SIGNATURE signature,\n                           void* buffer,\n                           unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetTime\n//          Get the time of signing of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n//          buffer      -   The address of a buffer that receives the time.\n//          length      -   The size, in bytes, of |buffer|.\n// Return value:\n//          Returns the number of bytes in the encoding name (including the\n//          trailing NUL character) on success, 0 on error.\n//\n// The |buffer| is always encoded in 7-bit ASCII. If |length| is less than the\n// returned length, or |buffer| is NULL, |buffer| will not be modified.\n//\n// The format of time is expected to be D:YYYYMMDDHHMMSS+XX'YY', i.e. it's\n// percision is seconds, with timezone information. This value should be used\n// only when the time of signing is not available in the (PKCS#7 binary)\n// signature.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFSignatureObj_GetTime(FPDF_SIGNATURE signature,\n                         char* buffer,\n                         unsigned long length);\n\n// Experimental API.\n// Function: FPDFSignatureObj_GetDocMDPPermission\n//          Get the DocMDP permission of a signature object.\n// Parameters:\n//          signature   -   Handle to the signature object. Returned by\n//                          FPDF_GetSignatureObject().\n// Return value:\n//          Returns the permission (1, 2 or 3) on success, 0 on error.\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFSignatureObj_GetDocMDPPermission(FPDF_SIGNATURE signature);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  // PUBLIC_FPDF_SIGNATURE_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_structtree.h",
    "content": "// Copyright 2016 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_STRUCTTREE_H_\n#define PUBLIC_FPDF_STRUCTTREE_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDF_StructTree_GetForPage\n//          Get the structure tree for a page.\n// Parameters:\n//          page        -   Handle to the page, as returned by FPDF_LoadPage().\n// Return value:\n//          A handle to the structure tree or NULL on error. The caller owns the\n//          returned handle and must use FPDF_StructTree_Close() to release it.\n//          The handle should be released before |page| gets released.\nFPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV\nFPDF_StructTree_GetForPage(FPDF_PAGE page);\n\n// Function: FPDF_StructTree_Close\n//          Release a resource allocated by FPDF_StructTree_GetForPage().\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_CountChildren\n//          Count the number of children for the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree);\n\n// Function: FPDF_StructTree_GetChildAtIndex\n//          Get a child in the structure tree.\n// Parameters:\n//          struct_tree -   Handle to the structure tree, as returned by\n//                          FPDF_StructTree_LoadPage().\n//          index       -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error. The caller does not\n//          own the handle. The handle remains valid as long as |struct_tree|\n//          remains valid.\n// Comments:\n//          The |index| must be less than the FPDF_StructTree_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index);\n\n// Function: FPDF_StructElement_GetAltText\n//          Get the alt text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the alt text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the alt text, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetActualText\n//          Get the actual text for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the actual text. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the actual text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetExpansion\n//          Get the expansion of an abbreviation or acronym for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the expansion text. May be\n//                             NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the expansion text, including the terminating\n//          NUL character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetExpansion(FPDF_STRUCTELEMENT struct_element,\n                                void* buffer,\n                                unsigned long buflen);\n\n// Function: FPDF_StructElement_GetID\n//          Get the ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the ID string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,\n                         void* buffer,\n                         unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetLang\n//          Get the case-insensitive IETF BCP 47 language code for an element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          buffer         -   A buffer for output the lang string. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the ID string, including the terminating NUL\n//          character. The number of bytes is returned regardless of the\n//          |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetStringAttribute\n//          Get a struct element attribute of type \"name\" or \"string\".\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          attr_name      -   The name of the attribute to retrieve.\n//          buffer         -   A buffer for output. May be NULL.\n//          buflen         -   The length of the buffer, in bytes. May be 0.\n// Return value:\n//          The number of bytes in the attribute value, including the\n//          terminating NUL character. The number of bytes is returned\n//          regardless of the |buffer| and |buflen| parameters.\n// Comments:\n//          Regardless of the platform, the |buffer| is always in UTF-16LE\n//          encoding. The string is terminated by a UTF16 NUL character. If\n//          |buflen| is less than the required length, or |buffer| is NULL,\n//          |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,\n                                      FPDF_BYTESTRING attr_name,\n                                      void* buffer,\n                                      unsigned long buflen);\n\n// Function: FPDF_StructElement_GetMarkedContentID\n//          Get the marked content ID for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          FPDF_StructElement_GetMarkedContentIdAtIndex() may be able to\n//          extract more marked content IDs out of |struct_element|. This API\n//          may be deprecated in the future.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetType\n//           Get the type (/S) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the type, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,\n                           void* buffer,\n                           unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetObjType\n//           Get the object type (/Type) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the object type, including the terminating\n//           NUL character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,\n                              void* buffer,\n                              unsigned long buflen);\n\n// Function: FPDF_StructElement_GetTitle\n//           Get the title (/T) for a given element.\n// Parameters:\n//           struct_element - Handle to the struct element.\n//           buffer         - A buffer for output. May be NULL.\n//           buflen         - The length of the buffer, in bytes. May be 0.\n// Return value:\n//           The number of bytes in the title, including the terminating NUL\n//           character. The number of bytes is returned regardless of the\n//           |buffer| and |buflen| parameters.\n// Comments:\n//           Regardless of the platform, the |buffer| is always in UTF-16LE\n//           encoding. The string is terminated by a UTF16 NUL character. If\n//           |buflen| is less than the required length, or |buffer| is NULL,\n//           |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,\n                            void* buffer,\n                            unsigned long buflen);\n\n// Function: FPDF_StructElement_CountChildren\n//          Count the number of children for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetChildAtIndex\n//          Get a child in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The child at the n-th index or NULL on error.\n// Comments:\n//          If the child exists but is not an element, then this function will\n//          return NULL. This will also return NULL for out of bounds indices.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                   int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetChildMarkedContentID\n//          Get the child's content id\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the child, 0-based.\n// Return value:\n//          The marked content ID of the child. If no ID exists, returns -1.\n// Comments:\n//          If the child exists but is not a stream or object, then this\n//          function will return -1. This will also return -1 for out of bounds\n//          indices. Compared to FPDF_StructElement_GetMarkedContentIdAtIndex,\n//          it is scoped to the current page.\n//          The |index| must be less than the FPDF_StructElement_CountChildren()\n//          return value.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetChildMarkedContentID(FPDF_STRUCTELEMENT struct_element,\n                                           int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetParent\n//          Get the parent of the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The parent structure element or NULL on error.\n// Comments:\n//          If structure element is StructTreeRoot, then this function will\n//          return NULL.\nFPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV\nFPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element);\n\n// Function: FPDF_StructElement_GetAttributeCount\n//          Count the number of attributes for the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetAttributeAtIndex\n//          Get an attribute object in the structure element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index for the attribute object, 0-based.\n// Return value:\n//          The attribute object at the n-th index or NULL on error.\n// Comments:\n//          If the attribute object exists but is not a dict, then this\n//          function will return NULL. This will also return NULL for out of\n//          bounds indices. The caller does not own the handle. The handle\n//          remains valid as long as |struct_element| remains valid.\n//          The |index| must be less than the\n//          FPDF_StructElement_GetAttributeCount() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV\nFPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element, int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetCount\n//          Count the number of attributes in a structure element attribute map.\n// Parameters:\n//          struct_attribute - Handle to the struct element attribute.\n// Return value:\n//          The number of attributes, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute);\n\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetName\n//          Get the name of an attribute in a structure element attribute map.\n// Parameters:\n//          struct_attribute   - Handle to the struct element attribute.\n//          index              - The index of attribute in the map.\n//          buffer             - A buffer for output. May be NULL. This is only\n//                               modified if |buflen| is longer than the length\n//                               of the key. Optional, pass null to just\n//                               retrieve the size of the buffer needed.\n//          buflen             - The length of the buffer.\n//          out_buflen         - A pointer to variable that will receive the\n//                               minimum buffer size to contain the key. Not\n//                               filled if FALSE is returned.\n// Return value:\n//          TRUE if the operation was successful, FALSE otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                int index,\n                                void* buffer,\n                                unsigned long buflen,\n                                unsigned long* out_buflen);\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetValue\n//           Get a handle to a value for an attribute in a structure element\n//           attribute map.\n// Parameters:\n//           struct_attribute   - Handle to the struct element attribute.\n//           name               - The attribute name.\n// Return value:\n//           Returns a handle to the value associated with the input, if any.\n//           Returns NULL on failure. The caller does not own the handle.\n//           The handle remains valid as long as |struct_attribute| remains\n//           valid.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,\n                                 FPDF_BYTESTRING name);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetType\n//           Get the type of an attribute in a structure element attribute map.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           Returns the type of the value, or FPDF_OBJECT_UNKNOWN in case of\n//           failure. Note that this will never return FPDF_OBJECT_REFERENCE, as\n//           references are always dereferenced.\nFPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBooleanValue\n//           Get the value of a boolean attribute in an attribute map as\n//           FPDF_BOOL. FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_BOOLEAN for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a boolean value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        FPDF_BOOL* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetNumberValue\n//           Get the value of a number attribute in an attribute map as float.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_NUMBER for this property.\n// Parameters:\n//           value     - Handle to the value.\n//           out_value - A pointer to variable that will receive the value. Not\n//                       filled if false is returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a number value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       float* out_value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetStringValue\n//           Get the value of a string attribute in an attribute map as string.\n//           FPDF_StructElement_Attr_GetType() should have returned\n//           FPDF_OBJECT_STRING or FPDF_OBJECT_NAME for this property.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned key in UTF-16LE.\n//                        This is only modified if |buflen| is longer than the\n//                        length of the key. Optional, pass null to just\n//                        retrieve the size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                       void* buffer,\n                                       unsigned long buflen,\n                                       unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetBlobValue\n//           Get the value of a blob attribute in an attribute map as string.\n// Parameters:\n//           value      - Handle to the value.\n//           buffer     - A buffer for holding the returned value. This is only\n//                        modified if |buflen| is at least as long as the length\n//                        of the value. Optional, pass null to just retrieve the\n//                        size of the buffer needed.\n//           buflen     - The length of the buffer.\n//           out_buflen - A pointer to variable that will receive the minimum\n//                        buffer size to contain the key. Not filled if FALSE is\n//                        returned.\n// Return value:\n//           Returns TRUE if the attribute maps to a string value, FALSE\n//           otherwise.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                     void* buffer,\n                                     unsigned long buflen,\n                                     unsigned long* out_buflen);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_CountChildren\n//           Count the number of children values in an attribute.\n// Parameters:\n//           value - Handle to the value.\n// Return value:\n//           The number of children, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_Attr_CountChildren(FPDF_STRUCTELEMENT_ATTR_VALUE value);\n\n// Experimental API.\n// Function: FPDF_StructElement_Attr_GetChildAtIndex\n//           Get a child from an attribute.\n// Parameters:\n//           value - Handle to the value.\n//           index - The index for the child, 0-based.\n// Return value:\n//           The child at the n-th index or NULL on error.\n// Comments:\n//           The |index| must be less than the\n//           FPDF_StructElement_Attr_CountChildren() return value.\nFPDF_EXPORT FPDF_STRUCTELEMENT_ATTR_VALUE FPDF_CALLCONV\nFPDF_StructElement_Attr_GetChildAtIndex(FPDF_STRUCTELEMENT_ATTR_VALUE value,\n                                        int index);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdCount\n//          Get the count of marked content ids for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n// Return value:\n//          The count of marked content ids or -1 if none exists.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element);\n\n// Experimental API.\n// Function: FPDF_StructElement_GetMarkedContentIdAtIndex\n//          Get the marked content id at a given index for a given element.\n// Parameters:\n//          struct_element -   Handle to the struct element.\n//          index          -   The index of the marked content id, 0-based.\n// Return value:\n//          The marked content ID of the element. If no ID exists, returns\n//          -1.\n// Comments:\n//          The |index| must be less than the\n//          FPDF_StructElement_GetMarkedContentIdCount() return value.\n//          This will likely supersede FPDF_StructElement_GetMarkedContentID().\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,\n                                             int index);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif\n\n#endif  // PUBLIC_FPDF_STRUCTTREE_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_sysfontinfo.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_SYSFONTINFO_H_\n#define PUBLIC_FPDF_SYSFONTINFO_H_\n\n#include <stddef.h>\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Character sets for the font\n#define FXFONT_ANSI_CHARSET 0\n#define FXFONT_DEFAULT_CHARSET 1\n#define FXFONT_SYMBOL_CHARSET 2\n#define FXFONT_SHIFTJIS_CHARSET 128\n#define FXFONT_HANGEUL_CHARSET 129\n#define FXFONT_GB2312_CHARSET 134\n#define FXFONT_CHINESEBIG5_CHARSET 136\n#define FXFONT_GREEK_CHARSET 161\n#define FXFONT_VIETNAMESE_CHARSET 163\n#define FXFONT_HEBREW_CHARSET 177\n#define FXFONT_ARABIC_CHARSET 178\n#define FXFONT_CYRILLIC_CHARSET 204\n#define FXFONT_THAI_CHARSET 222\n#define FXFONT_EASTERNEUROPEAN_CHARSET 238\n\n// Font pitch and family flags\n#define FXFONT_FF_FIXEDPITCH (1 << 0)\n#define FXFONT_FF_ROMAN (1 << 4)\n#define FXFONT_FF_SCRIPT (4 << 4)\n\n// Typical weight values\n#define FXFONT_FW_NORMAL 400\n#define FXFONT_FW_BOLD 700\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Interface: FPDF_SYSFONTINFO\n//          Interface for getting system font information and font mapping\ntypedef struct _FPDF_SYSFONTINFO {\n  // Version number of the interface. Currently must be 1 or 2.\n  // Version 1: Traditional behavior - calls EnumFonts during initialization.\n  // Version 2: Per-request behavior - skips EnumFonts, relies on MapFont.\n  //            Experimental: Subject to change based on feedback.\n  int version;\n\n  // Method: Release\n  //          Give implementation a chance to release any data after the\n  //          interface is no longer used.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  // Return Value:\n  //          None\n  // Comments:\n  //          Called by PDFium during the final cleanup process.\n  void (*Release)(struct _FPDF_SYSFONTINFO* pThis);\n\n  // Method: EnumFonts\n  //          Enumerate all fonts installed on the system\n  // Interface Version:\n  //          1\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          pMapper     -   An opaque pointer to internal font mapper, used\n  //                          when calling FPDF_AddInstalledFont().\n  // Return Value:\n  //          None\n  // Comments:\n  //          Implementations should call FPDF_AddInstalledFont() function for\n  //          each font found. Only TrueType/OpenType and Type1 fonts are\n  //          accepted by PDFium.\n  //          NOTE: This method will not be called when version is set to 2.\n  //          Version 2 relies entirely on MapFont() for per-request matching.\n  void (*EnumFonts)(struct _FPDF_SYSFONTINFO* pThis, void* pMapper);\n\n  // Method: MapFont\n  //          Use the system font mapper to get a font handle from requested\n  //          parameters.\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if GetFont method is not implemented.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          weight      -   Weight of the requested font. 400 is normal and\n  //                          700 is bold.\n  //          bItalic     -   Italic option of the requested font, TRUE or\n  //                          FALSE.\n  //          charset     -   Character set identifier for the requested font.\n  //                          See above defined constants.\n  //          pitch_family -  A combination of flags. See above defined\n  //                          constants.\n  //          face        -   Typeface name. Currently use system local encoding\n  //                          only.\n  //          bExact      -   Obsolete: this parameter is now ignored.\n  // Return Value:\n  //          An opaque pointer for font handle, or NULL if system mapping is\n  //          not supported.\n  // Comments:\n  //          If the system supports native font mapper (like Windows),\n  //          implementation can implement this method to get a font handle.\n  //          Otherwise, PDFium will do the mapping and then call GetFont\n  //          method. Only TrueType/OpenType and Type1 fonts are accepted\n  //          by PDFium.\n  void* (*MapFont)(struct _FPDF_SYSFONTINFO* pThis,\n                   int weight,\n                   FPDF_BOOL bItalic,\n                   int charset,\n                   int pitch_family,\n                   const char* face,\n                   FPDF_BOOL* bExact);\n\n  // Method: GetFont\n  //          Get a handle to a particular font by its internal ID\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Required if MapFont method is not implemented.\n  // Return Value:\n  //          An opaque pointer for font handle.\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          face        -   Typeface name in system local encoding.\n  // Comments:\n  //          If the system mapping not supported, PDFium will do the font\n  //          mapping and use this method to get a font handle.\n  void* (*GetFont)(struct _FPDF_SYSFONTINFO* pThis, const char* face);\n\n  // Method: GetFontData\n  //          Get font data from a font\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          table       -   TrueType/OpenType table identifier (refer to\n  //                          TrueType specification), or 0 for the whole file.\n  //          buffer      -   The buffer receiving the font data. Can be NULL if\n  //                          not provided.\n  //          buf_size    -   Buffer size, can be zero if not provided.\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  // Comments:\n  //          Can read either the full font file, or a particular\n  //          TrueType/OpenType table.\n  unsigned long (*GetFontData)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               unsigned int table,\n                               unsigned char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFaceName\n  //          Get face name from a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  //          buffer      -   The buffer receiving the face name. Can be NULL if\n  //                          not provided\n  //          buf_size    -   Buffer size, can be zero if not provided\n  // Return Value:\n  //          Number of bytes needed, if buffer not provided or not large\n  //          enough, or number of bytes written into buffer otherwise.\n  unsigned long (*GetFaceName)(struct _FPDF_SYSFONTINFO* pThis,\n                               void* hFont,\n                               char* buffer,\n                               unsigned long buf_size);\n\n  // Method: GetFontCharset\n  //          Get character set information for a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          No\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          Character set identifier. See defined constants above.\n  int (*GetFontCharset)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n\n  // Method: DeleteFont\n  //          Delete a font handle\n  // Interface Version:\n  //          1 and 2\n  // Implementation Required:\n  //          Yes\n  // Parameters:\n  //          pThis       -   Pointer to the interface structure itself\n  //          hFont       -   Font handle returned by MapFont or GetFont method\n  // Return Value:\n  //          None\n  void (*DeleteFont)(struct _FPDF_SYSFONTINFO* pThis, void* hFont);\n} FPDF_SYSFONTINFO;\n\n// Struct: FPDF_CharsetFontMap\n//    Provides the name of a font to use for a given charset value.\ntypedef struct FPDF_CharsetFontMap_ {\n  int charset;  // Character Set Enum value, see FXFONT_*_CHARSET above.\n  const char* fontname;  // Name of default font to use with that charset.\n} FPDF_CharsetFontMap;\n\n// Function: FPDF_GetDefaultTTFMap\n//    Returns a pointer to the default character set to TT Font name map. The\n//    map is an array of FPDF_CharsetFontMap structs, with its end indicated\n//    by a { -1, NULL } entry.\n// Parameters:\n//     None.\n// Return Value:\n//     Pointer to the Charset Font Map.\n// Note:\n//     Once FPDF_GetDefaultTTFMapCount() and FPDF_GetDefaultTTFMapEntry() are no\n//     longer experimental, this API will be marked as deprecated.\n//     See https://crbug.com/348468114\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV FPDF_GetDefaultTTFMap();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapCount\n//    Returns the number of entries in the default character set to TT Font name\n//    map.\n// Parameters:\n//    None.\n// Return Value:\n//    The number of entries in the map.\nFPDF_EXPORT size_t FPDF_CALLCONV FPDF_GetDefaultTTFMapCount();\n\n// Experimental API.\n//\n// Function: FPDF_GetDefaultTTFMapEntry\n//    Returns an entry in the default character set to TT Font name map.\n// Parameters:\n//    index    -   The index to the entry in the map to retrieve.\n// Return Value:\n//     A pointer to the entry, if it is in the map, or NULL if the index is out\n//     of bounds.\nFPDF_EXPORT const FPDF_CharsetFontMap* FPDF_CALLCONV\nFPDF_GetDefaultTTFMapEntry(size_t index);\n\n// Function: FPDF_AddInstalledFont\n//          Add a system font to the list in PDFium.\n// Comments:\n//          This function is only called during the system font list building\n//          process.\n// Parameters:\n//          mapper          -   Opaque pointer to Foxit font mapper\n//          face            -   The font face name\n//          charset         -   Font character set. See above defined constants.\n// Return Value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_AddInstalledFont(void* mapper,\n                                                     const char* face,\n                                                     int charset);\n\n// Function: FPDF_SetSystemFontInfo\n//          Set the system font info interface into PDFium\n// Parameters:\n//          font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//          None\n// Comments:\n//          Platform support implementation should implement required methods of\n//          FFDF_SYSFONTINFO interface, then call this function during PDFium\n//          initialization process.\n//\n//          Call this with NULL to tell PDFium to stop using a previously set\n//          |FPDF_SYSFONTINFO|.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_SetSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n// Function: FPDF_GetDefaultSystemFontInfo\n//          Get default system font info interface for current platform\n// Parameters:\n//          None\n// Return Value:\n//          Pointer to a FPDF_SYSFONTINFO structure describing the default\n//          interface, or NULL if the platform doesn't have a default interface.\n//          Application should call FPDF_FreeDefaultSystemFontInfo to free the\n//          returned pointer.\n// Comments:\n//          For some platforms, PDFium implements a default version of system\n//          font info interface. The default implementation can be passed to\n//          FPDF_SetSystemFontInfo().\nFPDF_EXPORT FPDF_SYSFONTINFO* FPDF_CALLCONV FPDF_GetDefaultSystemFontInfo();\n\n// Function: FPDF_FreeDefaultSystemFontInfo\n//           Free a default system font info interface\n// Parameters:\n//           font_info       -   Pointer to a FPDF_SYSFONTINFO structure\n// Return Value:\n//           None\n// Comments:\n//           This function should be called on the output from\n//           FPDF_GetDefaultSystemFontInfo() once it is no longer needed.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_FreeDefaultSystemFontInfo(FPDF_SYSFONTINFO* font_info);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_SYSFONTINFO_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_text.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TEXT_H_\n#define PUBLIC_FPDF_TEXT_H_\n\n// clang-format off\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Function: FPDFText_LoadPage\n//          Prepare information about all characters in a page.\n// Parameters:\n//          page    -   Handle to the page. Returned by FPDF_LoadPage function\n//                      (in FPDFVIEW module).\n// Return value:\n//          A handle to the text page information structure.\n//          NULL if something goes wrong.\n// Comments:\n//          Application must call FPDFText_ClosePage to release the text page\n//          information.\n//\nFPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page);\n\n// Function: FPDFText_ClosePage\n//          Release all resources allocated for a text page information\n//          structure.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_CountChars\n//          Get number of characters in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return value:\n//          Number of characters in the page. Return -1 for error.\n//          Generated characters, like additional space characters, new line\n//          characters, are also counted.\n// Comments:\n//          Characters in a page form a \"stream\", inside the stream, each\n//          character has an index.\n//          We will use the index parameters in many of FPDFTEXT functions. The\n//          first character in the page\n//          has an index value of zero.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFText_GetUnicode\n//          Get Unicode of a character in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The Unicode of the particular character.\n//          If a character is not encoded in Unicode and Foxit engine can't\n//          convert to Unicode,\n//          the return value will be zero.\n//\nFPDF_EXPORT unsigned int FPDF_CALLCONV\nFPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_GetTextObject\n//          Get the FPDF_PAGEOBJECT associated with a given character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The associated text object for the character at |index|, or NULL on\n//          error. The returned text object, if non-null, is of type\n//          |FPDF_PAGEOBJ_TEXT|. The caller does not own the returned object.\n//\nFPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV\nFPDFText_GetTextObject(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsGenerated\n//          Get if a character in a page is generated by PDFium.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is generated by PDFium.\n//          0 if the character is not generated by PDFium.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsGenerated(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_IsHyphen\n//          Get if a character in a page is a hyphen.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character is a hyphen.\n//          0 if the character is not a hyphen.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_IsHyphen(FPDF_TEXTPAGE text_page, int index);\n\n// Experimental API.\n// Function: FPDFText_HasUnicodeMapError\n//          Get if a character in a page has an invalid unicode mapping.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          1 if the character has an invalid unicode mapping.\n//          0 if the character has no known unicode mapping issues.\n//          -1 if there was an error.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index);\n\n// Function: FPDFText_GetFontSize\n//          Get the font size of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          The font size of the particular character, measured in points (about\n//          1/72 inch). This is the typographic size of the font (so called\n//          \"em size\").\n//\nFPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Experimental API.\n// Function: FPDFText_GetFontInfo\n//          Get the font name and flags of a particular character.\n// Parameters:\n//          text_page - Handle to a text page information structure.\n//                      Returned by FPDFText_LoadPage function.\n//          index     - Zero-based index of the character.\n//          buffer    - A buffer receiving the font name.\n//          buflen    - The length of |buffer| in bytes.\n//          flags     - Optional pointer to an int receiving the font flags.\n//                      These flags should be interpreted per PDF spec 1.7\n//                      Section 5.7.1 Font Descriptor Flags.\n// Return value:\n//          On success, return the length of the font name, including the\n//          trailing NUL character, in bytes. If this length is less than or\n//          equal to |length|, |buffer| is set to the font name, |flags| is\n//          set to the font flags. |buffer| is in UTF-8 encoding. Return 0 on\n//          failure.\n//\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,\n                     int index,\n                     void* buffer,\n                     unsigned long buflen,\n                     int* flags);\n\n// Experimental API.\n// Function: FPDFText_GetFontWeight\n//          Get the font weight of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return value:\n//          On success, return the font weight of the particular character. If\n//          |text_page| is invalid, if |index| is out of bounds, or if the\n//          character's text object is undefined, return -1.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,\n                                                     int index);\n\n// Experimental API.\n// Function: FPDFText_GetFillColor\n//          Get the fill color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the fill color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the fill color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the fill color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the fill color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetFillColor(FPDF_TEXTPAGE text_page,\n                      int index,\n                      unsigned int* R,\n                      unsigned int* G,\n                      unsigned int* B,\n                      unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetStrokeColor\n//          Get the stroke color of a particular character.\n// Parameters:\n//          text_page      -   Handle to a text page information structure.\n//                             Returned by FPDFText_LoadPage function.\n//          index          -   Zero-based index of the character.\n//          R              -   Pointer to an unsigned int number receiving the\n//                             red value of the stroke color.\n//          G              -   Pointer to an unsigned int number receiving the\n//                             green value of the stroke color.\n//          B              -   Pointer to an unsigned int number receiving the\n//                             blue value of the stroke color.\n//          A              -   Pointer to an unsigned int number receiving the\n//                             alpha value of the stroke color.\n// Return value:\n//          Whether the call succeeded. If false, |R|, |G|, |B| and |A| are\n//          unchanged.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,\n                        int index,\n                        unsigned int* R,\n                        unsigned int* G,\n                        unsigned int* B,\n                        unsigned int* A);\n\n// Experimental API.\n// Function: FPDFText_GetCharAngle\n//          Get character rotation angle.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n// Return Value:\n//          On success, return the angle value in radian. Value will always be\n//          greater or equal to 0. If |text_page| is invalid, or if |index| is\n//          out of bounds, then return -1.\n//\nFPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,\n                                                      int index);\n\n// Function: FPDFText_GetCharBox\n//          Get bounding box of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          left        -   Pointer to a double number receiving left position\n//                          of the character box.\n//          right       -   Pointer to a double number receiving right position\n//                          of the character box.\n//          bottom      -   Pointer to a double number receiving bottom position\n//                          of the character box.\n//          top         -   Pointer to a double number receiving top position of\n//                          the character box.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |right|, |bottom|, and\n//          |top|. If |text_page| is invalid, or if |index| is out of bounds,\n//          then return FALSE, and the out parameters remain unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,\n                                                        int index,\n                                                        double* left,\n                                                        double* right,\n                                                        double* bottom,\n                                                        double* top);\n\n// Experimental API.\n// Function: FPDFText_GetLooseCharBox\n//          Get a \"loose\" bounding box of a particular character, i.e., covering\n//          the entire glyph bounds, without taking the actual glyph shape into\n//          account.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          rect        -   Pointer to a FS_RECTF receiving the character box.\n// Return Value:\n//          On success, return TRUE and fill in |rect|. If |text_page| is\n//          invalid, or if |index| is out of bounds, then return FALSE, and the\n//          |rect| out parameter remains unmodified.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDFText_GetMatrix\n//          Get the effective transformation matrix for a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage().\n//          index       -   Zero-based index of the character.\n//          matrix      -   Pointer to a FS_MATRIX receiving the transformation\n//                          matrix.\n// Return Value:\n//          On success, return TRUE and fill in |matrix|. If |text_page| is\n//          invalid, or if |index| is out of bounds, or if |matrix| is NULL,\n//          then return FALSE, and |matrix| remains unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,\n                                                       int index,\n                                                       FS_MATRIX* matrix);\n\n// Function: FPDFText_GetCharOrigin\n//          Get origin of a particular character.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          index       -   Zero-based index of the character.\n//          x           -   Pointer to a double number receiving x coordinate of\n//                          the character origin.\n//          y           -   Pointer to a double number receiving y coordinate of\n//                          the character origin.\n// Return Value:\n//          Whether the call succeeded. If false, x and y are unchanged.\n// Comments:\n//          All positions are measured in PDF \"user space\".\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,\n                       int index,\n                       double* x,\n                       double* y);\n\n// Function: FPDFText_GetCharIndexAtPos\n//          Get the index of a character at or nearby a certain position on the\n//          page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          x           -   X position in PDF \"user space\".\n//          y           -   Y position in PDF \"user space\".\n//          xTolerance  -   An x-axis tolerance value for character hit\n//                          detection, in point units.\n//          yTolerance  -   A y-axis tolerance value for character hit\n//                          detection, in point units.\n// Return Value:\n//          The zero-based index of the character at, or nearby the point (x,y).\n//          If there is no character at or nearby the point, return value will\n//          be -1. If an error occurs, -3 will be returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,\n                           double x,\n                           double y,\n                           double xTolerance,\n                           double yTolerance);\n\n// Function: FPDFText_GetText\n//          Extract unicode text string from the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start characters.\n//          count       -   Number of UCS-2 values to be extracted.\n//          result      -   A buffer (allocated by application) receiving the\n//                          extracted UCS-2 values. The buffer must be able to\n//                          hold `count` UCS-2 values plus a terminator.\n// Return Value:\n//          Number of characters written into the result buffer, including the\n//          trailing terminator.\n// Comments:\n//          This function ignores characters without UCS-2 representations.\n//          It considers all characters on the page, even those that are not\n//          visible when the page has a cropbox. To filter out the characters\n//          outside of the cropbox, use FPDF_GetPageBoundingBox() and\n//          FPDFText_GetCharBox().\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE text_page,\n                                               int start_index,\n                                               int count,\n                                               unsigned short* result);\n\n// Function: FPDFText_CountRects\n//          Counts number of rectangular areas occupied by a segment of text,\n//          and caches the result for subsequent FPDFText_GetRect() calls.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          start_index -   Index for the start character.\n//          count       -   Number of characters, or -1 for all remaining.\n// Return value:\n//          Number of rectangles, 0 if text_page is null, or -1 on bad\n//          start_index.\n// Comments:\n//          This function, along with FPDFText_GetRect can be used by\n//          applications to detect the position on the page for a text segment,\n//          so proper areas can be highlighted. The FPDFText_* functions will\n//          automatically merge small character boxes into bigger one if those\n//          characters are on the same line and use same font settings.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,\n                                                  int start_index,\n                                                  int count);\n\n// Function: FPDFText_GetRect\n//          Get a rectangular area from the result generated by\n//          FPDFText_CountRects.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          rect_index  -   Zero-based index for the rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |text_page| is invalid then return FALSE, and the out\n//          parameters remain unmodified. If |text_page| is valid but\n//          |rect_index| is out of bounds, then return FALSE and set the out\n//          parameters to 0.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Function: FPDFText_GetBoundedText\n//          Extract unicode text within a rectangular boundary on the page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          left        -   Left boundary.\n//          top         -   Top boundary.\n//          right       -   Right boundary.\n//          bottom      -   Bottom boundary.\n//          buffer      -   Caller-allocated buffer to receive UTF-16 values.\n//          buflen      -   Number of UTF-16 values (not bytes) that `buffer`\n//                          is capable of holding.\n// Return Value:\n//          If buffer is NULL or buflen is zero, return number of UTF-16\n//          values (not bytes) of text present within the rectangle, excluding\n//          a terminating NUL. Generally you should pass a buffer at least one\n//          larger than this if you want a terminating NUL, which will be\n//          provided if space is available. Otherwise, return number of UTF-16\n//          values copied into the buffer, including the terminating NUL when\n//          space for it is available.\n// Comment:\n//          If the buffer is too small, as much text as will fit is copied into\n//          it. May return a split surrogate in that case.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,\n                                                      double left,\n                                                      double top,\n                                                      double right,\n                                                      double bottom,\n                                                      unsigned short* buffer,\n                                                      int buflen);\n\n// Flags used by FPDFText_FindStart function.\n//\n// If not set, it will not match case by default.\n#define FPDF_MATCHCASE 0x00000001\n// If not set, it will not match the whole word by default.\n#define FPDF_MATCHWHOLEWORD 0x00000002\n// If not set, it will skip past the current match to look for the next match.\n#define FPDF_CONSECUTIVE 0x00000004\n\n// Function: FPDFText_FindStart\n//          Start a search.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n//          findwhat    -   A unicode match pattern.\n//          flags       -   Option flags.\n//          start_index -   Start from this character. -1 for end of the page.\n// Return Value:\n//          A handle for the search context. FPDFText_FindClose must be called\n//          to release this handle.\n//\nFPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV\nFPDFText_FindStart(FPDF_TEXTPAGE text_page,\n                   FPDF_WIDESTRING findwhat,\n                   unsigned long flags,\n                   int start_index);\n\n// Function: FPDFText_FindNext\n//          Search in the direction from page start to end.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindPrev\n//          Search in the direction from page end to start.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Whether a match is found.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchResultIndex\n//          Get the starting character index of the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Index for the starting character.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_GetSchCount\n//          Get the number of matched characters in the search result.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          Number of matched characters.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle);\n\n// Function: FPDFText_FindClose\n//          Release a search context.\n// Parameters:\n//          handle      -   A search context handle returned by\n//                          FPDFText_FindStart.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle);\n\n// Function: FPDFLink_LoadWebLinks\n//          Prepare information about weblinks in a page.\n// Parameters:\n//          text_page   -   Handle to a text page information structure.\n//                          Returned by FPDFText_LoadPage function.\n// Return Value:\n//          A handle to the page's links information structure, or\n//          NULL if something goes wrong.\n// Comments:\n//          Weblinks are those links implicitly embedded in PDF pages. PDF also\n//          has a type of annotation called \"link\" (FPDFTEXT doesn't deal with\n//          that kind of link). FPDFTEXT weblink feature is useful for\n//          automatically detecting links in the page contents. For example,\n//          things like \"https://www.example.com\" will be detected, so\n//          applications can allow user to click on those characters to activate\n//          the link, even the PDF doesn't come with link annotations.\n//\n//          FPDFLink_CloseWebLinks must be called to release resources.\n//\nFPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV\nFPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page);\n\n// Function: FPDFLink_CountWebLinks\n//          Count number of detected web links.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          Number of detected web links.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page);\n\n// Function: FPDFLink_GetURL\n//          Fetch the URL information for a detected web link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          buffer      -   A unicode buffer for the result.\n//          buflen      -   Number of 16-bit code units (not bytes) for the\n//                          buffer, including an additional terminator.\n// Return Value:\n//          If |buffer| is NULL or |buflen| is zero, return the number of 16-bit\n//          code units (not bytes) needed to buffer the result (an additional\n//          terminator is included in this count).\n//          Otherwise, copy the result into |buffer|, truncating at |buflen| if\n//          the result is too large to fit, and return the number of 16-bit code\n//          units actually copied into the buffer (the additional terminator is\n//          also included in this count).\n//          If |link_index| does not correspond to a valid link, then the result\n//          is an empty string.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,\n                                              int link_index,\n                                              unsigned short* buffer,\n                                              int buflen);\n\n// Function: FPDFLink_CountRects\n//          Count number of rectangular areas for the link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n// Return Value:\n//          Number of rectangular areas for the link.  If |link_index| does\n//          not correspond to a valid link, then 0 is returned.\n//\nFPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,\n                                                  int link_index);\n\n// Function: FPDFLink_GetRect\n//          Fetch the boundaries of a rectangle for a link.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index  -   Zero-based index for the link.\n//          rect_index  -   Zero-based index for a rectangle.\n//          left        -   Pointer to a double value receiving the rectangle\n//                          left boundary.\n//          top         -   Pointer to a double value receiving the rectangle\n//                          top boundary.\n//          right       -   Pointer to a double value receiving the rectangle\n//                          right boundary.\n//          bottom      -   Pointer to a double value receiving the rectangle\n//                          bottom boundary.\n// Return Value:\n//          On success, return TRUE and fill in |left|, |top|, |right|, and\n//          |bottom|. If |link_page| is invalid or if |link_index| does not\n//          correspond to a valid link, then return FALSE, and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,\n                                                     int link_index,\n                                                     int rect_index,\n                                                     double* left,\n                                                     double* top,\n                                                     double* right,\n                                                     double* bottom);\n\n// Experimental API.\n// Function: FPDFLink_GetTextRange\n//          Fetch the start char index and char count for a link.\n// Parameters:\n//          link_page         -   Handle returned by FPDFLink_LoadWebLinks.\n//          link_index        -   Zero-based index for the link.\n//          start_char_index  -   pointer to int receiving the start char index\n//          char_count        -   pointer to int receiving the char count\n// Return Value:\n//          On success, return TRUE and fill in |start_char_index| and\n//          |char_count|. if |link_page| is invalid or if |link_index| does\n//          not correspond to a valid link, then return FALSE and the out\n//          parameters remain unmodified.\n//\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFLink_GetTextRange(FPDF_PAGELINK link_page,\n                      int link_index,\n                      int* start_char_index,\n                      int* char_count);\n\n// Function: FPDFLink_CloseWebLinks\n//          Release resources used by weblink feature.\n// Parameters:\n//          link_page   -   Handle returned by FPDFLink_LoadWebLinks.\n// Return Value:\n//          None.\n//\nFPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TEXT_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_thumbnail.h",
    "content": "// Copyright 2019 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#ifndef PUBLIC_FPDF_THUMBNAIL_H_\n#define PUBLIC_FPDF_THUMBNAIL_H_\n\n#include <stdint.h>\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Experimental API.\n// Gets the decoded data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| less than or equal to the\n// size of the decoded data. Returns the size of the decoded\n// data or 0 if thumbnail DNE. Optional, pass null to just retrieve\n// the size of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the decoded image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetDecodedThumbnailData(FPDF_PAGE page,\n                                 void* buffer,\n                                 unsigned long buflen);\n\n// Experimental API.\n// Gets the raw data from the thumbnail of |page| if it exists.\n// This only modifies |buffer| if |buflen| is less than or equal to\n// the size of the raw data. Returns the size of the raw data or 0\n// if thumbnail DNE. Optional, pass null to just retrieve the size\n// of the buffer needed.\n//\n//   page    - handle to a page.\n//   buffer  - buffer for holding the raw image data.\n//   buflen  - length of the buffer in bytes.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDFPage_GetRawThumbnailData(FPDF_PAGE page,\n                             void* buffer,\n                             unsigned long buflen);\n\n// Experimental API.\n// Returns the thumbnail of |page| as a FPDF_BITMAP. Returns a nullptr\n// if unable to access the thumbnail's stream.\n//\n//   page - handle to a page.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV\nFPDFPage_GetThumbnailAsBitmap(FPDF_PAGE page);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_THUMBNAIL_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdf_transformpage.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n#ifndef PUBLIC_FPDF_TRANSFORMPAGE_H_\n#define PUBLIC_FPDF_TRANSFORMPAGE_H_\n\n// NOLINTNEXTLINE(build/include)\n#include \"fpdfview.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Set \"MediaBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"CropBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"BleedBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page,\n                                                    float left,\n                                                    float bottom,\n                                                    float right,\n                                                    float top);\n\n// Set \"TrimBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page,\n                                                   float left,\n                                                   float bottom,\n                                                   float right,\n                                                   float top);\n\n// Set \"ArtBox\" entry to the page dictionary.\n//\n// page   - Handle to a page.\n// left   - The left of the rectangle.\n// bottom - The bottom of the rectangle.\n// right  - The right of the rectangle.\n// top    - The top of the rectangle.\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page,\n                                                  float left,\n                                                  float bottom,\n                                                  float right,\n                                                  float top);\n\n// Get \"MediaBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"CropBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"BleedBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page,\n                                                         float* left,\n                                                         float* bottom,\n                                                         float* right,\n                                                         float* top);\n\n// Get \"TrimBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page,\n                                                        float* left,\n                                                        float* bottom,\n                                                        float* right,\n                                                        float* top);\n\n// Get \"ArtBox\" entry from the page dictionary.\n//\n// page   - Handle to a page.\n// left   - Pointer to a float value receiving the left of the rectangle.\n// bottom - Pointer to a float value receiving the bottom of the rectangle.\n// right  - Pointer to a float value receiving the right of the rectangle.\n// top    - Pointer to a float value receiving the top of the rectangle.\n//\n// On success, return true and write to the out parameters. Otherwise return\n// false and leave the out parameters unmodified.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page,\n                                                       float* left,\n                                                       float* bottom,\n                                                       float* right,\n                                                       float* top);\n\n// Apply transforms to |page|.\n//\n// If |matrix| is provided it will be applied to transform the page.\n// If |clipRect| is provided it will be used to clip the resulting page.\n// If neither |matrix| or |clipRect| are provided this method returns |false|.\n// Returns |true| if transforms are applied.\n//\n// This function will transform the whole page, and would take effect to all the\n// objects in the page.\n//\n// page        - Page handle.\n// matrix      - Transform matrix.\n// clipRect    - Clipping rectangle.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDFPage_TransFormWithClip(FPDF_PAGE page,\n                           const FS_MATRIX* matrix,\n                           const FS_RECTF* clipRect);\n\n// Transform (scale, rotate, shear, move) the clip path of page object.\n// page_object - Handle to a page object. Returned by\n// FPDFPageObj_NewImageObj().\n//\n// a  - The coefficient \"a\" of the matrix.\n// b  - The coefficient \"b\" of the matrix.\n// c  - The coefficient \"c\" of the matrix.\n// d  - The coefficient \"d\" of the matrix.\n// e  - The coefficient \"e\" of the matrix.\n// f  - The coefficient \"f\" of the matrix.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,\n                              double a,\n                              double b,\n                              double c,\n                              double d,\n                              double e,\n                              double f);\n\n// Experimental API.\n// Get the clip path of the page object.\n//\n//   page object - Handle to a page object. Returned by e.g.\n//                 FPDFPage_GetObject().\n//\n// Returns the handle to the clip path, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_CLIPPATH. Instead, it remains valid until\n// FPDF_ClosePage() is called for the page containing |page_object|.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV\nFPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object);\n\n// Experimental API.\n// Get number of paths inside |clip_path|.\n//\n//   clip_path - handle to a clip_path.\n//\n// Returns the number of objects in |clip_path| or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path);\n\n// Experimental API.\n// Get number of segments inside one path of |clip_path|.\n//\n//   clip_path  - handle to a clip_path.\n//   path_index - index into the array of paths of the clip path.\n//\n// Returns the number of segments or -1 on failure.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index);\n\n// Experimental API.\n// Get segment in one specific path of |clip_path| at index.\n//\n//   clip_path     - handle to a clip_path.\n//   path_index    - the index of a path.\n//   segment_index - the index of a segment.\n//\n// Returns the handle to the segment, or NULL on failure. The caller does not\n// take ownership of the returned FPDF_PATHSEGMENT. Instead, it remains valid\n// until FPDF_ClosePage() is called for the page containing |clip_path|.\nFPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV\nFPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,\n                            int path_index,\n                            int segment_index);\n\n// Create a new clip path, with a rectangle inserted.\n//\n// Caller takes ownership of the returned FPDF_CLIPPATH. It should be freed with\n// FPDF_DestroyClipPath().\n//\n// left   - The left of the clip box.\n// bottom - The bottom of the clip box.\n// right  - The right of the clip box.\n// top    - The top of the clip box.\nFPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left,\n                                                            float bottom,\n                                                            float right,\n                                                            float top);\n\n// Destroy the clip path.\n//\n// clipPath - A handle to the clip path. It will be invalid after this call.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath);\n\n// Clip the page content, the page content that outside the clipping region\n// become invisible.\n//\n// A clip path will be inserted before the page content stream or content array.\n// In this way, the page content will be clipped by this clip path.\n//\n// page        - A page handle.\n// clipPath    - A handle to the clip path. (Does not take ownership.)\nFPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page,\n                                                       FPDF_CLIPPATH clipPath);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDF_TRANSFORMPAGE_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdfview.h",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/include/fpdfview.h.orig",
    "content": "// Copyright 2014 The PDFium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\n\n// This is the main header file for embedders of PDFium. It provides APIs to\n// initialize the library, load documents, and render pages, amongst other\n// things.\n//\n// NOTE: None of the PDFium APIs are thread-safe. They expect to be called\n// from a single thread. Barring that, embedders are required to ensure (via\n// a mutex or similar) that only a single PDFium call can be made at a time.\n//\n// NOTE: External docs refer to this file as \"fpdfview.h\", so do not rename\n// despite lack of consistency with other public files.\n\n#ifndef PUBLIC_FPDFVIEW_H_\n#define PUBLIC_FPDFVIEW_H_\n\n// clang-format off\n\n#include <stddef.h>\n\n#if defined(_WIN32) && !defined(__WINDOWS__)\n#include <windows.h>\n#endif\n\n#ifdef PDF_ENABLE_XFA\n// PDF_USE_XFA is set in confirmation that this version of PDFium can support\n// XFA forms as requested by the PDF_ENABLE_XFA setting.\n#define PDF_USE_XFA\n#endif  // PDF_ENABLE_XFA\n\n// PDF object types\n#define FPDF_OBJECT_UNKNOWN 0\n#define FPDF_OBJECT_BOOLEAN 1\n#define FPDF_OBJECT_NUMBER 2\n#define FPDF_OBJECT_STRING 3\n#define FPDF_OBJECT_NAME 4\n#define FPDF_OBJECT_ARRAY 5\n#define FPDF_OBJECT_DICTIONARY 6\n#define FPDF_OBJECT_STREAM 7\n#define FPDF_OBJECT_NULLOBJ 8\n#define FPDF_OBJECT_REFERENCE 9\n\n// PDF text rendering modes\ntypedef enum {\n  FPDF_TEXTRENDERMODE_UNKNOWN = -1,\n  FPDF_TEXTRENDERMODE_FILL = 0,\n  FPDF_TEXTRENDERMODE_STROKE = 1,\n  FPDF_TEXTRENDERMODE_FILL_STROKE = 2,\n  FPDF_TEXTRENDERMODE_INVISIBLE = 3,\n  FPDF_TEXTRENDERMODE_FILL_CLIP = 4,\n  FPDF_TEXTRENDERMODE_STROKE_CLIP = 5,\n  FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP = 6,\n  FPDF_TEXTRENDERMODE_CLIP = 7,\n  FPDF_TEXTRENDERMODE_LAST = FPDF_TEXTRENDERMODE_CLIP,\n} FPDF_TEXT_RENDERMODE;\n\n// PDF types - use incomplete types (never completed) to force API type safety.\ntypedef struct fpdf_action_t__* FPDF_ACTION;\ntypedef struct fpdf_annotation_t__* FPDF_ANNOTATION;\ntypedef struct fpdf_attachment_t__* FPDF_ATTACHMENT;\ntypedef struct fpdf_avail_t__* FPDF_AVAIL;\ntypedef struct fpdf_bitmap_t__* FPDF_BITMAP;\ntypedef struct fpdf_bookmark_t__* FPDF_BOOKMARK;\ntypedef struct fpdf_clippath_t__* FPDF_CLIPPATH;\ntypedef struct fpdf_dest_t__* FPDF_DEST;\ntypedef struct fpdf_document_t__* FPDF_DOCUMENT;\ntypedef struct fpdf_font_t__* FPDF_FONT;\ntypedef struct fpdf_form_handle_t__* FPDF_FORMHANDLE;\ntypedef const struct fpdf_glyphpath_t__* FPDF_GLYPHPATH;\ntypedef struct fpdf_javascript_action_t* FPDF_JAVASCRIPT_ACTION;\ntypedef struct fpdf_link_t__* FPDF_LINK;\ntypedef struct fpdf_page_t__* FPDF_PAGE;\ntypedef struct fpdf_pagelink_t__* FPDF_PAGELINK;\ntypedef struct fpdf_pageobject_t__* FPDF_PAGEOBJECT;  // (text, path, etc.)\ntypedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;\ntypedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;\ntypedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;\ntypedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;\ntypedef const struct fpdf_signature_t__* FPDF_SIGNATURE;\ntypedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.\ntypedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;\ntypedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;\ntypedef const struct fpdf_structelement_attr_value_t__*\nFPDF_STRUCTELEMENT_ATTR_VALUE;\ntypedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;\ntypedef struct fpdf_textpage_t__* FPDF_TEXTPAGE;\ntypedef struct fpdf_widget_t__* FPDF_WIDGET;\ntypedef struct fpdf_xobject_t__* FPDF_XOBJECT;\n\n// Basic data types\ntypedef int FPDF_BOOL;\ntypedef int FPDF_RESULT;\ntypedef unsigned long FPDF_DWORD;\ntypedef float FS_FLOAT;\n\n// Duplex types\ntypedef enum _FPDF_DUPLEXTYPE_ {\n  DuplexUndefined = 0,\n  Simplex,\n  DuplexFlipShortEdge,\n  DuplexFlipLongEdge\n} FPDF_DUPLEXTYPE;\n\n// String types\ntypedef unsigned short FPDF_WCHAR;\n\n// The public PDFium API uses three types of strings: byte string, wide string\n// (UTF-16LE encoded), and platform dependent string.\n\n// Public PDFium API type for byte strings.\ntypedef const char* FPDF_BYTESTRING;\n\n// The public PDFium API always uses UTF-16LE encoded wide strings, each\n// character uses 2 bytes (except surrogation), with the low byte first.\ntypedef const FPDF_WCHAR* FPDF_WIDESTRING;\n\n// Structure for persisting a string beyond the duration of a callback.\n// Note: although represented as a char*, string may be interpreted as\n// a UTF-16LE formated string. Used only by XFA callbacks.\ntypedef struct FPDF_BSTR_ {\n  char* str;  // String buffer, manipulate only with FPDF_BStr_* methods.\n  int len;    // Length of the string, in bytes.\n} FPDF_BSTR;\n\n// For Windows programmers: In most cases it's OK to treat FPDF_WIDESTRING as a\n// Windows unicode string, however, special care needs to be taken if you\n// expect to process Unicode larger than 0xffff.\n//\n// For Linux/Unix programmers: most compiler/library environments use 4 bytes\n// for a Unicode character, and you have to convert between FPDF_WIDESTRING and\n// system wide string by yourself.\ntypedef const char* FPDF_STRING;\n\n// Matrix for transformation, in the form [a b c d e f], equivalent to:\n// | a  b  0 |\n// | c  d  0 |\n// | e  f  1 |\n//\n// Translation is performed with [1 0 0 1 tx ty].\n// Scaling is performed with [sx 0 0 sy 0 0].\n// See PDF Reference 1.7, 4.2.2 Common Transformations for more.\ntypedef struct _FS_MATRIX_ {\n  float a;\n  float b;\n  float c;\n  float d;\n  float e;\n  float f;\n} FS_MATRIX;\n\n// Rectangle area(float) in device or page coordinate system.\ntypedef struct _FS_RECTF_ {\n  // The x-coordinate of the left-top corner.\n  float left;\n  // The y-coordinate of the left-top corner.\n  float top;\n  // The x-coordinate of the right-bottom corner.\n  float right;\n  // The y-coordinate of the right-bottom corner.\n  float bottom;\n} * FS_LPRECTF, FS_RECTF;\n\n// Const Pointer to FS_RECTF structure.\ntypedef const FS_RECTF* FS_LPCRECTF;\n\n// Rectangle size. Coordinate system agnostic.\ntypedef struct FS_SIZEF_ {\n  float width;\n  float height;\n} * FS_LPSIZEF, FS_SIZEF;\n\n// Const Pointer to FS_SIZEF structure.\ntypedef const FS_SIZEF* FS_LPCSIZEF;\n\n// 2D Point. Coordinate system agnostic.\ntypedef struct FS_POINTF_ {\n  float x;\n  float y;\n} * FS_LPPOINTF, FS_POINTF;\n\n// Const Pointer to FS_POINTF structure.\ntypedef const FS_POINTF* FS_LPCPOINTF;\n\ntypedef struct _FS_QUADPOINTSF {\n  FS_FLOAT x1;\n  FS_FLOAT y1;\n  FS_FLOAT x2;\n  FS_FLOAT y2;\n  FS_FLOAT x3;\n  FS_FLOAT y3;\n  FS_FLOAT x4;\n  FS_FLOAT y4;\n} FS_QUADPOINTSF;\n\n// Annotation enums.\ntypedef int FPDF_ANNOTATION_SUBTYPE;\ntypedef int FPDF_ANNOT_APPEARANCEMODE;\n\n// Dictionary value types.\ntypedef int FPDF_OBJECT_TYPE;\n\n#if defined(COMPONENT_BUILD)\n// FPDF_EXPORT should be consistent with |export| in the pdfium_fuzzer\n// template in testing/fuzzers/BUILD.gn.\n#if defined(WIN32)\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __declspec(dllexport)\n#else\n#define FPDF_EXPORT __declspec(dllimport)\n#endif  // defined(FPDF_IMPLEMENTATION)\n#else\n#if defined(FPDF_IMPLEMENTATION)\n#define FPDF_EXPORT __attribute__((visibility(\"default\")))\n#else\n#define FPDF_EXPORT\n#endif  // defined(FPDF_IMPLEMENTATION)\n#endif  // defined(WIN32)\n#else\n#define FPDF_EXPORT\n#endif  // defined(COMPONENT_BUILD)\n\n#if defined(WIN32) && defined(FPDFSDK_EXPORTS)\n#define FPDF_CALLCONV __stdcall\n#else\n#define FPDF_CALLCONV\n#endif\n\n// Exported Functions\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// PDF renderer types - Experimental.\n// Selection of 2D graphics library to use for rendering to FPDF_BITMAPs.\ntypedef enum {\n  // Anti-Grain Geometry - https://sourceforge.net/projects/agg/\n  FPDF_RENDERERTYPE_AGG = 0,\n  // Skia - https://skia.org/\n  FPDF_RENDERERTYPE_SKIA = 1,\n} FPDF_RENDERER_TYPE;\n\n// PDF font library types - Experimental.\n// Selection of font backend library to use.\ntypedef enum {\n  // FreeType - https://freetype.org/\n  FPDF_FONTBACKENDTYPE_FREETYPE = 0,\n  // Fontations - https://github.com/googlefonts/fontations/\n  FPDF_FONTBACKENDTYPE_FONTATIONS = 1,\n} FPDF_FONT_BACKEND_TYPE;\n\n// Process-wide options for initializing the library.\ntypedef struct FPDF_LIBRARY_CONFIG_ {\n  // Version number of the interface. Currently must be 2.\n  // Support for version 1 will be deprecated in the future.\n  int version;\n\n  // Array of paths to scan in place of the defaults when using built-in\n  // FXGE font loading code. The array is terminated by a NULL pointer.\n  // The Array may be NULL itself to use the default paths. May be ignored\n  // entirely depending upon the platform.\n  const char** m_pUserFontPaths;\n\n  // Version 2.\n\n  // Pointer to the v8::Isolate to use, or NULL to force PDFium to create one.\n  void* m_pIsolate;\n\n  // The embedder data slot to use in the v8::Isolate to store PDFium's\n  // per-isolate data. The value needs to be in the range\n  // [0, |v8::Internals::kNumIsolateDataLots|). Note that 0 is fine for most\n  // embedders.\n  unsigned int m_v8EmbedderSlot;\n\n  // Version 3 - Experimental.\n\n  // Pointer to the V8::Platform to use.\n  void* m_pPlatform;\n\n  // Version 4 - Experimental.\n\n  // Explicit specification of 2D graphics rendering library to use.\n  // |m_RendererType| must be a valid value for |FPDF_LIBRARY_CONFIG| versions\n  // of this level or higher, or else the initialization will fail with an\n  // immediate crash.\n  // Note that use of a specified |FPDF_RENDERER_TYPE| value for which the\n  // corresponding 2D graphics rendering library is not included in the build\n  // will similarly fail with an immediate crash.\n  FPDF_RENDERER_TYPE m_RendererType;\n\n  // Version 5 - Experimental.\n\n  // Explicit specification of font library to use when |m_RendererType| is set\n  // to |FPDF_RENDERERTYPE_SKIA|.\n  // |m_FontLibraryType| must be a valid value for |FPDF_LIBRARY_CONFIG|\n  // versions of this level or higher, or else the initialization will fail with\n  // an immediate crash.\n  // Note that use of a specified |FPDF_FONT_BACKEND_TYPE| value for which the\n  // corresponding font library is not included in the build will similarly fail\n  // with an immediate crash.\n  FPDF_FONT_BACKEND_TYPE m_FontLibraryType;\n} FPDF_LIBRARY_CONFIG;\n\n// Function: FPDF_InitLibraryWithConfig\n//          Initialize the PDFium library and allocate global resources for it.\n// Parameters:\n//          config - configuration information as above.\n// Return value:\n//          None.\n// Comments:\n//          You have to call this function before you can call any PDF\n//          processing functions.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG* config);\n\n// Function: FPDF_InitLibrary\n//          Initialize the PDFium library (alternative form).\n// Parameters:\n//          None\n// Return value:\n//          None.\n// Comments:\n//          Convenience function to call FPDF_InitLibraryWithConfig() with a\n//          default configuration for backwards compatibility purposes. New\n//          code should call FPDF_InitLibraryWithConfig() instead. This will\n//          be deprecated in the future.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibrary();\n\n// Function: FPDF_DestroyLibrary\n//          Release global resources allocated to the PDFium library by\n//          FPDF_InitLibrary() or FPDF_InitLibraryWithConfig().\n// Parameters:\n//          None.\n// Return value:\n//          None.\n// Comments:\n//          After this function is called, you must not call any PDF\n//          processing functions.\n//\n//          Calling this function does not automatically close other\n//          objects. It is recommended to close other objects before\n//          closing the library with this function.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary();\n\n// Policy for accessing the local machine time.\n#define FPDF_POLICY_MACHINETIME_ACCESS 0\n\n// Function: FPDF_SetSandBoxPolicy\n//          Set the policy for the sandbox environment.\n// Parameters:\n//          policy -   The specified policy for setting, for example:\n//                     FPDF_POLICY_MACHINETIME_ACCESS.\n//          enable -   True to enable, false to disable the policy.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_SetSandBoxPolicy(FPDF_DWORD policy,\n                                                     FPDF_BOOL enable);\n\n#if defined(_WIN32)\n// Experimental API.\n// Function: FPDF_SetPrintMode\n//          Set printing mode when printing on Windows.\n// Parameters:\n//          mode - FPDF_PRINTMODE_EMF to output EMF (default)\n//                 FPDF_PRINTMODE_TEXTONLY to output text only (for charstream\n//                 devices)\n//                 FPDF_PRINTMODE_POSTSCRIPT2 to output level 2 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3 to output level 3 PostScript into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT2_PASSTHROUGH to output level 2\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_PASSTHROUGH to output level 3\n//                 PostScript via ExtEscape() in PASSTHROUGH mode.\n//                 FPDF_PRINTMODE_EMF_IMAGE_MASKS to output EMF, with more\n//                 efficient processing of documents containing image masks.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42 to output level 3\n//                 PostScript with embedded Type 42 fonts, when applicable, into\n//                 EMF as a series of GDI comments.\n//                 FPDF_PRINTMODE_POSTSCRIPT3_TYPE42_PASSTHROUGH to output level\n//                 3 PostScript with embedded Type 42 fonts, when applicable,\n//                 via ExtEscape() in PASSTHROUGH mode.\n// Return value:\n//          True if successful, false if unsuccessful (typically invalid input).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_SetPrintMode(int mode);\n#endif  // defined(_WIN32)\n\n// Function: FPDF_LoadDocument\n//          Open and load a PDF document.\n// Parameters:\n//          file_path -  Path to the PDF file (including extension).\n//          password  -  A string used as the password for the PDF file.\n//                       If no password is needed, empty or NULL can be used.\n//                       See comments below regarding the encoding.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          Loaded document can be closed by FPDF_CloseDocument().\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          The encoding for |file_path| is UTF-8.\n//\n//          The encoding for |password| can be either UTF-8 or Latin-1. PDFs,\n//          depending on the security handler revision, will only accept one or\n//          the other encoding. If |password|'s encoding and the PDF's expected\n//          encoding do not match, FPDF_LoadDocument() will automatically\n//          convert |password| to the other encoding.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadDocument(FPDF_STRING file_path, FPDF_BYTESTRING password);\n\n// Function: FPDF_LoadMemDocument\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument(const void* data_buf, int size, FPDF_BYTESTRING password);\n\n// Experimental API.\n// Function: FPDF_LoadMemDocument64\n//          Open and load a PDF document from memory.\n// Parameters:\n//          data_buf    -   Pointer to a buffer containing the PDF document.\n//          size        -   Number of bytes in the PDF document.\n//          password    -   A string used as the password for the PDF file.\n//                          If no password is needed, empty or NULL can be used.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The memory buffer must remain valid when the document is open.\n//          The loaded document can be closed by FPDF_CloseDocument.\n//          If this function fails, you can use FPDF_GetLastError() to retrieve\n//          the reason why it failed.\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadMemDocument64(const void* data_buf,\n                       size_t size,\n                       FPDF_BYTESTRING password);\n\n// Structure for custom file access.\ntypedef struct {\n  // File length, in bytes.\n  unsigned long m_FileLen;\n\n  // A function pointer for getting a block of data from a specific position.\n  // Position is specified by byte offset from the beginning of the file.\n  // The pointer to the buffer is never NULL and the size is never 0.\n  // The position and size will never go out of range of the file length.\n  // It may be possible for PDFium to call this function multiple times for\n  // the same position.\n  // Return value: should be non-zero if successful, zero for error.\n  int (*m_GetBlock)(void* param,\n                    unsigned long position,\n                    unsigned char* pBuf,\n                    unsigned long size);\n\n  // A custom pointer for all implementation specific data.  This pointer will\n  // be used as the first parameter to the m_GetBlock callback.\n  void* m_Param;\n} FPDF_FILEACCESS;\n\n// Structure for file reading or writing (I/O).\n//\n// Note: This is a handler and should be implemented by callers,\n// and is only used from XFA.\ntypedef struct FPDF_FILEHANDLER_ {\n  // User-defined data.\n  // Note: Callers can use this field to track controls.\n  void* clientData;\n\n  // Callback function to release the current file stream object.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       None.\n  void (*Release)(void* clientData);\n\n  // Callback function to retrieve the current file stream size.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       Size of file stream.\n  FPDF_DWORD (*GetSize)(void* clientData);\n\n  // Callback function to read data from the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates reading position.\n  //       buffer       -  Memory buffer to store data which are read from\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be read from file stream,\n  //                       in bytes. The buffer indicated by |buffer| must be\n  //                       large enough to store specified data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*ReadBlock)(void* clientData,\n                           FPDF_DWORD offset,\n                           void* buffer,\n                           FPDF_DWORD size);\n\n  // Callback function to write data into the current file stream.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       offset       -  Offset position starts from the beginning of file\n  //                       stream. This parameter indicates writing position.\n  //       buffer       -  Memory buffer contains data which is written into\n  //                       file stream. This parameter should not be NULL.\n  //       size         -  Size of data which should be written into file\n  //                       stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*WriteBlock)(void* clientData,\n                            FPDF_DWORD offset,\n                            const void* buffer,\n                            FPDF_DWORD size);\n  // Callback function to flush all internal accessing buffers.\n  //\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Flush)(void* clientData);\n\n  // Callback function to change file size.\n  //\n  // Description:\n  //       This function is called under writing mode usually. Implementer\n  //       can determine whether to realize it based on application requests.\n  // Parameters:\n  //       clientData   -  Pointer to user-defined data.\n  //       size         -  New size of file stream, in bytes.\n  // Returns:\n  //       0 for success, other value for failure.\n  FPDF_RESULT (*Truncate)(void* clientData, FPDF_DWORD size);\n} FPDF_FILEHANDLER;\n\n// Function: FPDF_LoadCustomDocument\n//          Load PDF document from a custom access descriptor.\n// Parameters:\n//          pFileAccess -   A structure for accessing the file.\n//          password    -   Optional password for decrypting the PDF file.\n// Return value:\n//          A handle to the loaded document, or NULL on failure.\n// Comments:\n//          The application must keep the file resources |pFileAccess| points to\n//          valid until the returned FPDF_DOCUMENT is closed. |pFileAccess|\n//          itself does not need to outlive the FPDF_DOCUMENT.\n//\n//          The loaded document can be closed with FPDF_CloseDocument().\n//\n//          See the comments for FPDF_LoadDocument() regarding the encoding for\n//          |password|.\n// Notes:\n//          If PDFium is built with the XFA module, the application should call\n//          FPDF_LoadXFA() function after the PDF document loaded to support XFA\n//          fields defined in the fpdfformfill.h file.\nFPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV\nFPDF_LoadCustomDocument(FPDF_FILEACCESS* pFileAccess, FPDF_BYTESTRING password);\n\n// Function: FPDF_GetFileVersion\n//          Get the file version of the given PDF document.\n// Parameters:\n//          doc         -   Handle to a document.\n//          fileVersion -   The PDF file version. File version: 14 for 1.4, 15\n//                          for 1.5, ...\n// Return value:\n//          True if succeeds, false otherwise.\n// Comments:\n//          If the document was created by FPDF_CreateNewDocument,\n//          then this function will always fail.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetFileVersion(FPDF_DOCUMENT doc,\n                                                        int* fileVersion);\n\n#define FPDF_ERR_SUCCESS 0    // No error.\n#define FPDF_ERR_UNKNOWN 1    // Unknown error.\n#define FPDF_ERR_FILE 2       // File not found or could not be opened.\n#define FPDF_ERR_FORMAT 3     // File not in PDF format or corrupted.\n#define FPDF_ERR_PASSWORD 4   // Password required or incorrect password.\n#define FPDF_ERR_SECURITY 5   // Unsupported security scheme.\n#define FPDF_ERR_PAGE 6       // Page not found or content error.\n#ifdef PDF_ENABLE_XFA\n#define FPDF_ERR_XFALOAD 7    // Load XFA error.\n#define FPDF_ERR_XFALAYOUT 8  // Layout XFA error.\n#endif  // PDF_ENABLE_XFA\n\n// Function: FPDF_GetLastError\n//          Get last error code when a function fails.\n// Parameters:\n//          None.\n// Return value:\n//          A 32-bit integer indicating error code as defined above.\n// Comments:\n//          If the previous SDK call succeeded, the return value of this\n//          function is not defined. This function only works in conjunction\n//          with APIs that mention FPDF_GetLastError() in their documentation.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError();\n\n// Experimental API.\n// Function: FPDF_DocumentHasValidCrossReferenceTable\n//          Whether the document's cross reference table is valid or not.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          True if the PDF parser did not encounter problems parsing the cross\n//          reference table. False if the parser could not parse the cross\n//          reference table and the table had to be rebuild from other data\n//          within the document.\n// Comments:\n//          The return value can change over time as the PDF parser evolves.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_DocumentHasValidCrossReferenceTable(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetTrailerEnds\n//          Get the byte offsets of trailer ends.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          buffer      -   The address of a buffer that receives the\n//                          byte offsets.\n//          length      -   The size, in ints, of |buffer|.\n// Return value:\n//          Returns the number of ints in the buffer on success, 0 on error.\n//\n// |buffer| is an array of integers that describes the exact byte offsets of the\n// trailer ends in the document. If |length| is less than the returned length,\n// or |document| or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetTrailerEnds(FPDF_DOCUMENT document,\n                    unsigned int* buffer,\n                    unsigned long length);\n\n// Function: FPDF_GetDocPermissions\n//          Get file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected or was unlocked by the owner, 0xffffffff will be returned.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetDocUserPermissions\n//          Get user file permission flags of the document.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          A 32-bit integer indicating permission flags. Please refer to the\n//          PDF Reference for detailed descriptions. If the document is not\n//          protected, 0xffffffff will be returned. Always returns user\n//          permissions, even if the document was unlocked by the owner.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_GetDocUserPermissions(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetSecurityHandlerRevision\n//          Get the revision for the security handler.\n// Parameters:\n//          document    -   Handle to a document. Returned by FPDF_LoadDocument.\n// Return value:\n//          The security handler revision number. Please refer to the PDF\n//          Reference for a detailed description. If the document is not\n//          protected, -1 will be returned.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_GetSecurityHandlerRevision(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetPageCount\n//          Get total number of pages in the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n// Return value:\n//          Total number of pages in the document.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageCount(FPDF_DOCUMENT document);\n\n// Function: FPDF_LoadPage\n//          Load a page inside the document.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument\n//          page_index  -   Index number of the page. 0 for the first page.\n// Return value:\n//          A handle to the loaded page, or NULL if page load fails.\n// Comments:\n//          The loaded page can be rendered to devices using FPDF_RenderPage.\n//          The loaded page can be closed using FPDF_ClosePage.\nFPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document,\n                                                  int page_index);\n\n// Experimental API\n// Function: FPDF_GetPageWidthF\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageWidth\n//          Get page width.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page width (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm).\n// Note:\n//          Prefer FPDF_GetPageWidthF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageWidth(FPDF_PAGE page);\n\n// Experimental API\n// Function: FPDF_GetPageHeightF\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage().\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page);\n\n// Function: FPDF_GetPageHeight\n//          Get page height.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n// Return value:\n//          Page height (excluding non-displayable area) measured in points.\n//          One point is 1/72 inch (around 0.3528 mm)\n// Note:\n//          Prefer FPDF_GetPageHeightF() above. This will be deprecated in the\n//          future.\n// Comments:\n//          Changing the rotation of |page| affects the return value.\nFPDF_EXPORT double FPDF_CALLCONV FPDF_GetPageHeight(FPDF_PAGE page);\n\n// Experimental API.\n// Function: FPDF_GetPageBoundingBox\n//          Get the bounding box of the page. This is the intersection between\n//          its media box and its crop box.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          rect        -   Pointer to a rect to receive the page bounding box.\n//                          On an error, |rect| won't be filled.\n// Return value:\n//          True for success.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetPageBoundingBox(FPDF_PAGE page,\n                                                            FS_RECTF* rect);\n\n// Experimental API.\n// Function: FPDF_GetPageSizeByIndexF\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument().\n//          page_index  -   Page index, zero for the first page.\n//          size        -   Pointer to a FS_SIZEF to receive the page size.\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_GetPageSizeByIndexF(FPDF_DOCUMENT document,\n                         int page_index,\n                         FS_SIZEF* size);\n\n// Function: FPDF_GetPageSizeByIndex\n//          Get the size of the page at the given index.\n// Parameters:\n//          document    -   Handle to document. Returned by FPDF_LoadDocument.\n//          page_index  -   Page index, zero for the first page.\n//          width       -   Pointer to a double to receive the page width\n//                          (in points).\n//          height      -   Pointer to a double to receive the page height\n//                          (in points).\n// Return value:\n//          Non-zero for success. 0 for error (document or page not found).\n// Note:\n//          Prefer FPDF_GetPageSizeByIndexF() above. This will be deprecated in\n//          the future.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetPageSizeByIndex(FPDF_DOCUMENT document,\n                                                      int page_index,\n                                                      double* width,\n                                                      double* height);\n\n// Page rendering flags. They can be combined with bit-wise OR.\n//\n// Set if annotations are to be rendered.\n#define FPDF_ANNOT 0x01\n// Set if using text rendering optimized for LCD display. This flag will only\n// take effect if anti-aliasing is enabled for text.\n#define FPDF_LCD_TEXT 0x02\n// Don't use the native text output available on some platforms\n#define FPDF_NO_NATIVETEXT 0x04\n// Grayscale output.\n#define FPDF_GRAYSCALE 0x08\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_DEBUG_INFO 0x80\n// Obsolete, has no effect, retained for compatibility.\n#define FPDF_NO_CATCH 0x100\n// Limit image cache size.\n#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200\n// Always use halftone for image stretching.\n#define FPDF_RENDER_FORCEHALFTONE 0x400\n// Render for printing.\n#define FPDF_PRINTING 0x800\n// Set to disable anti-aliasing on text. This flag will also disable LCD\n// optimization for text rendering.\n#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000\n// Set to disable anti-aliasing on images.\n#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000\n// Set to disable anti-aliasing on paths.\n#define FPDF_RENDER_NO_SMOOTHPATH 0x4000\n// Set whether to render in a reverse Byte order, this flag is only used when\n// rendering to a bitmap.\n#define FPDF_REVERSE_BYTE_ORDER 0x10\n// Set whether fill paths need to be stroked. This flag is only used when\n// FPDF_COLORSCHEME is passed in, since with a single fill color for paths the\n// boundaries of adjacent fill paths are less visible.\n#define FPDF_CONVERT_FILL_TO_STROKE 0x20\n\n// Struct for color scheme.\n// Each should be a 32-bit value specifying the color, in 8888 ARGB format.\ntypedef struct FPDF_COLORSCHEME_ {\n  FPDF_DWORD path_fill_color;\n  FPDF_DWORD path_stroke_color;\n  FPDF_DWORD text_fill_color;\n  FPDF_DWORD text_stroke_color;\n} FPDF_COLORSCHEME;\n\n#ifdef _WIN32\n// Function: FPDF_RenderPage\n//          Render contents of a page to a device (screen, bitmap, or printer).\n//          This function is only supported on Windows.\n// Parameters:\n//          dc          -   Handle to the device context.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of flags\n//                          defined above.\n// Return value:\n//          Returns true if the page is rendered successfully, false otherwise.\n\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_RenderPage(HDC dc,\n                                                    FPDF_PAGE page,\n                                                    int start_x,\n                                                    int start_y,\n                                                    int size_x,\n                                                    int size_y,\n                                                    int rotate,\n                                                    int flags);\n#endif\n\n// Function: FPDF_RenderPageBitmap\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved from an image\n//                          object by FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage\n//          start_x     -   Left pixel position of the display area in\n//                          bitmap coordinates.\n//          start_y     -   Top pixel position of the display area in bitmap\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,\n                                                     FPDF_PAGE page,\n                                                     int start_x,\n                                                     int start_y,\n                                                     int size_x,\n                                                     int size_y,\n                                                     int rotate,\n                                                     int flags);\n\n// Function: FPDF_RenderPageBitmapWithMatrix\n//          Render contents of a page to a device independent bitmap.\n// Parameters:\n//          bitmap      -   Handle to the device independent bitmap (as the\n//                          output buffer). The bitmap handle can be created\n//                          by FPDFBitmap_Create or retrieved by\n//                          FPDFImageObj_GetBitmap.\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          matrix      -   The transform matrix, which must be invertible.\n//                          See PDF Reference 1.7, 4.2.2 Common Transformations.\n//          clipping    -   The rect to clip to in device coords.\n//          flags       -   0 for normal display, or combination of the Page\n//                          Rendering flags defined above. With the FPDF_ANNOT\n//                          flag, it renders all annotations that do not require\n//                          user-interaction, which are all annotations except\n//                          widget and popup annotations.\n// Return value:\n//          None. Note that behavior is undefined if det of |matrix| is 0.\nFPDF_EXPORT void FPDF_CALLCONV\nFPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,\n                                FPDF_PAGE page,\n                                const FS_MATRIX* matrix,\n                                const FS_RECTF* clipping,\n                                int flags);\n\n#if defined(PDF_USE_SKIA)\n// Experimental API.\n// Function: FPDF_RenderPageSkia\n//          Render contents of a page to a Skia SkCanvas.\n// Parameters:\n//          canvas      -   SkCanvas to render to.\n//          page        -   Handle to the page.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,\n                                                   FPDF_PAGE page,\n                                                   int size_x,\n                                                   int size_y);\n#endif\n\n// Function: FPDF_ClosePage\n//          Close a loaded PDF page.\n// Parameters:\n//          page        -   Handle to the loaded page.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_ClosePage(FPDF_PAGE page);\n\n// Function: FPDF_CloseDocument\n//          Close a loaded PDF document.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT void FPDF_CALLCONV FPDF_CloseDocument(FPDF_DOCUMENT document);\n\n// Function: FPDF_DeviceToPage\n//          Convert the screen coordinates of a point to page coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          device_x    -   X value in device coordinates to be converted.\n//          device_y    -   Y value in device coordinates to be converted.\n//          page_x      -   A pointer to a double receiving the converted X\n//                          value in page coordinates.\n//          page_y      -   A pointer to a double receiving the converted Y\n//                          value in page coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |page_x| and |page_y|\n//          successfully receives the converted coordinates.\n// Comments:\n//          The page coordinate system has its origin at the left-bottom corner\n//          of the page, with the X-axis on the bottom going to the right, and\n//          the Y-axis on the left side going up.\n//\n//          NOTE: this coordinate system can be altered when you zoom, scroll,\n//          or rotate a page, however, a point on the page should always have\n//          the same coordinate values in the page coordinate system.\n//\n//          The device coordinate system is device dependent. For screen device,\n//          its origin is at the left-top corner of the window. However this\n//          origin can be altered by the Windows coordinate transformation\n//          utilities.\n//\n//          You must make sure the start_x, start_y, size_x, size_y\n//          and rotate parameters have exactly same values as you used in\n//          the FPDF_RenderPage() function call.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_DeviceToPage(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      int device_x,\n                                                      int device_y,\n                                                      double* page_x,\n                                                      double* page_y);\n\n// Function: FPDF_PageToDevice\n//          Convert the page coordinates of a point to screen coordinates.\n// Parameters:\n//          page        -   Handle to the page. Returned by FPDF_LoadPage.\n//          start_x     -   Left pixel position of the display area in\n//                          device coordinates.\n//          start_y     -   Top pixel position of the display area in device\n//                          coordinates.\n//          size_x      -   Horizontal size (in pixels) for displaying the page.\n//          size_y      -   Vertical size (in pixels) for displaying the page.\n//          rotate      -   Page orientation:\n//                            0 (normal)\n//                            1 (rotated 90 degrees clockwise)\n//                            2 (rotated 180 degrees)\n//                            3 (rotated 90 degrees counter-clockwise)\n//          page_x      -   X value in page coordinates.\n//          page_y      -   Y value in page coordinate.\n//          device_x    -   A pointer to an integer receiving the result X\n//                          value in device coordinates.\n//          device_y    -   A pointer to an integer receiving the result Y\n//                          value in device coordinates.\n// Return value:\n//          Returns true if the conversion succeeds, and |device_x| and\n//          |device_y| successfully receives the converted coordinates.\n// Comments:\n//          See comments for FPDF_DeviceToPage().\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_PageToDevice(FPDF_PAGE page,\n                                                      int start_x,\n                                                      int start_y,\n                                                      int size_x,\n                                                      int size_y,\n                                                      int rotate,\n                                                      double page_x,\n                                                      double page_y,\n                                                      int* device_x,\n                                                      int* device_y);\n\n// Function: FPDFBitmap_Create\n//          Create a device independent bitmap (FXDIB).\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          alpha       -   A flag indicating whether the alpha channel is used.\n//                          Non-zero for using alpha, zero for not using.\n// Return value:\n//          The created bitmap handle, or NULL if a parameter error or out of\n//          memory.\n// Comments:\n//          The bitmap always uses 4 bytes per pixel. The first byte is always\n//          double word aligned.\n//\n//          The byte order is BGRx (the last byte unused if no alpha channel) or\n//          BGRA.\n//\n//          The pixels in a horizontal line are stored side by side, with the\n//          left most pixel stored first (with lower memory address).\n//          Each line uses width * 4 bytes.\n//\n//          Lines are stored one after another, with the top most line stored\n//          first. There is no gap between adjacent lines.\n//\n//          This function allocates enough memory for holding all pixels in the\n//          bitmap, but it doesn't initialize the buffer. Applications can use\n//          FPDFBitmap_FillRect() to fill the bitmap using any color. If the OS\n//          allows it, this function can allocate up to 4 GB of memory.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_Create(int width,\n                                                        int height,\n                                                        int alpha);\n\n// More DIB formats\n// Unknown or unsupported format.\n// All of the colors are listed in order of LSB to MSB.\n#define FPDFBitmap_Unknown 0\n// Gray scale bitmap, one byte per pixel.\n#define FPDFBitmap_Gray 1\n// 3 bytes per pixel, byte order: blue, green, red.\n#define FPDFBitmap_BGR 2\n// 4 bytes per pixel, byte order: blue, green, red, unused.\n#define FPDFBitmap_BGRx 3\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are independent of alpha.\n#define FPDFBitmap_BGRA 4\n// 4 bytes per pixel, byte order: blue, green, red, alpha.\n// Pixel components are premultiplied by alpha.\n// Note that this is experimental and only supported when rendering with\n// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|.\n#define FPDFBitmap_BGRA_Premul 5\n\n// Function: FPDFBitmap_CreateEx\n//          Create a device independent bitmap (FXDIB)\n// Parameters:\n//          width       -   The number of pixels in width for the bitmap.\n//                          Must be greater than 0.\n//          height      -   The number of pixels in height for the bitmap.\n//                          Must be greater than 0.\n//          format      -   A number indicating for bitmap format, as defined\n//                          above.\n//          first_scan  -   A pointer to the first byte of the first line if\n//                          using an external buffer. If this parameter is NULL,\n//                          then a new buffer will be created.\n//          stride      -   Number of bytes for each scan line. The value must\n//                          be 0 or greater. When the value is 0,\n//                          FPDFBitmap_CreateEx() will automatically calculate\n//                          the appropriate value using |width| and |format|.\n//                          When using an external buffer, it is recommended for\n//                          the caller to pass in the value.\n//                          When not using an external buffer, it is recommended\n//                          for the caller to pass in 0.\n// Return value:\n//          The bitmap handle, or NULL if parameter error or out of memory.\n// Comments:\n//          Similar to FPDFBitmap_Create function, but allows for more formats\n//          and an external buffer is supported. The bitmap created by this\n//          function can be used in any place that a FPDF_BITMAP handle is\n//          required.\n//\n//          If an external buffer is used, then the caller should destroy the\n//          buffer. FPDFBitmap_Destroy() will not destroy the buffer.\n//\n//          It is recommended to use FPDFBitmap_GetStride() to get the stride\n//          value.\nFPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV FPDFBitmap_CreateEx(int width,\n                                                          int height,\n                                                          int format,\n                                                          void* first_scan,\n                                                          int stride);\n\n// Function: FPDFBitmap_GetFormat\n//          Get the format of the bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The format of the bitmap.\n// Comments:\n//          Only formats supported by FPDFBitmap_CreateEx are supported by this\n//          function; see the list of such formats above.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetFormat(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_FillRect\n//          Fill a rectangle in a bitmap.\n// Parameters:\n//          bitmap      -   The handle to the bitmap. Returned by\n//                          FPDFBitmap_Create.\n//          left        -   The left position. Starting from 0 at the\n//                          left-most pixel.\n//          top         -   The top position. Starting from 0 at the\n//                          top-most line.\n//          width       -   Width in pixels to be filled.\n//          height      -   Height in pixels to be filled.\n//          color       -   A 32-bit value specifing the color, in 8888 ARGB\n//                          format.\n// Return value:\n//          Returns whether the operation succeeded or not.\n// Comments:\n//          This function sets the color and (optionally) alpha value in the\n//          specified region of the bitmap.\n//\n//          NOTE: If the alpha channel is used, this function does NOT\n//          composite the background with the source color, instead the\n//          background will be replaced by the source color and the alpha.\n//\n//          If the alpha channel is not used, the alpha parameter is ignored.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFBitmap_FillRect(FPDF_BITMAP bitmap,\n                                                        int left,\n                                                        int top,\n                                                        int width,\n                                                        int height,\n                                                        FPDF_DWORD color);\n\n// Function: FPDFBitmap_GetBuffer\n//          Get data buffer of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The pointer to the first byte of the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel\n//\n//          Applications can use this function to get the bitmap buffer pointer,\n//          then manipulate any color and/or alpha values for any pixels in the\n//          bitmap.\n//\n//          Use FPDFBitmap_GetFormat() to find out the format of the data.\nFPDF_EXPORT void* FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetWidth\n//          Get width of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The width of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetWidth(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetHeight\n//          Get height of a bitmap.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The height of the bitmap in pixels.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetHeight(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_GetStride\n//          Get number of bytes for each line in the bitmap buffer.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          The number of bytes for each line in the bitmap buffer.\n// Comments:\n//          The stride may be more than width * number of bytes per pixel.\nFPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap);\n\n// Function: FPDFBitmap_Destroy\n//          Destroy a bitmap and release all related buffers.\n// Parameters:\n//          bitmap      -   Handle to the bitmap. Returned by FPDFBitmap_Create\n//                          or FPDFImageObj_GetBitmap.\n// Return value:\n//          None.\n// Comments:\n//          This function will not destroy any external buffers provided when\n//          the bitmap was created.\nFPDF_EXPORT void FPDF_CALLCONV FPDFBitmap_Destroy(FPDF_BITMAP bitmap);\n\n// Function: FPDF_VIEWERREF_GetPrintScaling\n//          Whether the PDF document prefers to be scaled or not.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          None.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintScaling(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetNumCopies\n//          Returns the number of copies to be printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The number of copies to be printed.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetNumCopies(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetPrintPageRange\n//          Page numbers to initialize print dialog box when file is printed.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The print page range to be used for printing.\nFPDF_EXPORT FPDF_PAGERANGE FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRange(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeCount\n//          Returns the number of elements in a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n// Return value:\n//          The number of elements in the page range. Returns 0 on error.\nFPDF_EXPORT size_t FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeCount(FPDF_PAGERANGE pagerange);\n\n// Experimental API.\n// Function: FPDF_VIEWERREF_GetPrintPageRangeElement\n//          Returns an element from a FPDF_PAGERANGE.\n// Parameters:\n//          pagerange   -   Handle to the page range.\n//          index       -   Index of the element.\n// Return value:\n//          The value of the element in the page range at a given index.\n//          Returns -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV\nFPDF_VIEWERREF_GetPrintPageRangeElement(FPDF_PAGERANGE pagerange, size_t index);\n\n// Function: FPDF_VIEWERREF_GetDuplex\n//          Returns the paper handling option to be used when printing from\n//          the print dialog.\n// Parameters:\n//          document    -   Handle to the loaded document.\n// Return value:\n//          The paper handling option to be used when printing.\nFPDF_EXPORT FPDF_DUPLEXTYPE FPDF_CALLCONV\nFPDF_VIEWERREF_GetDuplex(FPDF_DOCUMENT document);\n\n// Function: FPDF_VIEWERREF_GetName\n//          Gets the contents for a viewer ref, with a given key. The value must\n//          be of type \"name\".\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          key         -   Name of the key in the viewer pref dictionary,\n//                          encoded in UTF-8.\n//          buffer      -   Caller-allocate buffer to receive the key, or NULL\n//                      -   to query the required length.\n//          length      -   Length of the buffer.\n// Return value:\n//          The number of bytes in the contents, including the NULL terminator.\n//          Thus if the return value is 0, then that indicates an error, such\n//          as when |document| is invalid. If |length| is less than the required\n//          length, or |buffer| is NULL, |buffer| will not be modified.\nFPDF_EXPORT unsigned long FPDF_CALLCONV\nFPDF_VIEWERREF_GetName(FPDF_DOCUMENT document,\n                       FPDF_BYTESTRING key,\n                       char* buffer,\n                       unsigned long length);\n\n// Function: FPDF_CountNamedDests\n//          Get the count of named destinations in the PDF document.\n// Parameters:\n//          document    -   Handle to a document\n// Return value:\n//          The count of named destinations.\nFPDF_EXPORT FPDF_DWORD FPDF_CALLCONV\nFPDF_CountNamedDests(FPDF_DOCUMENT document);\n\n// Function: FPDF_GetNamedDestByName\n//          Get a the destination handle for the given name.\n// Parameters:\n//          document    -   Handle to the loaded document.\n//          name        -   The name of a destination.\n// Return value:\n//          The handle to the destination.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV\nFPDF_GetNamedDestByName(FPDF_DOCUMENT document, FPDF_BYTESTRING name);\n\n// Function: FPDF_GetNamedDest\n//          Get the named destination by index.\n// Parameters:\n//          document        -   Handle to a document\n//          index           -   The index of a named destination.\n//          buffer          -   The buffer to store the destination name,\n//                              used as wchar_t*.\n//          buflen [in/out] -   Size of the buffer in bytes on input,\n//                              length of the result in bytes on output\n//                              or -1 if the buffer is too small.\n// Return value:\n//          The destination handle for a given index, or NULL if there is no\n//          named destination corresponding to |index|.\n// Comments:\n//          Call this function twice to get the name of the named destination:\n//            1) First time pass in |buffer| as NULL and get buflen.\n//            2) Second time pass in allocated |buffer| and buflen to retrieve\n//               |buffer|, which should be used as wchar_t*.\n//\n//         If buflen is not sufficiently large, it will be set to -1 upon\n//         return.\nFPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDF_GetNamedDest(FPDF_DOCUMENT document,\n                                                      int index,\n                                                      void* buffer,\n                                                      long* buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketCount\n//          Get the number of valid packets in the XFA entry.\n// Parameters:\n//          document - Handle to the document.\n// Return value:\n//          The number of valid packets, or -1 on error.\nFPDF_EXPORT int FPDF_CALLCONV FPDF_GetXFAPacketCount(FPDF_DOCUMENT document);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketName\n//          Get the name of a packet in the XFA array.\n// Parameters:\n//          document - Handle to the document.\n//          index    - Index number of the packet. 0 for the first packet.\n//          buffer   - Buffer for holding the name of the XFA packet.\n//          buflen   - Length of |buffer| in bytes.\n// Return value:\n//          The length of the packet name in bytes, or 0 on error.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount().\n// |buffer| is only modified if it is non-NULL and |buflen| is greater than or\n// equal to the length of the packet name. The packet name includes a\n// terminating NUL character. |buffer| is unmodified on error.\nFPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetXFAPacketName(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen);\n\n// Experimental API.\n// Function: FPDF_GetXFAPacketContent\n//          Get the content of a packet in the XFA array.\n// Parameters:\n//          document   - Handle to the document.\n//          index      - Index number of the packet. 0 for the first packet.\n//          buffer     - Buffer for holding the content of the XFA packet.\n//          buflen     - Length of |buffer| in bytes.\n//          out_buflen - Pointer to the variable that will receive the minimum\n//                       buffer size needed to contain the content of the XFA\n//                       packet.\n// Return value:\n//          Whether the operation succeeded or not.\n//\n// |document| must be valid and |index| must be in the range [0, N), where N is\n// the value returned by FPDF_GetXFAPacketCount(). |out_buflen| must not be\n// NULL. When the aforementioned arguments are valid, the operation succeeds,\n// and |out_buflen| receives the content size. |buffer| is only modified if\n// |buffer| is non-null and long enough to contain the content. Callers must\n// check both the return value and the input |buflen| is no less than the\n// returned |out_buflen| before using the data in |buffer|.\nFPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_GetXFAPacketContent(\n    FPDF_DOCUMENT document,\n    int index,\n    void* buffer,\n    unsigned long buflen,\n    unsigned long* out_buflen);\n\n#ifdef PDF_ENABLE_V8\n// Function: FPDF_GetRecommendedV8Flags\n//          Returns a space-separated string of command line flags that are\n//          recommended to be passed into V8 via V8::SetFlagsFromString()\n//          prior to initializing the PDFium library.\n// Parameters:\n//          None.\n// Return value:\n//          NUL-terminated string of the form \"--flag1 --flag2\".\n//          The caller must not attempt to modify or free the result.\nFPDF_EXPORT const char* FPDF_CALLCONV FPDF_GetRecommendedV8Flags();\n\n// Experimental API.\n// Function: FPDF_GetArrayBufferAllocatorSharedInstance()\n//          Helper function for initializing V8 isolates that will\n//          use PDFium's internal memory management.\n// Parameters:\n//          None.\n// Return Value:\n//          Pointer to a suitable v8::ArrayBuffer::Allocator, returned\n//          as void for C compatibility.\n// Notes:\n//          Use is optional, but allows external creation of isolates\n//          matching the ones PDFium will make when none is provided\n//          via |FPDF_LIBRARY_CONFIG::m_pIsolate|.\n//\n//          Can only be called when the library is in an uninitialized or\n//          destroyed state.\nFPDF_EXPORT void* FPDF_CALLCONV FPDF_GetArrayBufferAllocatorSharedInstance();\n#endif  // PDF_ENABLE_V8\n\n#ifdef PDF_ENABLE_XFA\n// Function: FPDF_BStr_Init\n//          Helper function to initialize a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Init(FPDF_BSTR* bstr);\n\n// Function: FPDF_BStr_Set\n//          Helper function to copy string data into the FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Set(FPDF_BSTR* bstr,\n                                                    const char* cstr,\n                                                    int length);\n\n// Function: FPDF_BStr_Clear\n//          Helper function to clear a FPDF_BSTR.\nFPDF_EXPORT FPDF_RESULT FPDF_CALLCONV FPDF_BStr_Clear(FPDF_BSTR* bstr);\n#endif  // PDF_ENABLE_XFA\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // PUBLIC_FPDFVIEW_H_\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/abseil.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        https://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       https://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/agg23.txt",
    "content": "//----------------------------------------------------------------------------\n// Anti-Grain Geometry - Version 2.3\n// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)\n//\n// Permission to copy, use, modify, sell and distribute this software\n// is granted provided this copyright notice appears in all copies.\n// This software is provided \"as is\" without express or implied\n// warranty, and with no claim as to its suitability for any purpose.\n//\n//----------------------------------------------------------------------------\n// Contact: mcseem@antigrain.com\n//          mcseemagg@yahoo.com\n//          http://www.antigrain.com\n//----------------------------------------------------------------------------\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/fast_float.txt",
    "content": "MIT License\r\n\r\nCopyright (c) 2021 The fast_float authors\r\n\r\nPermission is hereby granted, free of charge, to any\r\nperson obtaining a copy of this software and associated\r\ndocumentation files (the \"Software\"), to deal in the\r\nSoftware without restriction, including without\r\nlimitation the rights to use, copy, modify, merge,\r\npublish, distribute, sublicense, and/or sell copies of\r\nthe Software, and to permit persons to whom the Software\r\nis furnished to do so, subject to the following\r\nconditions:\r\n\r\nThe above copyright notice and this permission notice\r\nshall be included in all copies or substantial portions\r\nof the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\r\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\r\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\r\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\r\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\r\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r\nDEALINGS IN THE SOFTWARE.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/freetype.txt",
    "content": "                    The FreeType Project LICENSE\n                    ----------------------------\n\n                            2006-Jan-27\n\n                    Copyright 1996-2002, 2006 by\n          David Turner, Robert Wilhelm, and Werner Lemberg\n\n\n\nIntroduction\n============\n\n  The FreeType  Project is distributed in  several archive packages;\n  some of them may contain, in addition to the FreeType font engine,\n  various tools and  contributions which rely on, or  relate to, the\n  FreeType Project.\n\n  This  license applies  to all  files found  in such  packages, and\n  which do not  fall under their own explicit  license.  The license\n  affects  thus  the  FreeType   font  engine,  the  test  programs,\n  documentation and makefiles, at the very least.\n\n  This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG\n  (Independent JPEG  Group) licenses, which  all encourage inclusion\n  and  use of  free  software in  commercial  and freeware  products\n  alike.  As a consequence, its main points are that:\n\n    o We don't promise that this software works. However, we will be\n      interested in any kind of bug reports. (`as is' distribution)\n\n    o You can  use this software for whatever you  want, in parts or\n      full form, without having to pay us. (`royalty-free' usage)\n\n    o You may not pretend that  you wrote this software.  If you use\n      it, or  only parts of it,  in a program,  you must acknowledge\n      somewhere  in  your  documentation  that  you  have  used  the\n      FreeType code. (`credits')\n\n  We  specifically  permit  and  encourage  the  inclusion  of  this\n  software, with  or without modifications,  in commercial products.\n  We  disclaim  all warranties  covering  The  FreeType Project  and\n  assume no liability related to The FreeType Project.\n\n\n  Finally,  many  people  asked  us  for  a  preferred  form  for  a\n  credit/disclaimer to use in compliance with this license.  We thus\n  encourage you to use the following text:\n\n   \"\"\"\n    Portions of this software are copyright  <year> The FreeType\n    Project (www.freetype.org).  All rights reserved.\n   \"\"\"\n\n  Please replace <year> with the value from the FreeType version you\n  actually use.\n\n\nLegal Terms\n===========\n\n0. Definitions\n--------------\n\n  Throughout this license,  the terms `package', `FreeType Project',\n  and  `FreeType  archive' refer  to  the  set  of files  originally\n  distributed  by the  authors  (David Turner,  Robert Wilhelm,  and\n  Werner Lemberg) as the `FreeType Project', be they named as alpha,\n  beta or final release.\n\n  `You' refers to  the licensee, or person using  the project, where\n  `using' is a generic term including compiling the project's source\n  code as  well as linking it  to form a  `program' or `executable'.\n  This  program is  referred to  as  `a program  using the  FreeType\n  engine'.\n\n  This  license applies  to all  files distributed  in  the original\n  FreeType  Project,   including  all  source   code,  binaries  and\n  documentation,  unless  otherwise  stated   in  the  file  in  its\n  original, unmodified form as  distributed in the original archive.\n  If you are  unsure whether or not a particular  file is covered by\n  this license, you must contact us to verify this.\n\n  The FreeType  Project is copyright (C) 1996-2000  by David Turner,\n  Robert Wilhelm, and Werner Lemberg.  All rights reserved except as\n  specified below.\n\n1. No Warranty\n--------------\n\n  THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY\n  KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,\n  WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR\n  PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS\n  BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO\n  USE, OF THE FREETYPE PROJECT.\n\n2. Redistribution\n-----------------\n\n  This  license  grants  a  worldwide, royalty-free,  perpetual  and\n  irrevocable right  and license to use,  execute, perform, compile,\n  display,  copy,   create  derivative  works   of,  distribute  and\n  sublicense the  FreeType Project (in  both source and  object code\n  forms)  and  derivative works  thereof  for  any  purpose; and  to\n  authorize others  to exercise  some or all  of the  rights granted\n  herein, subject to the following conditions:\n\n    o Redistribution of  source code  must retain this  license file\n      (`FTL.TXT') unaltered; any  additions, deletions or changes to\n      the original  files must be clearly  indicated in accompanying\n      documentation.   The  copyright   notices  of  the  unaltered,\n      original  files must  be  preserved in  all  copies of  source\n      files.\n\n    o Redistribution in binary form must provide a  disclaimer  that\n      states  that  the software is based in part of the work of the\n      FreeType Team,  in  the  distribution  documentation.  We also\n      encourage you to put an URL to the FreeType web page  in  your\n      documentation, though this isn't mandatory.\n\n  These conditions  apply to any  software derived from or  based on\n  the FreeType Project,  not just the unmodified files.   If you use\n  our work, you  must acknowledge us.  However, no  fee need be paid\n  to us.\n\n3. Advertising\n--------------\n\n  Neither the  FreeType authors and  contributors nor you  shall use\n  the name of the  other for commercial, advertising, or promotional\n  purposes without specific prior written permission.\n\n  We suggest,  but do not require, that  you use one or  more of the\n  following phrases to refer  to this software in your documentation\n  or advertising  materials: `FreeType Project',  `FreeType Engine',\n  `FreeType library', or `FreeType Distribution'.\n\n  As  you have  not signed  this license,  you are  not  required to\n  accept  it.   However,  as  the FreeType  Project  is  copyrighted\n  material, only  this license, or  another one contracted  with the\n  authors, grants you  the right to use, distribute,  and modify it.\n  Therefore,  by  using,  distributing,  or modifying  the  FreeType\n  Project, you indicate that you understand and accept all the terms\n  of this license.\n\n4. Contacts\n-----------\n\n  There are two mailing lists related to FreeType:\n\n    o freetype@nongnu.org\n\n      Discusses general use and applications of FreeType, as well as\n      future and  wanted additions to the  library and distribution.\n      If  you are looking  for support,  start in  this list  if you\n      haven't found anything to help you in the documentation.\n\n    o freetype-devel@nongnu.org\n\n      Discusses bugs,  as well  as engine internals,  design issues,\n      specific licenses, porting, etc.\n\n  Our home page can be found at\n\n    http://www.freetype.org\n\n\n--- end of FTL.TXT ---\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/icu.txt",
    "content": "UNICODE LICENSE V3\r\n\r\nCOPYRIGHT AND PERMISSION NOTICE\r\n\r\nCopyright © 2016-2025 Unicode, Inc.\r\n\r\nNOTICE TO USER: Carefully read the following legal agreement. BY\r\nDOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\r\nSOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\r\nTERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\r\nDOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a\r\ncopy of data files and any associated documentation (the \"Data Files\") or\r\nsoftware and any associated documentation (the \"Software\") to deal in the\r\nData Files or Software without restriction, including without limitation\r\nthe rights to use, copy, modify, merge, publish, distribute, and/or sell\r\ncopies of the Data Files or Software, and to permit persons to whom the\r\nData Files or Software are furnished to do so, provided that either (a)\r\nthis copyright and permission notice appear with all copies of the Data\r\nFiles or Software, or (b) this copyright and permission notice appear in\r\nassociated Documentation.\r\n\r\nTHE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\r\nKIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\r\nTHIRD PARTY RIGHTS.\r\n\r\nIN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\r\nBE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\r\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\r\nFILES OR SOFTWARE.\r\n\r\nExcept as contained in this notice, the name of a copyright holder shall\r\nnot be used in advertising or otherwise to promote the sale, use or other\r\ndealings in these Data Files or Software without prior written\r\nauthorization of the copyright holder.\r\n\r\nSPDX-License-Identifier: Unicode-3.0\r\n\r\n----------------------------------------------------------------------\r\n\r\nThird-Party Software Licenses\r\n\r\nThis section contains third-party software notices and/or additional\r\nterms for licensed third-party software components included within ICU\r\nlibraries.\r\n\r\n----------------------------------------------------------------------\r\n\r\nICU License - ICU 1.8.1 to ICU 57.1\r\n\r\nCOPYRIGHT AND PERMISSION NOTICE\r\n\r\nCopyright (c) 1995-2016 International Business Machines Corporation and others\r\nAll rights reserved.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining\r\na copy of this software and associated documentation files (the\r\n\"Software\"), to deal in the Software without restriction, including\r\nwithout limitation the rights to use, copy, modify, merge, publish,\r\ndistribute, and/or sell copies of the Software, and to permit persons\r\nto whom the Software is furnished to do so, provided that the above\r\ncopyright notice(s) and this permission notice appear in all copies of\r\nthe Software and that both the above copyright notice(s) and this\r\npermission notice appear in supporting documentation.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r\nOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\r\nHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\r\nSPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\r\nRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\r\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\r\nCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r\n\r\nExcept as contained in this notice, the name of a copyright holder\r\nshall not be used in advertising or otherwise to promote the sale, use\r\nor other dealings in this Software without prior written authorization\r\nof the copyright holder.\r\n\r\nAll trademarks and registered trademarks mentioned herein are the\r\nproperty of their respective owners.\r\n\r\n----------------------------------------------------------------------\r\n\r\nChinese/Japanese Word Break Dictionary Data (cjdict.txt)\r\n\r\n #     The Google Chrome software developed by Google is licensed under\r\n # the BSD license. Other software included in this distribution is\r\n # provided under other licenses, as set forth below.\r\n #\r\n #  The BSD License\r\n #  http://opensource.org/licenses/bsd-license.php\r\n #  Copyright (C) 2006-2008, Google Inc.\r\n #\r\n #  All rights reserved.\r\n #\r\n #  Redistribution and use in source and binary forms, with or without\r\n # modification, are permitted provided that the following conditions are met:\r\n #\r\n #  Redistributions of source code must retain the above copyright notice,\r\n # this list of conditions and the following disclaimer.\r\n #  Redistributions in binary form must reproduce the above\r\n # copyright notice, this list of conditions and the following\r\n # disclaimer in the documentation and/or other materials provided with\r\n # the distribution.\r\n #  Neither the name of  Google Inc. nor the names of its\r\n # contributors may be used to endorse or promote products derived from\r\n # this software without specific prior written permission.\r\n #\r\n #\r\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\r\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\r\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n #\r\n #\r\n #  The word list in cjdict.txt are generated by combining three word lists\r\n # listed below with further processing for compound word breaking. The\r\n # frequency is generated with an iterative training against Google web\r\n # corpora.\r\n #\r\n #  * Libtabe (Chinese)\r\n #    - https://sourceforge.net/project/?group_id=1519\r\n #    - Its license terms and conditions are shown below.\r\n #\r\n #  * IPADIC (Japanese)\r\n #    - http://chasen.aist-nara.ac.jp/chasen/distribution.html\r\n #    - Its license terms and conditions are shown below.\r\n #\r\n #  ---------COPYING.libtabe ---- BEGIN--------------------\r\n #\r\n #  /*\r\n #   * Copyright (c) 1999 TaBE Project.\r\n #   * Copyright (c) 1999 Pai-Hsiang Hsiao.\r\n #   * All rights reserved.\r\n #   *\r\n #   * Redistribution and use in source and binary forms, with or without\r\n #   * modification, are permitted provided that the following conditions\r\n #   * are met:\r\n #   *\r\n #   * . Redistributions of source code must retain the above copyright\r\n #   *   notice, this list of conditions and the following disclaimer.\r\n #   * . Redistributions in binary form must reproduce the above copyright\r\n #   *   notice, this list of conditions and the following disclaimer in\r\n #   *   the documentation and/or other materials provided with the\r\n #   *   distribution.\r\n #   * . Neither the name of the TaBE Project nor the names of its\r\n #   *   contributors may be used to endorse or promote products derived\r\n #   *   from this software without specific prior written permission.\r\n #   *\r\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\r\n #   */\r\n #\r\n #  /*\r\n #   * Copyright (c) 1999 Computer Systems and Communication Lab,\r\n #   *                    Institute of Information Science, Academia\r\n #       *                    Sinica. All rights reserved.\r\n #   *\r\n #   * Redistribution and use in source and binary forms, with or without\r\n #   * modification, are permitted provided that the following conditions\r\n #   * are met:\r\n #   *\r\n #   * . Redistributions of source code must retain the above copyright\r\n #   *   notice, this list of conditions and the following disclaimer.\r\n #   * . Redistributions in binary form must reproduce the above copyright\r\n #   *   notice, this list of conditions and the following disclaimer in\r\n #   *   the documentation and/or other materials provided with the\r\n #   *   distribution.\r\n #   * . Neither the name of the Computer Systems and Communication Lab\r\n #   *   nor the names of its contributors may be used to endorse or\r\n #   *   promote products derived from this software without specific\r\n #   *   prior written permission.\r\n #   *\r\n #   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n #   * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n #   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r\n #   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r\n #   * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r\n #   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n #   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n #   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r\n #   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r\n #   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n #   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r\n #   * OF THE POSSIBILITY OF SUCH DAMAGE.\r\n #   */\r\n #\r\n #  Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\r\n #      University of Illinois\r\n #  c-tsai4@uiuc.edu  http://casper.beckman.uiuc.edu/~c-tsai4\r\n #\r\n #  ---------------COPYING.libtabe-----END--------------------------------\r\n #\r\n #\r\n #  ---------------COPYING.ipadic-----BEGIN-------------------------------\r\n #\r\n #  Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\r\n #  and Technology.  All Rights Reserved.\r\n #\r\n #  Use, reproduction, and distribution of this software is permitted.\r\n #  Any copy of this software, whether in its original form or modified,\r\n #  must include both the above copyright notice and the following\r\n #  paragraphs.\r\n #\r\n #  Nara Institute of Science and Technology (NAIST),\r\n #  the copyright holders, disclaims all warranties with regard to this\r\n #  software, including all implied warranties of merchantability and\r\n #  fitness, in no event shall NAIST be liable for\r\n #  any special, indirect or consequential damages or any damages\r\n #  whatsoever resulting from loss of use, data or profits, whether in an\r\n #  action of contract, negligence or other tortuous action, arising out\r\n #  of or in connection with the use or performance of this software.\r\n #\r\n #  A large portion of the dictionary entries\r\n #  originate from ICOT Free Software.  The following conditions for ICOT\r\n #  Free Software applies to the current dictionary as well.\r\n #\r\n #  Each User may also freely distribute the Program, whether in its\r\n #  original form or modified, to any third party or parties, PROVIDED\r\n #  that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\r\n #  on, or be attached to, the Program, which is distributed substantially\r\n #  in the same form as set out herein and that such intended\r\n #  distribution, if actually made, will neither violate or otherwise\r\n #  contravene any of the laws and regulations of the countries having\r\n #  jurisdiction over the User or the intended distribution itself.\r\n #\r\n #  NO WARRANTY\r\n #\r\n #  The program was produced on an experimental basis in the course of the\r\n #  research and development conducted during the project and is provided\r\n #  to users as so produced on an experimental basis.  Accordingly, the\r\n #  program is provided without any warranty whatsoever, whether express,\r\n #  implied, statutory or otherwise.  The term \"warranty\" used herein\r\n #  includes, but is not limited to, any warranty of the quality,\r\n #  performance, merchantability and fitness for a particular purpose of\r\n #  the program and the nonexistence of any infringement or violation of\r\n #  any right of any third party.\r\n #\r\n #  Each user of the program will agree and understand, and be deemed to\r\n #  have agreed and understood, that there is no warranty whatsoever for\r\n #  the program and, accordingly, the entire risk arising from or\r\n #  otherwise connected with the program is assumed by the user.\r\n #\r\n #  Therefore, neither ICOT, the copyright holder, or any other\r\n #  organization that participated in or was otherwise related to the\r\n #  development of the program and their respective officials, directors,\r\n #  officers and other employees shall be held liable for any and all\r\n #  damages, including, without limitation, general, special, incidental\r\n #  and consequential damages, arising out of or otherwise in connection\r\n #  with the use or inability to use the program or any product, material\r\n #  or result produced or otherwise obtained by using the program,\r\n #  regardless of whether they have been advised of, or otherwise had\r\n #  knowledge of, the possibility of such damages at any time during the\r\n #  project or thereafter.  Each user will be deemed to have agreed to the\r\n #  foregoing by his or her commencement of use of the program.  The term\r\n #  \"use\" as used herein includes, but is not limited to, the use,\r\n #  modification, copying and distribution of the program and the\r\n #  production of secondary products from the program.\r\n #\r\n #  In the case where the program, whether in its original form or\r\n #  modified, was distributed or delivered to or received by a user from\r\n #  any person, organization or entity other than ICOT, unless it makes or\r\n #  grants independently of ICOT any specific warranty to the user in\r\n #  writing, such person, organization or entity, will also be exempted\r\n #  from and not be held liable to the user for any such damages as noted\r\n #  above as far as the program is concerned.\r\n #\r\n #  ---------------COPYING.ipadic-----END----------------------------------\r\n\r\n----------------------------------------------------------------------\r\n\r\nLao Word Break Dictionary Data (laodict.txt)\r\n\r\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\r\n # License & terms of use: http://www.unicode.org/copyright.html\r\n # Copyright (c) 2015 International Business Machines Corporation\r\n # and others. All Rights Reserved.\r\n #\r\n # Project: https://github.com/rober42539/lao-dictionary\r\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\r\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\r\n #          (copied below)\r\n #\r\n #\tThis file is derived from the above dictionary version of Nov 22, 2020\r\n #  ----------------------------------------------------------------------\r\n #  Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\r\n #  All rights reserved.\r\n #\r\n #  Redistribution and use in source and binary forms, with or without\r\n #  modification, are permitted provided that the following conditions are met:\r\n #\r\n #  Redistributions of source code must retain the above copyright notice, this\r\n #  list of conditions and the following disclaimer. Redistributions in binary\r\n #  form must reproduce the above copyright notice, this list of conditions and\r\n #  the following disclaimer in the documentation and/or other materials\r\n #  provided with the distribution.\r\n #\r\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r\n # OF THE POSSIBILITY OF SUCH DAMAGE.\r\n #  --------------------------------------------------------------------------\r\n\r\n----------------------------------------------------------------------\r\n\r\nBurmese Word Break Dictionary Data (burmesedict.txt)\r\n\r\n #  Copyright (c) 2014 International Business Machines Corporation\r\n #  and others. All Rights Reserved.\r\n #\r\n #  This list is part of a project hosted at:\r\n #    github.com/kanyawtech/myanmar-karen-word-lists\r\n #\r\n #  --------------------------------------------------------------------------\r\n #  Copyright (c) 2013, LeRoy Benjamin Sharon\r\n #  All rights reserved.\r\n #\r\n #  Redistribution and use in source and binary forms, with or without\r\n #  modification, are permitted provided that the following conditions\r\n #  are met: Redistributions of source code must retain the above\r\n #  copyright notice, this list of conditions and the following\r\n #  disclaimer.  Redistributions in binary form must reproduce the\r\n #  above copyright notice, this list of conditions and the following\r\n #  disclaimer in the documentation and/or other materials provided\r\n #  with the distribution.\r\n #\r\n #    Neither the name Myanmar Karen Word Lists, nor the names of its\r\n #    contributors may be used to endorse or promote products derived\r\n #    from this software without specific prior written permission.\r\n #\r\n #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r\n #  CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r\n #  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\r\n #  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\n #  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\r\n #  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n #  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n #  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\r\n #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\r\n #  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r\n #  SUCH DAMAGE.\r\n #  --------------------------------------------------------------------------\r\n\r\n----------------------------------------------------------------------\r\n\r\nTime Zone Database\r\n\r\n  ICU uses the public domain data and code derived from Time Zone\r\nDatabase for its time zone support. The ownership of the TZ database\r\nis explained in BCP 175: Procedure for Maintaining the Time Zone\r\nDatabase section 7.\r\n\r\n # 7.  Database Ownership\r\n #\r\n #    The TZ database itself is not an IETF Contribution or an IETF\r\n #    document.  Rather it is a pre-existing and regularly updated work\r\n #    that is in the public domain, and is intended to remain in the\r\n #    public domain.  Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\r\n #    not apply to the TZ Database or contributions that individuals make\r\n #    to it.  Should any claims be made and substantiated against the TZ\r\n #    Database, the organization that is providing the IANA\r\n #    Considerations defined in this RFC, under the memorandum of\r\n #    understanding with the IETF, currently ICANN, may act in accordance\r\n #    with all competent court orders.  No ownership claims will be made\r\n #    by ICANN or the IETF Trust on the database or the code.  Any person\r\n #    making a contribution to the database or code waives all rights to\r\n #    future claims in that contribution or in the TZ Database.\r\n\r\n----------------------------------------------------------------------\r\n\r\nGoogle double-conversion\r\n\r\nCopyright 2006-2011, the V8 project authors. All rights reserved.\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are\r\nmet:\r\n\r\n    * Redistributions of source code must retain the above copyright\r\n      notice, this list of conditions and the following disclaimer.\r\n    * Redistributions in binary form must reproduce the above\r\n      copyright notice, this list of conditions and the following\r\n      disclaimer in the documentation and/or other materials provided\r\n      with the distribution.\r\n    * Neither the name of Google Inc. nor the names of its\r\n      contributors may be used to endorse or promote products derived\r\n      from this software without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n----------------------------------------------------------------------\r\n\r\nJSON parsing library (nlohmann/json)\r\n\r\nFile: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\r\n\r\nMIT License\r\n\r\nCopyright (c) 2013-2022 Niels Lohmann\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n\r\n----------------------------------------------------------------------\r\n\r\nFile: aclocal.m4 (only for ICU4C)\r\nSection: pkg.m4 - Macros to locate and utilise pkg-config.\r\n\r\n\r\nCopyright © 2004 Scott James Remnant <scott@netsplit.com>.\r\nCopyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>\r\n\r\nThis program is free software; you can redistribute it and/or modify\r\nit under the terms of the GNU General Public License as published by\r\nthe Free Software Foundation; either version 2 of the License, or\r\n(at your option) any later version.\r\n\r\nThis program is distributed in the hope that it will be useful, but\r\nWITHOUT ANY WARRANTY; without even the implied warranty of\r\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r\nGeneral Public License for more details.\r\n\r\nYou should have received a copy of the GNU General Public License\r\nalong with this program; if not, write to the Free Software\r\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r\n02111-1307, USA.\r\n\r\nAs a special exception to the GNU General Public License, if you\r\ndistribute this file as part of a program that contains a\r\nconfiguration script generated by Autoconf, you may include it under\r\nthe same distribution terms that you use for the rest of that\r\nprogram.\r\n\r\n\r\n(The condition for the exception is fulfilled because\r\nICU4C includes a configuration script generated by Autoconf,\r\nnamely the `configure` script.)\r\n\r\n----------------------------------------------------------------------\r\n\r\nFile: config.guess (only for ICU4C)\r\n\r\n\r\nThis file is free software; you can redistribute it and/or modify it\r\nunder the terms of the GNU General Public License as published by\r\nthe Free Software Foundation, either version 3 of the License, or\r\n(at your option) any later version.\r\n\r\nThis program is distributed in the hope that it will be useful, but\r\nWITHOUT ANY WARRANTY; without even the implied warranty of\r\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r\nGeneral Public License for more details.\r\n\r\nYou should have received a copy of the GNU General Public License\r\nalong with this program; if not, see <https://www.gnu.org/licenses/>.\r\n\r\nAs a special exception to the GNU General Public License, if you\r\ndistribute this file as part of a program that contains a\r\nconfiguration script generated by Autoconf, you may include it under\r\nthe same distribution terms that you use for the rest of that\r\nprogram.  This Exception is an additional permission under section 7\r\nof the GNU General Public License, version 3 (\"GPLv3\").\r\n\r\n\r\n(The condition for the exception is fulfilled because\r\nICU4C includes a configuration script generated by Autoconf,\r\nnamely the `configure` script.)\r\n\r\n----------------------------------------------------------------------\r\n\r\nFile: install-sh (only for ICU4C)\r\n\r\n\r\nCopyright 1991 by the Massachusetts Institute of Technology\r\n\r\nPermission to use, copy, modify, distribute, and sell this software and its\r\ndocumentation for any purpose is hereby granted without fee, provided that\r\nthe above copyright notice appear in all copies and that both that\r\ncopyright notice and this permission notice appear in supporting\r\ndocumentation, and that the name of M.I.T. not be used in advertising or\r\npublicity pertaining to distribution of the software without specific,\r\nwritten prior permission.  M.I.T. makes no representations about the\r\nsuitability of this software for any purpose.  It is provided \"as is\"\r\nwithout express or implied warranty.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/lcms.txt",
    "content": "//---------------------------------------------------------------------------------\n//\n//  Little Color Management System\n//  Copyright (c) 1998-2023 Marti Maria Saguer\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the Software\n// is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n//---------------------------------------------------------------------------------\n//\n// Version 2.15 \n//\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/libjpeg_turbo.ijg",
    "content": "libjpeg-turbo note:  This file has been modified by The libjpeg-turbo Project\r\nto include only information relevant to libjpeg-turbo, to wordsmith certain\r\nsections, and to remove impolitic language that existed in the libjpeg v8\r\nREADME.  It is included only for reference.  Please see README.md for\r\ninformation specific to libjpeg-turbo.\r\n\r\n\r\nThe Independent JPEG Group's JPEG software\r\n==========================================\r\n\r\nThis distribution contains a release of the Independent JPEG Group's free JPEG\r\nsoftware.  You are welcome to redistribute this software and to use it for any\r\npurpose, subject to the conditions under LEGAL ISSUES, below.\r\n\r\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\r\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\r\nJulian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,\r\nand other members of the Independent JPEG Group.\r\n\r\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\r\n(also known as JPEG, together with ITU-T SG16).\r\n\r\n\r\nDOCUMENTATION ROADMAP\r\n=====================\r\n\r\nThis file contains the following sections:\r\n\r\nOVERVIEW            General description of JPEG and the IJG software.\r\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\r\nREFERENCES          Where to learn more about JPEG.\r\nARCHIVE LOCATIONS   Where to find newer versions of this software.\r\nFILE FORMAT WARS    Software *not* to get.\r\nTO DO               Plans for future IJG releases.\r\n\r\nOther documentation files in the distribution are:\r\n\r\nUser documentation:\r\n  doc/usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\r\n                        rdjpgcom, and wrjpgcom.\r\n  doc/*.1               Unix-style man pages for programs (same info as\r\n                        usage.txt).\r\n  doc/wizard.txt        Advanced usage instructions for JPEG wizards only.\r\n  doc/change.log        Version-to-version change highlights.\r\nProgrammer and internal documentation:\r\n  doc/libjpeg.txt       How to use the JPEG library in your own programs.\r\n  src/example.c         Sample code for calling the JPEG library.\r\n  doc/structure.txt     Overview of the JPEG library's internal structure.\r\n  doc/coderules.txt     Coding style rules --- please read if you contribute\r\n                        code.\r\n\r\nPlease read at least usage.txt.  Some information can also be found in the JPEG\r\nFAQ (Frequently Asked Questions) article.  See ARCHIVE LOCATIONS below to find\r\nout where to obtain the FAQ article.\r\n\r\nIf you want to understand how the JPEG code works, we suggest reading one or\r\nmore of the REFERENCES, then looking at the documentation files (in roughly\r\nthe order listed) before diving into the code.\r\n\r\n\r\nOVERVIEW\r\n========\r\n\r\nThis package contains C software to implement JPEG image encoding, decoding,\r\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\r\nmethod for full-color and grayscale images.  JPEG's strong suit is compressing\r\nphotographic images or other types of images that have smooth color and\r\nbrightness transitions between neighboring pixels.  Images with sharp lines or\r\nother abrupt features may not compress well with JPEG, and a higher JPEG\r\nquality may have to be used to avoid visible compression artifacts with such\r\nimages.\r\n\r\nJPEG is normally lossy, meaning that the output pixels are not necessarily\r\nidentical to the input pixels.  However, on photographic content and other\r\n\"smooth\" images, very good compression ratios can be obtained with no visible\r\ncompression artifacts, and extremely high compression ratios are possible if\r\nyou are willing to sacrifice image quality (by reducing the \"quality\" setting\r\nin the compressor.)\r\n\r\nThis software implements JPEG baseline, extended-sequential, progressive, and\r\nlossless compression processes.  Provision is made for supporting all variants\r\nof these processes, although some uncommon parameter settings aren't\r\nimplemented yet.  We have made no provision for supporting the hierarchical\r\nprocesses defined in the standard.\r\n\r\nWe provide a set of library routines for reading and writing JPEG image files,\r\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\r\nperform conversion between JPEG and some other popular image file formats.\r\nThe library is intended to be reused in other applications.\r\n\r\nIn order to support file conversion and viewing software, we have included\r\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\r\nfor example, the color quantization modules are not strictly part of JPEG\r\ndecoding, but they are essential for output to colormapped file formats.  These\r\nextra functions can be compiled out of the library if not required for a\r\nparticular application.\r\n\r\nWe have also included \"jpegtran\", a utility for lossless transcoding between\r\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\r\napplications for inserting and extracting textual comments in JFIF files.\r\n\r\nThe emphasis in designing this software has been on achieving portability and\r\nflexibility, while also making it fast enough to be useful.  In particular,\r\nthe software is not intended to be read as a tutorial on JPEG.  (See the\r\nREFERENCES section for introductory material.)  Rather, it is intended to\r\nbe reliable, portable, industrial-strength code.  We do not claim to have\r\nachieved that goal in every aspect of the software, but we strive for it.\r\n\r\nWe welcome the use of this software as a component of commercial products.\r\nNo royalty is required, but we do ask for an acknowledgement in product\r\ndocumentation, as described under LEGAL ISSUES.\r\n\r\n\r\nLEGAL ISSUES\r\n============\r\n\r\nIn plain English:\r\n\r\n1. We don't promise that this software works.  (But if you find any bugs,\r\n   please let us know!)\r\n2. You can use this software for whatever you want.  You don't have to pay us.\r\n3. You may not pretend that you wrote this software.  If you use it in a\r\n   program, you must acknowledge somewhere in your documentation that\r\n   you've used the IJG code.\r\n\r\nIn legalese:\r\n\r\nThe authors make NO WARRANTY or representation, either express or implied,\r\nwith respect to this software, its quality, accuracy, merchantability, or\r\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\r\nits user, assume the entire risk as to its quality and accuracy.\r\n\r\nThis software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.\r\nAll Rights Reserved except as specified below.\r\n\r\nPermission is hereby granted to use, copy, modify, and distribute this\r\nsoftware (or portions thereof) for any purpose, without fee, subject to these\r\nconditions:\r\n(1) If any part of the source code for this software is distributed, then this\r\nREADME file must be included, with this copyright and no-warranty notice\r\nunaltered; and any additions, deletions, or changes to the original files\r\nmust be clearly indicated in accompanying documentation.\r\n(2) If only executable code is distributed, then the accompanying\r\ndocumentation must state that \"this software is based in part on the work of\r\nthe Independent JPEG Group\".\r\n(3) Permission for use of this software is granted only if the user accepts\r\nfull responsibility for any undesirable consequences; the authors accept\r\nNO LIABILITY for damages of any kind.\r\n\r\nThese conditions apply to any software derived from or based on the IJG code,\r\nnot just to the unmodified library.  If you use our work, you ought to\r\nacknowledge us.\r\n\r\nPermission is NOT granted for the use of any IJG author's name or company name\r\nin advertising or publicity relating to this software or products derived from\r\nit.  This software may be referred to only as \"the Independent JPEG Group's\r\nsoftware\".\r\n\r\nWe specifically permit and encourage the use of this software as the basis of\r\ncommercial products, provided that all warranty or liability claims are\r\nassumed by the product vendor.\r\n\r\n\r\nREFERENCES\r\n==========\r\n\r\nWe recommend reading one or more of these references before trying to\r\nunderstand the innards of the JPEG software.\r\n\r\nThe best short technical introduction to the JPEG compression algorithm is\r\n        Wallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\r\n        Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\r\n(Adjacent articles in that issue discuss MPEG motion picture compression,\r\napplications of JPEG, and related topics.)  If you don't have the CACM issue\r\nhandy, a PDF file containing a revised version of Wallace's article is\r\navailable at http://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\r\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\r\nomits the sample images that appeared in CACM, but it includes corrections\r\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\r\nand it may not be used for commercial purposes.\r\n\r\nA somewhat less technical, more leisurely introduction to JPEG can be found in\r\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\r\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\r\ngood explanations and example C code for a multitude of compression methods\r\nincluding JPEG.  It is an excellent source if you are comfortable reading C\r\ncode but don't know much about data compression in general.  The book's JPEG\r\nsample code is far from industrial-strength, but when you are ready to look\r\nat a full implementation, you've got one here...\r\n\r\nThe best currently available description of JPEG is the textbook \"JPEG Still\r\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\r\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\r\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\r\nstandards (DIS 10918-1 and draft DIS 10918-2).\r\n\r\nThe original JPEG standard is divided into two parts, Part 1 being the actual\r\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\r\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\r\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\r\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\r\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\r\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\r\n\r\nThe JPEG standard does not specify all details of an interchangeable file\r\nformat.  For the omitted details, we follow the \"JFIF\" conventions, revision\r\n1.02.  JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and\r\nRecommendation ITU-T T.871 (05/2011): Information technology - Digital\r\ncompression and coding of continuous-tone still images: JPEG File Interchange\r\nFormat (JFIF).  It is available as a free download in PDF file format from\r\nhttps://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.\r\nA PDF file of the older JFIF 1.02 specification is available at\r\nhttp://www.w3.org/Graphics/JPEG/jfif3.pdf.\r\n\r\nThe TIFF 6.0 file format specification can be obtained from\r\nhttp://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation\r\nscheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious\r\nproblems.  IJG does not recommend use of the TIFF 6.0 design (TIFF Compression\r\ntag 6).  Instead, we recommend the JPEG design proposed by TIFF Technical Note\r\n#2 (Compression tag 7).  Copies of this Note can be obtained from\r\nhttp://www.ijg.org/files/.  It is expected that the next revision\r\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\r\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\r\nuses our library to implement TIFF/JPEG per the Note.\r\n\r\n\r\nARCHIVE LOCATIONS\r\n=================\r\n\r\nThe \"official\" archive site for this software is www.ijg.org.\r\nThe most recent released version can always be found there in\r\ndirectory \"files\".\r\n\r\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\r\ngeneral information about JPEG.  It is available at\r\nhttp://www.faqs.org/faqs/jpeg-faq.\r\n\r\n\r\nFILE FORMAT COMPATIBILITY\r\n=========================\r\n\r\nThis software implements ITU T.81 | ISO/IEC 10918 with some extensions from\r\nITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).\r\nInformally, the term \"JPEG image\" or \"JPEG file\" most often refers to JFIF or\r\na subset thereof, but there are other formats containing the name \"JPEG\" that\r\nare incompatible with the original JPEG standard or with JFIF (for instance,\r\nJPEG 2000 and JPEG XR).  This software therefore does not support these\r\nformats.  Indeed, one of the original reasons for developing this free software\r\nwas to help force convergence on a common, interoperable format standard for\r\nJPEG files.\r\n\r\nJFIF is a minimal or \"low end\" representation.  TIFF/JPEG (TIFF revision 6.0 as\r\nmodified by TIFF Technical Note #2) can be used for \"high end\" applications\r\nthat need to record a lot of additional data about an image.\r\n\r\n\r\nTO DO\r\n=====\r\n\r\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/libjpeg_turbo.md",
    "content": "libjpeg-turbo Licenses\r\n======================\r\n\r\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\r\n\r\n- The IJG (Independent JPEG Group) License, which is listed in\r\n  [README.ijg](README.ijg)\r\n\r\n  This license applies to the libjpeg API library and associated programs,\r\n  including any code inherited from libjpeg and any modifications to that\r\n  code.  Note that the libjpeg-turbo SIMD source code bears the\r\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\r\n  the overall libjpeg API library, the terms of the zlib License are subsumed\r\n  by the terms of the IJG License.\r\n\r\n- The Modified (3-clause) BSD License, which is listed below\r\n\r\n  This license applies to the TurboJPEG API library and associated programs, as\r\n  well as the build system.  Note that the TurboJPEG API library wraps the\r\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\r\n  both the terms of the IJG License and the terms of the Modified (3-clause)\r\n  BSD License apply.\r\n\r\n\r\nComplying with the libjpeg-turbo Licenses\r\n=========================================\r\n\r\nThis section provides a roll-up of the libjpeg-turbo licensing terms, to the\r\nbest of our understanding.  This is not a license in and of itself.  It is\r\nintended solely for clarification.\r\n\r\n1.  If you are distributing a modified version of the libjpeg-turbo source,\r\n    then:\r\n\r\n    1.  You cannot alter or remove any existing copyright or license notices\r\n        from the source.\r\n\r\n        **Origin**\r\n        - Clause 1 of the IJG License\r\n        - Clause 1 of the Modified BSD License\r\n        - Clauses 1 and 3 of the zlib License\r\n\r\n    2.  You must add your own copyright notice to the header of each source\r\n        file you modified, so others can tell that you modified that file.  (If\r\n        there is not an existing copyright header in that file, then you can\r\n        simply add a notice stating that you modified the file.)\r\n\r\n        **Origin**\r\n        - Clause 1 of the IJG License\r\n        - Clause 2 of the zlib License\r\n\r\n    3.  You must include the IJG README file, and you must not alter any of the\r\n        copyright or license text in that file.\r\n\r\n        **Origin**\r\n        - Clause 1 of the IJG License\r\n\r\n2.  If you are distributing only libjpeg-turbo binaries without the source, or\r\n    if you are distributing an application that statically links with\r\n    libjpeg-turbo, then:\r\n\r\n    1.  Your product documentation must include a message stating:\r\n\r\n        This software is based in part on the work of the Independent JPEG\r\n        Group.\r\n\r\n        **Origin**\r\n        - Clause 2 of the IJG license\r\n\r\n    2.  If your binary distribution includes or uses the TurboJPEG API, then\r\n        your product documentation must include the text of the Modified BSD\r\n        License (see below.)\r\n\r\n        **Origin**\r\n        - Clause 2 of the Modified BSD License\r\n\r\n3.  You cannot use the name of the IJG or The libjpeg-turbo Project or the\r\n    contributors thereof in advertising, publicity, etc.\r\n\r\n    **Origin**\r\n    - IJG License\r\n    - Clause 3 of the Modified BSD License\r\n\r\n4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be\r\n    free of defects, nor do we accept any liability for undesirable\r\n    consequences resulting from your use of the software.\r\n\r\n    **Origin**\r\n    - IJG License\r\n    - Modified BSD License\r\n    - zlib License\r\n\r\n\r\nThe Modified (3-clause) BSD License\r\n===================================\r\n\r\nCopyright (C)2009-2024 D. R. Commander.  All Rights Reserved.<br>\r\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions are met:\r\n\r\n- Redistributions of source code must retain the above copyright notice,\r\n  this list of conditions and the following disclaimer.\r\n- Redistributions in binary form must reproduce the above copyright notice,\r\n  this list of conditions and the following disclaimer in the documentation\r\n  and/or other materials provided with the distribution.\r\n- Neither the name of the libjpeg-turbo Project nor the names of its\r\n  contributors may be used to endorse or promote products derived from this\r\n  software without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\r\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\nPOSSIBILITY OF SUCH DAMAGE.\r\n\r\n\r\nWhy Two Licenses?\r\n=================\r\n\r\nThe zlib License could have been used instead of the Modified (3-clause) BSD\r\nLicense, and since the IJG License effectively subsumes the distribution\r\nconditions of the zlib License, this would have effectively placed\r\nlibjpeg-turbo binary distributions under the IJG License.  However, the IJG\r\nLicense specifically refers to the Independent JPEG Group and does not extend\r\nattribution and endorsement protections to other entities.  Thus, it was\r\ndesirable to choose a license that granted us the same protections for new code\r\nthat were granted to the IJG for code derived from their software.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/libopenjpeg.txt",
    "content": "/*\n * The copyright in this software is being made available under the 2-clauses\n * BSD License, included below. This software may be subject to other third\n * party and contributor rights, including patent rights, and no such rights\n * are granted under this license.\n *\n * Copyright (c) 2005, Herve Drolon, FreeImage Team\n * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR\n * Copyright (c) 2012, CS Systemes d'Information, France\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/libpng.txt",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\r\n=========================================\r\n\r\nPNG Reference Library License version 2\r\n---------------------------------------\r\n\r\n * Copyright (c) 1995-2019 The PNG Reference Library Authors.\r\n * Copyright (c) 2018-2019 Cosmin Truta.\r\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\r\n * Copyright (c) 1996-1997 Andreas Dilger.\r\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\r\n\r\nThe software is supplied \"as is\", without warranty of any kind,\r\nexpress or implied, including, without limitation, the warranties\r\nof merchantability, fitness for a particular purpose, title, and\r\nnon-infringement.  In no event shall the Copyright owners, or\r\nanyone distributing the software, be liable for any damages or\r\nother liability, whether in contract, tort or otherwise, arising\r\nfrom, out of, or in connection with the software, or the use or\r\nother dealings in the software, even if advised of the possibility\r\nof such damage.\r\n\r\nPermission is hereby granted to use, copy, modify, and distribute\r\nthis software, or portions hereof, for any purpose, without fee,\r\nsubject to the following restrictions:\r\n\r\n 1. The origin of this software must not be misrepresented; you\r\n    must not claim that you wrote the original software.  If you\r\n    use this software in a product, an acknowledgment in the product\r\n    documentation would be appreciated, but is not required.\r\n\r\n 2. Altered source versions must be plainly marked as such, and must\r\n    not be misrepresented as being the original software.\r\n\r\n 3. This Copyright notice may not be removed or altered from any\r\n    source or altered source distribution.\r\n\r\n\r\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\r\n-----------------------------------------------------------------------\r\n\r\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\r\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\r\nderived from libpng-1.0.6, and are distributed according to the same\r\ndisclaimer and license as libpng-1.0.6 with the following individuals\r\nadded to the list of Contributing Authors:\r\n\r\n    Simon-Pierre Cadieux\r\n    Eric S. Raymond\r\n    Mans Rullgard\r\n    Cosmin Truta\r\n    Gilles Vollant\r\n    James Yu\r\n    Mandar Sahastrabuddhe\r\n    Google Inc.\r\n    Vadim Barkov\r\n\r\nand with the following additions to the disclaimer:\r\n\r\n    There is no warranty against interference with your enjoyment of\r\n    the library or against infringement.  There is no warranty that our\r\n    efforts or the library will fulfill any of your particular purposes\r\n    or needs.  This library is provided with all faults, and the entire\r\n    risk of satisfactory quality, performance, accuracy, and effort is\r\n    with the user.\r\n\r\nSome files in the \"contrib\" directory and some configure-generated\r\nfiles that are distributed with libpng have other copyright owners, and\r\nare released under other open source licenses.\r\n\r\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\r\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\r\nlibpng-0.96, and are distributed according to the same disclaimer and\r\nlicense as libpng-0.96, with the following individuals added to the\r\nlist of Contributing Authors:\r\n\r\n    Tom Lane\r\n    Glenn Randers-Pehrson\r\n    Willem van Schaik\r\n\r\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\r\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\r\nand are distributed according to the same disclaimer and license as\r\nlibpng-0.88, with the following individuals added to the list of\r\nContributing Authors:\r\n\r\n    John Bowler\r\n    Kevin Bracey\r\n    Sam Bushell\r\n    Magnus Holmgren\r\n    Greg Roelofs\r\n    Tom Tanner\r\n\r\nSome files in the \"scripts\" directory have other copyright owners,\r\nbut are released under this license.\r\n\r\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\r\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\r\n\r\nFor the purposes of this copyright and license, \"Contributing Authors\"\r\nis defined as the following set of individuals:\r\n\r\n    Andreas Dilger\r\n    Dave Martindale\r\n    Guy Eric Schalnat\r\n    Paul Schmidt\r\n    Tim Wegner\r\n\r\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\r\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\r\nimplied, including, without limitation, the warranties of\r\nmerchantability and of fitness for any purpose.  The Contributing\r\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\r\nincidental, special, exemplary, or consequential damages, which may\r\nresult from the use of the PNG Reference Library, even if advised of\r\nthe possibility of such damage.\r\n\r\nPermission is hereby granted to use, copy, modify, and distribute this\r\nsource code, or portions hereof, for any purpose, without fee, subject\r\nto the following restrictions:\r\n\r\n 1. The origin of this source code must not be misrepresented.\r\n\r\n 2. Altered versions must be plainly marked as such and must not\r\n    be misrepresented as being the original source.\r\n\r\n 3. This Copyright notice may not be removed or altered from any\r\n    source or altered source distribution.\r\n\r\nThe Contributing Authors and Group 42, Inc. specifically permit,\r\nwithout fee, and encourage the use of this source code as a component\r\nto supporting the PNG file format in commercial products.  If you use\r\nthis source code in a product, acknowledgment is not required but would\r\nbe appreciated.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/libtiff.txt",
    "content": "Copyright (c) 1988-1997 Sam Leffler\nCopyright (c) 1991-1997 Silicon Graphics, Inc.\n\nPermission to use, copy, modify, distribute, and sell this software and\nits documentation for any purpose is hereby granted without fee, provided\nthat (i) the above copyright notices and this permission notice appear in\nall copies of the software and related documentation, and (ii) the names of\nSam Leffler and Silicon Graphics may not be used in any advertising or\npublicity relating to the software without the specific, prior written\npermission of Sam Leffler and Silicon Graphics.\n\nTHE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\nEXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\nWARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n\nIN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR\nANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF\nLIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\nOF THIS SOFTWARE.\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/llvm-libc.txt",
    "content": "==============================================================================\r\nThe LLVM Project is under the Apache License v2.0 with LLVM Exceptions:\r\n==============================================================================\r\n\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n    1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n    2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n    3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n    4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n    5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n    6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n    7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n    8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n    9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n    END OF TERMS AND CONDITIONS\r\n\r\n    APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n    Copyright [yyyy] [name of copyright owner]\r\n\r\n    Licensed under the Apache License, Version 2.0 (the \"License\");\r\n    you may not use this file except in compliance with the License.\r\n    You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n    Unless required by applicable law or agreed to in writing, software\r\n    distributed under the License is distributed on an \"AS IS\" BASIS,\r\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n    See the License for the specific language governing permissions and\r\n    limitations under the License.\r\n\r\n\r\n---- LLVM Exceptions to the Apache 2.0 License ----\r\n\r\nAs an exception, if, as a result of your compiling your source code, portions\r\nof this Software are embedded into an Object form of such source code, you\r\nmay redistribute such embedded portions in such Object form without complying\r\nwith the conditions of Sections 4(a), 4(b) and 4(d) of the License.\r\n\r\nIn addition, if you combine or link compiled forms of this Software with\r\nsoftware that is licensed under the GPLv2 (\"Combined Software\") and if a\r\ncourt of competent jurisdiction determines that the patent provision (Section\r\n3), the indemnity provision (Section 9) or other Section of the License\r\nconflicts with the conditions of the GPLv2, you may retroactively and\r\nprospectively choose to deem waived or otherwise exclude such Section(s) of\r\nthe License, but only in their entirety and only with respect to the Combined\r\nSoftware.\r\n\r\n==============================================================================\r\nSoftware from third parties included in the LLVM Project:\r\n==============================================================================\r\nThe LLVM Project contains third party software which is under different license\r\nterms. All such code will be identified clearly using at least one of two\r\nmechanisms:\r\n1) It will be in a separate directory tree with its own `LICENSE.txt` or\r\n   `LICENSE` file at the top containing the specific license and restrictions\r\n   which apply to that software, or\r\n2) It will contain specific license and restriction terms at the top of every\r\n   file.\r\n\r\n==============================================================================\r\nLegacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):\r\n==============================================================================\r\nUniversity of Illinois/NCSA\r\nOpen Source License\r\n\r\nCopyright (c) 2007-2019 University of Illinois at Urbana-Champaign.\r\nAll rights reserved.\r\n\r\nDeveloped by:\r\n\r\n    LLVM Team\r\n\r\n    University of Illinois at Urbana-Champaign\r\n\r\n    http://llvm.org\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of\r\nthis software and associated documentation files (the \"Software\"), to deal with\r\nthe Software without restriction, including without limitation the rights to\r\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\r\nof the Software, and to permit persons to whom the Software is furnished to do\r\nso, subject to the following conditions:\r\n\r\n    * Redistributions of source code must retain the above copyright notice,\r\n      this list of conditions and the following disclaimers.\r\n\r\n    * Redistributions in binary form must reproduce the above copyright notice,\r\n      this list of conditions and the following disclaimers in the\r\n      documentation and/or other materials provided with the distribution.\r\n\r\n    * Neither the names of the LLVM Team, University of Illinois at\r\n      Urbana-Champaign, nor the names of its contributors may be used to\r\n      endorse or promote products derived from this Software without specific\r\n      prior written permission.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\r\nCONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/pdfium.txt",
    "content": "Copyright 2014 The PDFium Authors\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/simdutf.txt",
    "content": "Copyright 2021 The simdutf authors\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of\r\nthis software and associated documentation files (the \"Software\"), to deal in\r\nthe Software without restriction, including without limitation the rights to\r\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\nthe Software, and to permit persons to whom the Software is furnished to do so,\r\nsubject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n"
  },
  {
    "path": "external/pdfium/windows-x64/licenses/zlib.txt",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.3.1, January 22nd, 2024\n\n  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n"
  },
  {
    "path": "external/pugixml/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5...3.30)\n\n# Policy configuration; this *MUST* be specified before project is defined\nif(POLICY CMP0091)\n    cmake_policy(SET CMP0091 NEW) # Enables use of MSVC_RUNTIME_LIBRARY\nendif()\n\nproject(pugixml VERSION 1.15 LANGUAGES CXX)\n\ninclude(CMakePackageConfigHelpers)\ninclude(CMakeDependentOption)\ninclude(GNUInstallDirs)\n\ncmake_dependent_option(PUGIXML_USE_VERSIONED_LIBDIR\n  \"Use a private subdirectory to install the headers and libraries\" OFF\n  \"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR\" OFF)\n\ncmake_dependent_option(PUGIXML_USE_POSTFIX\n  \"Use separate postfix for each configuration to make sure you can install multiple build outputs\" OFF\n  \"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR\" OFF)\n\ncmake_dependent_option(PUGIXML_STATIC_CRT\n  \"Use static MSVC RT libraries\" OFF\n  \"MSVC\" OFF)\n\ncmake_dependent_option(PUGIXML_BUILD_TESTS\n  \"Build pugixml tests\" OFF\n  \"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR\" OFF)\n\n# Custom build defines\nset(PUGIXML_BUILD_DEFINES CACHE STRING \"Build defines for custom options\")\nseparate_arguments(PUGIXML_BUILD_DEFINES)\n\n# Technically not needed for this file. This is builtin CMAKE global variable.\noption(BUILD_SHARED_LIBS \"Build shared instead of static library\" OFF)\n\n# Expose option to build PUGIXML as static as well when the global BUILD_SHARED_LIBS variable is set\ncmake_dependent_option(PUGIXML_BUILD_SHARED_AND_STATIC_LIBS\n  \"Build both shared and static libraries\" OFF\n  \"BUILD_SHARED_LIBS\" OFF)\n\n# Expose options from the pugiconfig.hpp\noption(PUGIXML_WCHAR_MODE \"Enable wchar_t mode\" OFF)\noption(PUGIXML_COMPACT \"Enable compact mode\" OFF)\noption(PUGIXML_INSTALL \"Enable installation rules\" ON)\n\n# Advanced options from pugiconfig.hpp\noption(PUGIXML_NO_XPATH \"Disable XPath\" OFF)\noption(PUGIXML_NO_STL \"Disable STL\" OFF)\noption(PUGIXML_NO_EXCEPTIONS \"Disable Exceptions\" OFF)\nmark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS)\n\nif (APPLE)\n  option(PUGIXML_BUILD_APPLE_FRAMEWORK \"Build as Apple Frameworks\" OFF)\nendif()\n\nset(PUGIXML_PUBLIC_DEFINITIONS\n  $<$<BOOL:${PUGIXML_WCHAR_MODE}>:PUGIXML_WCHAR_MODE>\n  $<$<BOOL:${PUGIXML_COMPACT}>:PUGIXML_COMPACT>\n  $<$<BOOL:${PUGIXML_NO_XPATH}>:PUGIXML_NO_XPATH>\n  $<$<BOOL:${PUGIXML_NO_STL}>:PUGIXML_NO_STL>\n  $<$<BOOL:${PUGIXML_NO_EXCEPTIONS}>:PUGIXML_NO_EXCEPTIONS>\n)\n\n# This is used to backport a CMake 3.15 feature, but is also forwards compatible\nif (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)\n  set(CMAKE_MSVC_RUNTIME_LIBRARY\n    MultiThreaded$<$<CONFIG:Debug>:Debug>$<$<NOT:$<BOOL:${PUGIXML_STATIC_CRT}>>:DLL>)\nendif()\n\n# Set the default C++ standard to C++17 if not set; CMake will automatically downgrade this if the compiler does not support it\n# When CMAKE_CXX_STANDARD_REQUIRED is set, we fall back to C++11 to avoid breaking older compilers\nif (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED AND NOT DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_VERSION VERSION_LESS 3.8)\n\n  set(CMAKE_CXX_STANDARD 17)\n  set(CMAKE_CXX_STANDARD_REQUIRED OFF)\nelseif (NOT DEFINED CMAKE_CXX_STANDARD)\n  set(CMAKE_CXX_STANDARD 11)\nendif()\n\nif (PUGIXML_USE_POSTFIX)\n  set(CMAKE_RELWITHDEBINFO_POSTFIX _r)\n  set(CMAKE_MINSIZEREL_POSTFIX _m)\n  set(CMAKE_DEBUG_POSTFIX _d)\nendif()\n\nif (CMAKE_VERSION VERSION_LESS 3.15)\n  set(msvc-rt $<TARGET_PROPERTY:MSVC_RUNTIME_LIBRARY>)\n\n  set(msvc-rt-mtd-shared $<STREQUAL:${msvc-rt},MultiThreadedDebugDLL>)\n  set(msvc-rt-mtd-static $<STREQUAL:${msvc-rt},MultiThreadedDebug>)\n  set(msvc-rt-mt-shared $<STREQUAL:${msvc-rt},MultiThreadedDLL>)\n  set(msvc-rt-mt-static $<STREQUAL:${msvc-rt},MultiThreaded>)\n  unset(msvc-rt)\n\n  set(msvc-rt-mtd-shared $<${msvc-rt-mtd-shared}:-MDd>)\n  set(msvc-rt-mtd-static $<${msvc-rt-mtd-static}:-MTd>)\n  set(msvc-rt-mt-shared $<${msvc-rt-mt-shared}:-MD>)\n  set(msvc-rt-mt-static $<${msvc-rt-mt-static}:-MT>)\nendif()\n\nset(versioned-dir $<$<BOOL:${PUGIXML_USE_VERSIONED_LIBDIR}>:/pugixml-${PROJECT_VERSION}>)\n\nset(libs)\n\nif (BUILD_SHARED_LIBS)\n  add_library(pugixml-shared SHARED\n    ${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc\n    ${PROJECT_SOURCE_DIR}/src/pugixml.cpp)\n  add_library(pugixml::shared ALIAS pugixml-shared)\n  list(APPEND libs pugixml-shared)\n  string(CONCAT pugixml.msvc $<OR:\n    $<STREQUAL:${CMAKE_CXX_COMPILER_FRONTEND_VARIANT},MSVC>,\n    $<CXX_COMPILER_ID:MSVC>\n  >)\n\n  set_property(TARGET pugixml-shared PROPERTY EXPORT_NAME shared)\n  target_include_directories(pugixml-shared\n    PUBLIC\n      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)\n  target_compile_definitions(pugixml-shared\n    PUBLIC\n      ${PUGIXML_BUILD_DEFINES}\n      ${PUGIXML_PUBLIC_DEFINITIONS}\n    PRIVATE\n      PUGIXML_API=$<IF:${pugixml.msvc},__declspec\\(dllexport\\),__attribute__\\(\\(visibility\\(\"default\"\\)\\)\\)>\n    )\n  target_compile_options(pugixml-shared\n    PRIVATE\n      ${msvc-rt-mtd-shared}\n      ${msvc-rt-mtd-static}\n      ${msvc-rt-mt-shared}\n      ${msvc-rt-mt-static})\nendif()\n\nif (NOT BUILD_SHARED_LIBS OR PUGIXML_BUILD_SHARED_AND_STATIC_LIBS)\n  add_library(pugixml-static STATIC\n    ${PROJECT_SOURCE_DIR}/src/pugixml.cpp)\n  add_library(pugixml::static ALIAS pugixml-static)\n  list(APPEND libs pugixml-static)\n\n  set_property(TARGET pugixml-static PROPERTY EXPORT_NAME static)\n  target_include_directories(pugixml-static\n    PUBLIC\n      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>)\n  target_compile_definitions(pugixml-static\n    PUBLIC\n      ${PUGIXML_BUILD_DEFINES}\n      ${PUGIXML_PUBLIC_DEFINITIONS})\n  target_compile_options(pugixml-static\n    PRIVATE\n      ${msvc-rt-mtd-shared}\n      ${msvc-rt-mtd-static}\n      ${msvc-rt-mt-shared}\n      ${msvc-rt-mt-static})\nendif()\n\nif (BUILD_SHARED_LIBS)\n  set(pugixml-alias pugixml-shared)\nelse()\n  set(pugixml-alias pugixml-static)\nendif()\nadd_library(pugixml INTERFACE)\ntarget_link_libraries(pugixml INTERFACE ${pugixml-alias})\nadd_library(pugixml::pugixml ALIAS pugixml)\n\nset_target_properties(${libs}\n  PROPERTIES\n    MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}\n    EXCLUDE_FROM_ALL ON\n    POSITION_INDEPENDENT_CODE ON\n    SOVERSION ${PROJECT_VERSION_MAJOR}\n    VERSION ${PROJECT_VERSION}\n    OUTPUT_NAME pugixml)\n\nset_target_properties(${libs}\n  PROPERTIES\n    EXCLUDE_FROM_ALL OFF)\nset(install-targets pugixml ${libs})\n\nif (PUGIXML_BUILD_APPLE_FRAMEWORK)\n  set_target_properties(${libs} PROPERTIES\n    FRAMEWORK TRUE\n    FRAMEWORK_VERSION ${PROJECT_VERSION}\n    XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.zeux.pugixml\n    MACOSX_FRAMEWORK_IDENTIFIER com.zeux.pugixml\n    MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION}\n    MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR})\nendif()\n\nconfigure_package_config_file(\n  \"${PROJECT_SOURCE_DIR}/scripts/pugixml-config.cmake.in\"\n  \"${PROJECT_BINARY_DIR}/pugixml-config.cmake\"\n  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}\n  NO_CHECK_REQUIRED_COMPONENTS_MACRO\n  NO_SET_AND_CHECK_MACRO)\n\nwrite_basic_package_version_file(\n  \"${PROJECT_BINARY_DIR}/pugixml-config-version.cmake\"\n  COMPATIBILITY SameMajorVersion)\n\nif (PUGIXML_USE_POSTFIX)\n  if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)\n    set(LIB_POSTFIX ${CMAKE_RELWITHDEBINFO_POSTFIX})\n  elseif(CMAKE_BUILD_TYPE MATCHES MinSizeRel)\n    set(LIB_POSTFIX ${CMAKE_MINSIZEREL_POSTFIX})\n  elseif(CMAKE_BUILD_TYPE MATCHES Debug)\n    set(LIB_POSTFIX ${CMAKE_DEBUG_POSTFIX})\n  endif()\nendif()\n\n# Handle both relative and absolute paths (e.g. NixOS) for a relocatable package\nif(IS_ABSOLUTE \"${CMAKE_INSTALL_INCLUDEDIR}\")\n  set(PUGIXML_PC_INCLUDEDIR \"${CMAKE_INSTALL_INCLUDEDIR}\")\nelse()\n  set(PUGIXML_PC_INCLUDEDIR \"\\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\")\nendif()\nif(IS_ABSOLUTE \"${CMAKE_INSTALL_LIBDIR}\")\n  set(PUGIXML_PC_LIBDIR \"${CMAKE_INSTALL_LIBDIR}\")\nelse()\n  set(PUGIXML_PC_LIBDIR \"\\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}\")\nendif()\nconfigure_file(scripts/pugixml.pc.in pugixml.pc @ONLY)\n\nexport(TARGETS ${install-targets}\n  NAMESPACE pugixml::\n  FILE pugixml-targets.cmake)\n\nif(PUGIXML_INSTALL)\n  if (NOT DEFINED PUGIXML_RUNTIME_COMPONENT)\n    set(PUGIXML_RUNTIME_COMPONENT Runtime)\n  endif()\n\n  if (NOT DEFINED PUGIXML_LIBRARY_COMPONENT)\n    set(PUGIXML_LIBRARY_COMPONENT Library)\n  endif()\n\n  if (NOT DEFINED PUGIXML_DEVELOPMENT_COMPONENT)\n    set(PUGIXML_DEVELOPMENT_COMPONENT Development)\n  endif()\n\n  set(namelink-component)\n  if (NOT CMAKE_VERSION VERSION_LESS 3.12)\n    set(namelink-component NAMELINK_COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})\n  endif()\n  install(TARGETS ${install-targets}\n    EXPORT pugixml-targets\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${PUGIXML_RUNTIME_COMPONENT}\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_LIBRARY_COMPONENT} ${namelink-component}\n    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}\n    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir}\n    FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime OPTIONAL)\n\n  install(EXPORT pugixml-targets\n    NAMESPACE pugixml::\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})\n\n  install(FILES\n    \"${PROJECT_BINARY_DIR}/pugixml-config-version.cmake\"\n    \"${PROJECT_BINARY_DIR}/pugixml-config.cmake\"\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})\n\n  install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc\n    DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})\n\n  install(\n    FILES\n      \"${PROJECT_SOURCE_DIR}/src/pugiconfig.hpp\"\n      \"${PROJECT_SOURCE_DIR}/src/pugixml.hpp\"\n    DESTINATION\n      ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT})\nendif()\n\nif (PUGIXML_BUILD_TESTS)\n  include(CTest)\n  set(fuzz-pattern \"tests/fuzz_*.cpp\")\n  set(test-pattern \"tests/*.cpp\")\n  if (CMAKE_VERSION VERSION_GREATER 3.11)\n    list(INSERT fuzz-pattern 0 CONFIGURE_DEPENDS)\n    list(INSERT test-pattern 0 CONFIGURE_DEPENDS)\n  endif()\n  file(GLOB test-sources ${test-pattern})\n  file(GLOB fuzz-sources ${fuzz-pattern})\n  list(REMOVE_ITEM test-sources ${fuzz-sources})\n\n  add_custom_target(check\n    COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure)\n\n  add_executable(pugixml-check ${test-sources})\n  add_test(NAME pugixml::test\n    COMMAND pugixml-check\n    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})\n  add_dependencies(check pugixml-check)\n  target_link_libraries(pugixml-check\n    PRIVATE\n      pugixml::pugixml)\nendif()\n"
  },
  {
    "path": "external/pugixml/LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pugixml/docs/manual.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"generator\" content=\"Asciidoctor 2.0.20\">\n<meta name=\"author\" content=\"website, repository\">\n<title>pugixml 1.15 manual</title>\n<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700\">\n<style>\n/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */\n/* Uncomment the following line when using as a custom stylesheet */\n/* @import \"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700\"; */\nhtml{font-family:sans-serif;-webkit-text-size-adjust:100%}\na{background:none}\na:focus{outline:thin dotted}\na:active,a:hover{outline:0}\nh1{font-size:2em;margin:.67em 0}\nb,strong{font-weight:bold}\nabbr{font-size:.9em}\nabbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}\ndfn{font-style:italic}\nhr{height:0}\nmark{background:#ff0;color:#000}\ncode,kbd,pre,samp{font-family:monospace;font-size:1em}\npre{white-space:pre-wrap}\nq{quotes:\"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\"}\nsmall{font-size:80%}\nsub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}\nsup{top:-.5em}\nsub{bottom:-.25em}\nimg{border:0}\nsvg:not(:root){overflow:hidden}\nfigure{margin:0}\naudio,video{display:inline-block}\naudio:not([controls]){display:none;height:0}\nfieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}\nlegend{border:0;padding:0}\nbutton,input,select,textarea{font-family:inherit;font-size:100%;margin:0}\nbutton,input{line-height:normal}\nbutton,select{text-transform:none}\nbutton,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}\nbutton[disabled],html input[disabled]{cursor:default}\ninput[type=checkbox],input[type=radio]{padding:0}\nbutton::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}\ntextarea{overflow:auto;vertical-align:top}\ntable{border-collapse:collapse;border-spacing:0}\n*,::before,::after{box-sizing:border-box}\nhtml,body{font-size:100%}\nbody{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:\"Noto Serif\",\"DejaVu Serif\",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}\na:hover{cursor:pointer}\nimg,object,embed{max-width:100%;height:auto}\nobject,embed{height:100%}\nimg{-ms-interpolation-mode:bicubic}\n.left{float:left!important}\n.right{float:right!important}\n.text-left{text-align:left!important}\n.text-right{text-align:right!important}\n.text-center{text-align:center!important}\n.text-justify{text-align:justify!important}\n.hide{display:none}\nimg,object,svg{display:inline-block;vertical-align:middle}\ntextarea{height:auto;min-height:50px}\nselect{width:100%}\n.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}\ndiv,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}\na{color:#2156a5;text-decoration:underline;line-height:inherit}\na:hover,a:focus{color:#1d4b8f}\na img{border:0}\np{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}\np aside{font-size:.875em;line-height:1.35;font-style:italic}\nh1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}\nh1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}\nh1{font-size:2.125em}\nh2{font-size:1.6875em}\nh3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}\nh4,h5{font-size:1.125em}\nh6{font-size:1em}\nhr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}\nem,i{font-style:italic;line-height:inherit}\nstrong,b{font-weight:bold;line-height:inherit}\nsmall{font-size:60%;line-height:inherit}\ncode{font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;font-weight:400;color:rgba(0,0,0,.9)}\nul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}\nul,ol{margin-left:1.5em}\nul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}\nul.circle{list-style-type:circle}\nul.disc{list-style-type:disc}\nul.square{list-style-type:square}\nul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}\nol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}\ndl dt{margin-bottom:.3125em;font-weight:bold}\ndl dd{margin-bottom:1.25em}\nblockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}\nblockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}\n@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}\nh1{font-size:2.75em}\nh2{font-size:2.3125em}\nh3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}\nh4{font-size:1.4375em}}\ntable{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}\ntable thead,table tfoot{background:#f7f8f7}\ntable thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}\ntable tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}\ntable tr.even,table tr.alt{background:#f8f8f7}\ntable thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}\nh1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}\nh1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}\n.center{margin-left:auto;margin-right:auto}\n.stretch{width:100%}\n.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:\" \";display:table}\n.clearfix::after,.float-group::after{clear:both}\n:not(pre).nobreak{word-wrap:normal}\n:not(pre).nowrap{white-space:nowrap}\n:not(pre).pre-wrap{white-space:pre-wrap}\n:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}\npre{color:rgba(0,0,0,.9);font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;line-height:1.45;text-rendering:optimizeSpeed}\npre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}\npre>code{display:block}\npre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}\nem em{font-style:normal}\nstrong strong{font-weight:400}\n.keyseq{color:rgba(51,51,51,.8)}\nkbd{font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}\n.keyseq kbd:first-child{margin-left:0}\n.keyseq kbd:last-child{margin-right:0}\n.menuseq,.menuref{color:#000}\n.menuseq b:not(.caret),.menuref{font-weight:inherit}\n.menuseq{word-spacing:-.02em}\n.menuseq b.caret{font-size:1.25em;line-height:.8}\n.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}\nb.button::before,b.button::after{position:relative;top:-1px;font-weight:400}\nb.button::before{content:\"[\";padding:0 3px 0 2px}\nb.button::after{content:\"]\";padding:0 2px 0 3px}\np a>code:hover{color:rgba(0,0,0,.9)}\n#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}\n#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:\" \";display:table}\n#header::after,#content::after,#footnotes::after,#footer::after{clear:both}\n#content{margin-top:1.25em}\n#content::before{content:none}\n#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}\n#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}\n#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}\n#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}\n#header .details span:first-child{margin-left:-.125em}\n#header .details span.email a{color:rgba(0,0,0,.85)}\n#header .details br{display:none}\n#header .details br+span::before{content:\"\\00a0\\2013\\00a0\"}\n#header .details br+span.author::before{content:\"\\00a0\\22c5\\00a0\";color:rgba(0,0,0,.85)}\n#header .details br+span#revremark::before{content:\"\\00a0|\\00a0\"}\n#header #revnumber{text-transform:capitalize}\n#header #revnumber::after{content:\"\\00a0\"}\n#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}\n#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}\n#toc>ul{margin-left:.125em}\n#toc ul.sectlevel0>li>a{font-style:italic}\n#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}\n#toc ul{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;list-style-type:none}\n#toc li{line-height:1.3334;margin-top:.3334em}\n#toc a{text-decoration:none}\n#toc a:active{text-decoration:underline}\n#toctitle{color:#7a2518;font-size:1.2em}\n@media screen and (min-width:768px){#toctitle{font-size:1.375em}\nbody.toc2{padding-left:15em;padding-right:0}\n#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}\n#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}\n#toc.toc2>ul{font-size:.9em;margin-bottom:0}\n#toc.toc2 ul ul{margin-left:0;padding-left:1em}\n#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}\nbody.toc2.toc-right{padding-left:0;padding-right:15em}\nbody.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}\n@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}\n#toc.toc2{width:20em}\n#toc.toc2 #toctitle{font-size:1.375em}\n#toc.toc2>ul{font-size:.95em}\n#toc.toc2 ul ul{padding-left:1.25em}\nbody.toc2.toc-right{padding-left:0;padding-right:20em}}\n#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}\n#content #toc>:first-child{margin-top:0}\n#content #toc>:last-child{margin-bottom:0}\n#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}\n#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}\n#content{margin-bottom:.625em}\n.sect1{padding-bottom:.625em}\n@media screen and (min-width:768px){#content{margin-bottom:1.25em}\n.sect1{padding-bottom:1.25em}}\n.sect1:last-child{padding-bottom:0}\n.sect1+.sect1{border-top:1px solid #e7e7e9}\n#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}\n#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:\"\\00A7\";font-size:.85em;display:block;padding-top:.1em}\n#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}\n#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}\n#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}\ndetails,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}\ndetails{margin-left:1.25rem}\ndetails>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}\ndetails>summary::-webkit-details-marker{display:none}\ndetails>summary::before{content:\"\";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}\ndetails[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}\ndetails>summary::after{content:\"\";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}\n.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:\"Noto Serif\",\"DejaVu Serif\",serif;font-size:1rem;font-style:italic}\ntable.tableblock.fit-content>caption.title{white-space:nowrap;width:0}\n.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}\n.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}\n.admonitionblock>table td.icon{text-align:center;width:80px}\n.admonitionblock>table td.icon img{max-width:none}\n.admonitionblock>table td.icon .title{font-weight:bold;font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;text-transform:uppercase}\n.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}\n.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}\n.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}\n.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}\n.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}\n.exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}\n.exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}\n.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}\n@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}\n@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}\n.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^=\"highlight \"]{background:#f7f7f8}\n.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}\n.listingblock>.content{position:relative}\n.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}\n.listingblock:hover code[data-lang]::before{display:block}\n.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}\n.listingblock.terminal pre .command:not([data-prompt])::before{content:\"$\"}\n.listingblock pre.highlightjs{padding:0}\n.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}\n.listingblock pre.prettyprint{border-width:0}\n.prettyprint{background:#f7f7f8}\npre.prettyprint .linenums{line-height:1.45;margin-left:2em}\npre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}\npre.prettyprint li code[data-lang]::before{opacity:1}\npre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}\ntable.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}\ntable.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}\ntable.linenotable td.code{padding-left:.75em}\ntable.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}\npre.pygments span.linenos{display:inline-block;margin-right:.75em}\n.quoteblock{margin:0 1em 1.25em 1.5em;display:table}\n.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}\n.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}\n.quoteblock blockquote{margin:0;padding:0;border:0}\n.quoteblock blockquote::before{content:\"\\201c\";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}\n.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}\n.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}\n.verseblock{margin:0 1em 1.25em}\n.verseblock pre{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}\n.verseblock pre strong{font-weight:400}\n.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}\n.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}\n.quoteblock .attribution br,.verseblock .attribution br{display:none}\n.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}\n.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}\n.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}\n.quoteblock.abstract{margin:0 1em 1.25em;display:block}\n.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}\n.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}\n.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}\n.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}\n.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}\np.tableblock:last-child{margin-bottom:0}\ntd.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}\ntd.tableblock>.content>:last-child{margin-bottom:-1.25em}\ntable.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}\ntable.grid-all>*>tr>*{border-width:1px}\ntable.grid-cols>*>tr>*{border-width:0 1px}\ntable.grid-rows>*>tr>*{border-width:1px 0}\ntable.frame-all{border-width:1px}\ntable.frame-ends{border-width:1px 0}\ntable.frame-sides{border-width:0 1px}\ntable.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}\ntable.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}\ntable.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}\ntable.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}\ntable.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}\nth.halign-left,td.halign-left{text-align:left}\nth.halign-right,td.halign-right{text-align:right}\nth.halign-center,td.halign-center{text-align:center}\nth.valign-top,td.valign-top{vertical-align:top}\nth.valign-bottom,td.valign-bottom{vertical-align:bottom}\nth.valign-middle,td.valign-middle{vertical-align:middle}\ntable thead th,table tfoot th{font-weight:bold}\ntbody tr th{background:#f7f8f7}\ntbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}\np.tableblock>code:only-child{background:none;padding:0}\np.tableblock{font-size:1em}\nol{margin-left:1.75em}\nul li ol{margin-left:1.5em}\ndl dd{margin-left:1.125em}\ndl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}\nli p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}\nul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}\nul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}\nul.unstyled,ol.unstyled{margin-left:0}\nli>p:empty:only-child::before{content:\"\";display:inline-block}\nul.checklist>li>p:first-child{margin-left:-1em}\nul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}\nul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}\nul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}\nul.inline>li{margin-left:1.25em}\n.unstyled dl dt{font-weight:400;font-style:normal}\nol.arabic{list-style-type:decimal}\nol.decimal{list-style-type:decimal-leading-zero}\nol.loweralpha{list-style-type:lower-alpha}\nol.upperalpha{list-style-type:upper-alpha}\nol.lowerroman{list-style-type:lower-roman}\nol.upperroman{list-style-type:upper-roman}\nol.lowergreek{list-style-type:lower-greek}\n.hdlist>table,.colist>table{border:0;background:none}\n.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}\ntd.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}\ntd.hdlist1{font-weight:bold;padding-bottom:1.25em}\ntd.hdlist2{word-wrap:anywhere}\n.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}\n.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}\n.colist td:not([class]):first-child img{max-width:none}\n.colist td:not([class]):last-child{padding:.25em 0}\n.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}\n.imageblock.left{margin:.25em .625em 1.25em 0}\n.imageblock.right{margin:.25em 0 1.25em .625em}\n.imageblock>.title{margin-bottom:0}\n.imageblock.thumb,.imageblock.th{border-width:6px}\n.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}\n.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}\n.image.left{margin-right:.625em}\n.image.right{margin-left:.625em}\na.image{text-decoration:none;display:inline-block}\na.image object{pointer-events:none}\nsup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}\nsup.footnote a,sup.footnoteref a{text-decoration:none}\nsup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}\n#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}\n#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}\n#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}\n#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}\n#footnotes .footnote:last-of-type{margin-bottom:0}\n#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}\ndiv.unbreakable{page-break-inside:avoid}\n.big{font-size:larger}\n.small{font-size:smaller}\n.underline{text-decoration:underline}\n.overline{text-decoration:overline}\n.line-through{text-decoration:line-through}\n.aqua{color:#00bfbf}\n.aqua-background{background:#00fafa}\n.black{color:#000}\n.black-background{background:#000}\n.blue{color:#0000bf}\n.blue-background{background:#0000fa}\n.fuchsia{color:#bf00bf}\n.fuchsia-background{background:#fa00fa}\n.gray{color:#606060}\n.gray-background{background:#7d7d7d}\n.green{color:#006000}\n.green-background{background:#007d00}\n.lime{color:#00bf00}\n.lime-background{background:#00fa00}\n.maroon{color:#600000}\n.maroon-background{background:#7d0000}\n.navy{color:#000060}\n.navy-background{background:#00007d}\n.olive{color:#606000}\n.olive-background{background:#7d7d00}\n.purple{color:#600060}\n.purple-background{background:#7d007d}\n.red{color:#bf0000}\n.red-background{background:#fa0000}\n.silver{color:#909090}\n.silver-background{background:#bcbcbc}\n.teal{color:#006060}\n.teal-background{background:#007d7d}\n.white{color:#bfbfbf}\n.white-background{background:#fafafa}\n.yellow{color:#bfbf00}\n.yellow-background{background:#fafa00}\nspan.icon>.fa{cursor:default}\na span.icon>.fa{cursor:inherit}\n.admonitionblock td.icon [class^=\"fa icon-\"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}\n.admonitionblock td.icon .icon-note::before{content:\"\\f05a\";color:#19407c}\n.admonitionblock td.icon .icon-tip::before{content:\"\\f0eb\";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}\n.admonitionblock td.icon .icon-warning::before{content:\"\\f071\";color:#bf6900}\n.admonitionblock td.icon .icon-caution::before{content:\"\\f06d\";color:#bf3400}\n.admonitionblock td.icon .icon-important::before{content:\"\\f06a\";color:#bf0000}\n.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-style:normal;font-weight:bold}\n.conum[data-value] *{color:#fff!important}\n.conum[data-value]+b{display:none}\n.conum[data-value]::after{content:attr(data-value)}\npre .conum[data-value]{position:relative;top:-.125em}\nb.conum *{color:inherit!important}\n.conum:not([data-value]):empty{display:none}\ndt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}\nh1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}\np strong,td.content strong,div.footnote strong{letter-spacing:-.005em}\np,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}\np{margin-bottom:1.25rem}\n.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}\n.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}\n.print-only{display:none!important}\n@page{margin:1.25cm .75cm}\n@media print{*{box-shadow:none!important;text-shadow:none!important}\nhtml{font-size:80%}\na{color:inherit!important;text-decoration:underline!important}\na.bare,a[href^=\"#\"],a[href^=\"mailto:\"]{text-decoration:none!important}\na[href^=\"http:\"]:not(.bare)::after,a[href^=\"https:\"]:not(.bare)::after{content:\"(\" attr(href) \")\";display:inline-block;font-size:.875em;padding-left:.25em}\nabbr[title]{border-bottom:1px dotted}\nabbr[title]::after{content:\" (\" attr(title) \")\"}\npre,blockquote,tr,img,object,svg{page-break-inside:avoid}\nthead{display:table-header-group}\nsvg{max-width:100%}\np,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}\nh2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}\n#header,#content,#footnotes,#footer{max-width:none}\n#toc,.sidebarblock,.exampleblock>.content{background:none!important}\n#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}\nbody.book #header{text-align:center}\nbody.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}\nbody.book #header .details{border:0!important;display:block;padding:0!important}\nbody.book #header .details span:first-child{margin-left:0!important}\nbody.book #header .details br{display:block}\nbody.book #header .details br+span::before{content:none!important}\nbody.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}\nbody.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}\n.listingblock code[data-lang]::before{display:block}\n#footer{padding:0 .9375em}\n.hide-on-print{display:none!important}\n.print-only{display:block!important}\n.hide-for-print{display:none!important}\n.show-for-print{display:inherit!important}}\n@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}\n.sect1{padding:0!important}\n.sect1+.sect1{border:0}\n#footer{background:none}\n#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}\n@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}\n</style>\n<style>\npre.pygments .hll { background-color: #ffffcc }\npre.pygments { background: #f8f8f8; }\npre.pygments .tok-c { color: #3D7B7B; font-style: italic } /* Comment */\npre.pygments .tok-err { border: 1px solid #FF0000 } /* Error */\npre.pygments .tok-k { color: #008000; font-weight: bold } /* Keyword */\npre.pygments .tok-o { color: #666666 } /* Operator */\npre.pygments .tok-ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\npre.pygments .tok-cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\npre.pygments .tok-cp { color: #9C6500 } /* Comment.Preproc */\npre.pygments .tok-cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\npre.pygments .tok-c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\npre.pygments .tok-cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\npre.pygments .tok-gd { color: #A00000 } /* Generic.Deleted */\npre.pygments .tok-ge { font-style: italic } /* Generic.Emph */\npre.pygments .tok-ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\npre.pygments .tok-gr { color: #E40000 } /* Generic.Error */\npre.pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */\npre.pygments .tok-gi { color: #008400 } /* Generic.Inserted */\npre.pygments .tok-go { color: #717171 } /* Generic.Output */\npre.pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */\npre.pygments .tok-gs { font-weight: bold } /* Generic.Strong */\npre.pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */\npre.pygments .tok-gt { color: #0044DD } /* Generic.Traceback */\npre.pygments .tok-kc { color: #008000; font-weight: bold } /* Keyword.Constant */\npre.pygments .tok-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\npre.pygments .tok-kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\npre.pygments .tok-kp { color: #008000 } /* Keyword.Pseudo */\npre.pygments .tok-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\npre.pygments .tok-kt { color: #B00040 } /* Keyword.Type */\npre.pygments .tok-m { color: #666666 } /* Literal.Number */\npre.pygments .tok-s { color: #BA2121 } /* Literal.String */\npre.pygments .tok-na { color: #687822 } /* Name.Attribute */\npre.pygments .tok-nb { color: #008000 } /* Name.Builtin */\npre.pygments .tok-nc { color: #0000FF; font-weight: bold } /* Name.Class */\npre.pygments .tok-no { color: #880000 } /* Name.Constant */\npre.pygments .tok-nd { color: #AA22FF } /* Name.Decorator */\npre.pygments .tok-ni { color: #717171; font-weight: bold } /* Name.Entity */\npre.pygments .tok-ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\npre.pygments .tok-nf { color: #0000FF } /* Name.Function */\npre.pygments .tok-nl { color: #767600 } /* Name.Label */\npre.pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\npre.pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */\npre.pygments .tok-nv { color: #19177C } /* Name.Variable */\npre.pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\npre.pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */\npre.pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */\npre.pygments .tok-mf { color: #666666 } /* Literal.Number.Float */\npre.pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */\npre.pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */\npre.pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */\npre.pygments .tok-sa { color: #BA2121 } /* Literal.String.Affix */\npre.pygments .tok-sb { color: #BA2121 } /* Literal.String.Backtick */\npre.pygments .tok-sc { color: #BA2121 } /* Literal.String.Char */\npre.pygments .tok-dl { color: #BA2121 } /* Literal.String.Delimiter */\npre.pygments .tok-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\npre.pygments .tok-s2 { color: #BA2121 } /* Literal.String.Double */\npre.pygments .tok-se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\npre.pygments .tok-sh { color: #BA2121 } /* Literal.String.Heredoc */\npre.pygments .tok-si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\npre.pygments .tok-sx { color: #008000 } /* Literal.String.Other */\npre.pygments .tok-sr { color: #A45A77 } /* Literal.String.Regex */\npre.pygments .tok-s1 { color: #BA2121 } /* Literal.String.Single */\npre.pygments .tok-ss { color: #19177C } /* Literal.String.Symbol */\npre.pygments .tok-bp { color: #008000 } /* Name.Builtin.Pseudo */\npre.pygments .tok-fm { color: #0000FF } /* Name.Function.Magic */\npre.pygments .tok-vc { color: #19177C } /* Name.Variable.Class */\npre.pygments .tok-vg { color: #19177C } /* Name.Variable.Global */\npre.pygments .tok-vi { color: #19177C } /* Name.Variable.Instance */\npre.pygments .tok-vm { color: #19177C } /* Name.Variable.Magic */\npre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */\n</style>\n</head>\n<body class=\"article toc2 toc-right\">\n<div id=\"header\">\n<h1>pugixml 1.15 manual</h1>\n<div class=\"details\">\n<span id=\"author\" class=\"author\">website</span><br>\n<span id=\"email\" class=\"email\"><a href=\"https://pugixml.org\" class=\"bare\">https://pugixml.org</a></span><br>\n<span id=\"author2\" class=\"author\">repository</span><br>\n<span id=\"email2\" class=\"email\"><a href=\"https://github.com/zeux/pugixml\" class=\"bare\">https://github.com/zeux/pugixml</a></span><br>\n</div>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents</div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#overview\">1. Overview</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#overview.introduction\">1.1. Introduction</a></li>\n<li><a href=\"#overview.feedback\">1.2. Feedback</a></li>\n<li><a href=\"#overview.thanks\">1.3. Acknowledgments</a></li>\n<li><a href=\"#overview.license\">1.4. License</a></li>\n</ul>\n</li>\n<li><a href=\"#install\">2. Installation</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#install.getting\">2.1. Getting pugixml</a></li>\n<li><a href=\"#install.building\">2.2. Building pugixml</a></li>\n<li><a href=\"#install.portability\">2.3. Portability</a></li>\n</ul>\n</li>\n<li><a href=\"#dom\">3. Document object model</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#dom.tree\">3.1. Tree structure</a></li>\n<li><a href=\"#dom.cpp\">3.2. C&#43;&#43; interface</a></li>\n<li><a href=\"#dom.unicode\">3.3. Unicode interface</a></li>\n<li><a href=\"#dom.thread\">3.4. Thread-safety guarantees</a></li>\n<li><a href=\"#dom.exception\">3.5. Exception guarantees</a></li>\n<li><a href=\"#dom.memory\">3.6. Memory management</a></li>\n</ul>\n</li>\n<li><a href=\"#loading\">4. Loading document</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#loading.file\">4.1. Loading document from file</a></li>\n<li><a href=\"#loading.memory\">4.2. Loading document from memory</a></li>\n<li><a href=\"#loading.stream\">4.3. Loading document from C&#43;&#43; IOstreams</a></li>\n<li><a href=\"#loading.errors\">4.4. Handling parsing errors</a></li>\n<li><a href=\"#loading.options\">4.5. Parsing options</a></li>\n<li><a href=\"#loading.encoding\">4.6. Encodings</a></li>\n<li><a href=\"#loading.w3c\">4.7. Conformance to W3C specification</a></li>\n</ul>\n</li>\n<li><a href=\"#access\">5. Accessing document data</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#access.basic\">5.1. Basic traversal functions</a></li>\n<li><a href=\"#access.nodedata\">5.2. Getting node data</a></li>\n<li><a href=\"#access.attrdata\">5.3. Getting attribute data</a></li>\n<li><a href=\"#access.contents\">5.4. Contents-based traversal functions</a></li>\n<li><a href=\"#access.rangefor\">5.5. Range-based for-loop support</a></li>\n<li><a href=\"#access.iterators\">5.6. Traversing node/attribute lists via iterators</a></li>\n<li><a href=\"#access.walker\">5.7. Recursive traversal with xml_tree_walker</a></li>\n<li><a href=\"#access.predicate\">5.8. Searching for nodes/attributes with predicates</a></li>\n<li><a href=\"#access.text\">5.9. Working with text contents</a></li>\n<li><a href=\"#access.misc\">5.10. Miscellaneous functions</a></li>\n</ul>\n</li>\n<li><a href=\"#modify\">6. Modifying document data</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#modify.nodedata\">6.1. Setting node data</a></li>\n<li><a href=\"#modify.attrdata\">6.2. Setting attribute data</a></li>\n<li><a href=\"#modify.add\">6.3. Adding nodes/attributes</a></li>\n<li><a href=\"#modify.remove\">6.4. Removing nodes/attributes</a></li>\n<li><a href=\"#modify.text\">6.5. Working with text contents</a></li>\n<li><a href=\"#modify.clone\">6.6. Cloning nodes/attributes</a></li>\n<li><a href=\"#modify.move\">6.7. Moving nodes</a></li>\n<li><a href=\"#modify.fragments\">6.8. Assembling document from fragments</a></li>\n</ul>\n</li>\n<li><a href=\"#saving\">7. Saving document</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#saving.file\">7.1. Saving document to a file</a></li>\n<li><a href=\"#saving.stream\">7.2. Saving document to C&#43;&#43; IOstreams</a></li>\n<li><a href=\"#saving.writer\">7.3. Saving document via writer interface</a></li>\n<li><a href=\"#saving.subtree\">7.4. Saving a single subtree</a></li>\n<li><a href=\"#saving.options\">7.5. Output options</a></li>\n<li><a href=\"#saving.encoding\">7.6. Encodings</a></li>\n<li><a href=\"#saving.declaration\">7.7. Customizing document declaration</a></li>\n</ul>\n</li>\n<li><a href=\"#xpath\">8. XPath</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#xpath.types\">8.1. XPath types</a></li>\n<li><a href=\"#xpath.select\">8.2. Selecting nodes via XPath expression</a></li>\n<li><a href=\"#xpath.query\">8.3. Using query objects</a></li>\n<li><a href=\"#xpath.variables\">8.4. Using variables</a></li>\n<li><a href=\"#xpath.errors\">8.5. Error handling</a></li>\n<li><a href=\"#xpath.w3c\">8.6. Conformance to W3C specification</a></li>\n</ul>\n</li>\n<li><a href=\"#changes\">9. Changelog</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#v1.15\">v1.15 <sup>2024-01-10</sup></a></li>\n<li><a href=\"#v1.14\">v1.14 <sup>2023-10-01</sup></a></li>\n<li><a href=\"#v1.13\">v1.13 <sup>2022-11-01</sup></a></li>\n<li><a href=\"#v1.12\">v1.12 <sup>2022-02-09</sup></a></li>\n<li><a href=\"#v1.11\">v1.11 <sup>2020-11-26</sup></a></li>\n<li><a href=\"#v1.10\">v1.10 <sup>2019-09-15</sup></a></li>\n<li><a href=\"#v1.9\">v1.9 <sup>2018-04-04</sup></a></li>\n<li><a href=\"#v1.8\">v1.8 <sup>2016-11-24</sup></a></li>\n<li><a href=\"#v1.7\">v1.7 <sup>2015-10-19</sup></a></li>\n<li><a href=\"#v1.6\">v1.6 <sup>2015-04-10</sup></a></li>\n<li><a href=\"#v1.5\">v1.5 <sup>2014-11-27</sup></a></li>\n<li><a href=\"#v1.4\">v1.4 <sup>2014-02-27</sup></a></li>\n<li><a href=\"#v1.2\">v1.2 <sup>2012-05-01</sup></a></li>\n<li><a href=\"#v1.0\">v1.0 <sup>2010-11-01</sup></a></li>\n<li><a href=\"#v0.9\">v0.9 <sup>2010-07-01</sup></a></li>\n<li><a href=\"#v0.5\">v0.5 <sup>2009-11-08</sup></a></li>\n<li><a href=\"#v0.42\">v0.42 <sup>2009-09-17</sup></a></li>\n<li><a href=\"#v0.41\">v0.41 <sup>2009-02-08</sup></a></li>\n<li><a href=\"#v0.4\">v0.4 <sup>2009-01-18</sup></a></li>\n<li><a href=\"#v0.34\">v0.34 <sup>2007-10-31</sup></a></li>\n<li><a href=\"#v0.3\">v0.3 <sup>2007-02-21</sup></a></li>\n<li><a href=\"#v0.2\">v0.2 <sup>2006-11-06</sup></a></li>\n<li><a href=\"#v0.1\">v0.1 <sup>2006-07-15</sup></a></li>\n</ul>\n</li>\n<li><a href=\"#apiref\">10. API Reference</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#apiref.macros\">10.1. Macros</a></li>\n<li><a href=\"#apiref.types\">10.2. Types</a></li>\n<li><a href=\"#apiref.enums\">10.3. Enumerations</a></li>\n<li><a href=\"#apiref.constants\">10.4. Constants</a></li>\n<li><a href=\"#apiref.classes\">10.5. Classes</a></li>\n<li><a href=\"#apiref.functions\">10.6. Functions</a></li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n<div id=\"content\">\n<div class=\"sect1\">\n<h2 id=\"overview\"><a class=\"anchor\" href=\"#overview\"></a><a class=\"link\" href=\"#overview\">1. Overview</a></h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"overview.introduction\"><a class=\"anchor\" href=\"#overview.introduction\"></a><a class=\"link\" href=\"#overview.introduction\">1.1. Introduction</a></h3>\n<div class=\"paragraph\">\n<p><a href=\"https://pugixml.org/\">pugixml</a> is a light-weight C&#43;&#43; XML processing library. It consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an <a href=\"#xpath\">XPath 1.0 implementation</a> for complex data-driven tree queries. Full Unicode support is also available, with <a href=\"#dom.unicode\">two Unicode interface variants</a> and conversions between different Unicode encodings (which happen automatically during parsing/saving). The library is <a href=\"#install.portability\">extremely portable</a> and easy to integrate and use. pugixml is developed and maintained since 2006 and has many users. All code is distributed under the <a href=\"#overview.license\">MIT license</a>, making it completely free to use in both open-source and proprietary applications.</p>\n</div>\n<div class=\"paragraph\">\n<p>pugixml enables very fast, convenient and memory-efficient XML document processing. However, since pugixml has a DOM parser, it can&#8217;t process XML documents that do not fit in memory; also the parser is a non-validating one, so if you need DTD or XML Schema validation, the library is not for you.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is the complete manual for pugixml, which describes all features of the library in detail. If you want to start writing code as quickly as possible, you are advised to <a href=\"quickstart.html\">read the quick start guide first</a>.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nNo documentation is perfect; neither is this one. If you find errors or omissions, please don’t hesitate to <a href=\"https://github.com/zeux/pugixml/issues/new\">submit an issue or open a pull request</a> with a fix.\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"overview.feedback\"><a class=\"anchor\" href=\"#overview.feedback\"></a><a class=\"link\" href=\"#overview.feedback\">1.2. Feedback</a></h3>\n<div class=\"paragraph\">\n<p>If you believe you&#8217;ve found a bug in pugixml (bugs include compilation problems (errors/warnings), crashes, performance degradation and incorrect behavior), please file an issue via <a href=\"https://github.com/zeux/pugixml/issues/new\">issue submission form</a>. Be sure to include the relevant information so that the bug can be reproduced: the version of pugixml, compiler version and target architecture, the code that uses pugixml and exhibits the bug, etc.</p>\n</div>\n<div class=\"paragraph\">\n<p>Feature requests can be reported the same way as bugs, so if you&#8217;re missing some functionality in pugixml or if the API is rough in some places and you can suggest an improvement, <a href=\"https://github.com/zeux/pugixml/issues/new\">file an issue</a>. However please note that there are many factors when considering API changes (compatibility with previous versions, API redundancy, etc.), so generally features that can be implemented via a small function without pugixml modification are not accepted. However, all rules have exceptions.</p>\n</div>\n<div class=\"paragraph\">\n<p>If you have a contribution to pugixml, such as build script for some build system/IDE, or a well-designed set of helper functions, or a binding to some language other than C&#43;&#43;, please <a href=\"https://github.com/zeux/pugixml/issues/new\">file an issue or open a pull request</a>. Your contribution has to be distributed under the terms of a license that&#8217;s compatible with pugixml license; i.e. GPL/LGPL licensed code is not accepted.</p>\n</div>\n<div class=\"paragraph\">\n<p>If filing an issue is not possible due to privacy or other concerns, you can contact pugixml author by e-mail directly: <a href=\"mailto:arseny.kapoulkine@gmail.com\">arseny.kapoulkine@gmail.com</a>.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"overview.thanks\"><a class=\"anchor\" href=\"#overview.thanks\"></a><a class=\"link\" href=\"#overview.thanks\">1.3. Acknowledgments</a></h3>\n<div class=\"paragraph\">\n<p>pugixml could not be developed without the help from many people; some of them are listed in this section. If you&#8217;ve played a part in pugixml development and you can not find yourself on this list, I&#8217;m truly sorry; please <a href=\"#email\">send me an e-mail</a> so I can fix this.</p>\n</div>\n<div class=\"paragraph\">\n<p>Thanks to <strong>Kristen Wegner</strong> for pugxml parser, which was used as a basis for pugixml.</p>\n</div>\n<div class=\"paragraph\">\n<p>Thanks to <strong>Neville Franks</strong> for contributions to pugxml parser.</p>\n</div>\n<div class=\"paragraph\">\n<p>Thanks to <strong>Artyom Palvelev</strong> for suggesting a lazy gap contraction approach.</p>\n</div>\n<div class=\"paragraph\">\n<p>Thanks to <strong>Vyacheslav Egorov</strong> for documentation proofreading and fuzz testing.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"overview.license\"><a class=\"anchor\" href=\"#overview.license\"></a><a class=\"link\" href=\"#overview.license\">1.4. License</a></h3>\n<div class=\"paragraph\">\n<p>The pugixml library is distributed under the MIT license:</p>\n</div>\n<div class=\"literalblock\">\n<div class=\"content\">\n<pre>Copyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.</pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This means that you can freely use pugixml in your applications, both open-source and proprietary. If you use pugixml in a product, it is sufficient to add an acknowledgment like this to the product distribution:</p>\n</div>\n<div class=\"literalblock\">\n<div class=\"content\">\n<pre>This software is based on pugixml library (https://pugixml.org).\npugixml is Copyright (C) 2006-2025 Arseny Kapoulkine.</pre>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"install\"><a class=\"anchor\" href=\"#install\"></a><a class=\"link\" href=\"#install\">2. Installation</a></h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"install.getting\"><a class=\"anchor\" href=\"#install.getting\"></a><a class=\"link\" href=\"#install.getting\">2.1. Getting pugixml</a></h3>\n<div class=\"paragraph\">\n<p>pugixml is distributed in source form. You can either download a source distribution or clone the Git repository.</p>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.getting.source\"><a class=\"anchor\" href=\"#install.getting.source\"></a><a class=\"link\" href=\"#install.getting.source\">2.1.1. Source distributions</a></h4>\n<div class=\"paragraph\">\n<p>You can download the latest source distribution as an archive:</p>\n</div>\n<div class=\"paragraph\">\n<p><a href=\"https://github.com/zeux/pugixml/releases/download/v1.15/pugixml-1.15.zip\">pugixml-1.15.zip</a> (Windows line endings)\n/\n<a href=\"https://github.com/zeux/pugixml/releases/download/v1.15/pugixml-1.15.tar.gz\">pugixml-1.15.tar.gz</a> (Unix line endings)</p>\n</div>\n<div class=\"paragraph\">\n<p>The distribution contains library source, documentation (the manual you&#8217;re reading now and the quick start guide) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive.</p>\n</div>\n<div class=\"paragraph\">\n<p>If you need an older version, you can download it from the <a href=\"https://github.com/zeux/pugixml/releases\">version archive</a>.</p>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.getting.git\"><a class=\"anchor\" href=\"#install.getting.git\"></a><a class=\"link\" href=\"#install.getting.git\">2.1.2. Git repository</a></h4>\n<div class=\"paragraph\">\n<p>The Git repository is located at <a href=\"https://github.com/zeux/pugixml/\" class=\"bare\">https://github.com/zeux/pugixml/</a>. There is a Git tag \"v{version}\" for each version; also there is the \"latest\" tag, which always points to the latest stable release.</p>\n</div>\n<div class=\"paragraph\">\n<p>For example, to checkout the current version, you can use this command:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"bash\">git clone https://github.com/zeux/pugixml\ncd pugixml\ngit checkout v1.15</code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The repository contains library source, documentation, code examples and full unit test suite.</p>\n</div>\n<div class=\"paragraph\">\n<p>Use <code>latest</code> tag if you want to automatically get new versions. Use other tags if you want to switch to new versions only explicitly. Also please note that the master branch contains the work-in-progress version of the code; while this means that you can get new features and bug fixes from master without waiting for a new release, this also means that occasionally the code can be broken in some configurations.</p>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.getting.subversion\"><a class=\"anchor\" href=\"#install.getting.subversion\"></a><a class=\"link\" href=\"#install.getting.subversion\">2.1.3. Subversion repository</a></h4>\n<div class=\"paragraph\">\n<p>You can access the Git repository via Subversion using <a href=\"https://github.com/zeux/pugixml\" class=\"bare\">https://github.com/zeux/pugixml</a> URL. For example, to checkout the current version, you can use this command:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"bash\">svn checkout https://github.com/zeux/pugixml/tags/v1.15 pugixml</code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.getting.packages\"><a class=\"anchor\" href=\"#install.getting.packages\"></a><a class=\"link\" href=\"#install.getting.packages\">2.1.4. Packages</a></h4>\n<div class=\"paragraph\">\n<p>pugixml is available as a package via various package managers. Note that most packages are maintained separately from the main repository so they do not necessarily contain the latest version.</p>\n</div>\n<div class=\"paragraph\">\n<p>Here&#8217;s an incomplete list of pugixml packages in various systems:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Linux (<a href=\"http://packages.ubuntu.com/search?keywords=pugixml\">Ubuntu</a>, <a href=\"https://tracker.debian.org/pkg/pugixml\">Debian</a>, <a href=\"https://apps.fedoraproject.org/packages/pugixml\">Fedora</a>, <a href=\"https://aur.archlinux.org/packages/pugixml/\">Arch Linux</a>, other <a href=\"http://pkgs.org/search/pugixml\">distributions</a>)</p>\n</li>\n<li>\n<p><a href=\"http://fbsdmon.org/ports/textproc/pugixml\">FreeBSD</a></p>\n</li>\n<li>\n<p>OSX, via <a href=\"http://brewformulas.org/Pugixml\">Homebrew</a></p>\n</li>\n<li>\n<p>Windows, via <a href=\"https://www.nuget.org/packages/pugixml/\">NuGet</a></p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"install.building\"><a class=\"anchor\" href=\"#install.building\"></a><a class=\"link\" href=\"#install.building\">2.2. Building pugixml</a></h3>\n<div class=\"paragraph\">\n<p>pugixml is distributed in source form without any pre-built binaries; you have to build them yourself.</p>\n</div>\n<div class=\"paragraph\">\n<p>The complete pugixml source consists of three files - one source file, <code>pugixml.cpp</code>, and two header files, <code>pugixml.hpp</code> and <code>pugiconfig.hpp</code>. <code>pugixml.hpp</code> is the primary header which you need to include in order to use pugixml classes/functions; <code>pugiconfig.hpp</code> is a supplementary configuration file (see <a href=\"#install.building.config\">Additional configuration options</a>). The rest of this guide assumes that <code>pugixml.hpp</code> is either in the current directory or in one of include directories of your projects, so that <code>#include \"pugixml.hpp\"</code> can find the header; however you can also use relative path (i.e. <code>#include \"../libs/pugixml/src/pugixml.hpp\"</code>) or include directory-relative path (i.e. <code>#include &lt;xml/thirdparty/pugixml/src/pugixml.hpp&gt;</code>).</p>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.building.embed\"><a class=\"anchor\" href=\"#install.building.embed\"></a><a class=\"link\" href=\"#install.building.embed\">2.2.1. Building pugixml as a part of another static library/executable</a></h4>\n<div class=\"paragraph\">\n<p>The easiest way to build pugixml is to compile the source file, <code>pugixml.cpp</code>, along with the existing library/executable. This process depends on the method of building your application; for example, if you&#8217;re using Microsoft Visual Studio <sup class=\"footnote\">[<a id=\"_footnoteref_1\" class=\"footnote\" href=\"#_footnotedef_1\" title=\"View footnote.\">1</a>]</sup>, Apple Xcode, Code::Blocks or any other IDE, just <strong>add <code>pugixml.cpp</code> to one of your projects</strong>.</p>\n</div>\n<div class=\"paragraph\">\n<p>If you&#8217;re using Microsoft Visual Studio and the project has precompiled headers turned on, you&#8217;ll see the following error messages:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugixml</span><span class=\"tok-p\">.</span><span class=\"tok-n\">cpp</span><span class=\"tok-p\">(</span><span class=\"tok-mi\">3477</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">fatal</span><span class=\"tok-w\"> </span><span class=\"tok-n\">error</span><span class=\"tok-w\"> </span><span class=\"tok-n\">C1010</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">unexpected</span><span class=\"tok-w\"> </span><span class=\"tok-n\">end</span><span class=\"tok-w\"> </span><span class=\"tok-n\">of</span><span class=\"tok-w\"> </span><span class=\"tok-n\">file</span><span class=\"tok-w\"> </span><span class=\"tok-k\">while</span><span class=\"tok-w\"> </span><span class=\"tok-n\">looking</span><span class=\"tok-w\"> </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-n\">precompiled</span><span class=\"tok-w\"> </span><span class=\"tok-n\">header</span><span class=\"tok-p\">.</span><span class=\"tok-w\"> </span><span class=\"tok-n\">Did</span><span class=\"tok-w\"> </span><span class=\"tok-n\">you</span><span class=\"tok-w\"> </span><span class=\"tok-n\">forget</span><span class=\"tok-w\"> </span><span class=\"tok-n\">to</span><span class=\"tok-w\"> </span><span class=\"tok-n\">add</span><span class=\"tok-w\"> </span><span class=\"tok-err\">&#39;#</span><span class=\"tok-n\">include</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;stdafx.h&quot;</span><span class=\"tok-err\">&#39;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">to</span><span class=\"tok-w\"> </span><span class=\"tok-n\">your</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-o\">?</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The correct way to resolve this is to disable precompiled headers for <code>pugixml.cpp</code>; you have to set \"Create/Use Precompiled Header\" option (Properties dialog &#8594; C/C&#43;&#43; &#8594; Precompiled Headers &#8594; Create/Use Precompiled Header) to \"Not Using Precompiled Headers\". You&#8217;ll have to do it for all project configurations/platforms (you can select Configuration \"All Configurations\" and Platform \"All Platforms\" before editing the option):</p>\n</div>\n<table class=\"tableblock frame-none grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n</colgroup>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_pch1.png\"><img src=\"images/vs2005_pch1.png\" alt=\"vs2005 pch1\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_pch2.png\"><img src=\"images/vs2005_pch2.png\" alt=\"vs2005 pch2\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_pch3.png\"><img src=\"images/vs2005_pch3.png\" alt=\"vs2005 pch3\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_pch4.png\"><img src=\"images/vs2005_pch4.png\" alt=\"vs2005 pch4\"></a>\n</div>\n</div></div></td>\n</tr>\n</tbody>\n</table>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.building.static\"><a class=\"anchor\" href=\"#install.building.static\"></a><a class=\"link\" href=\"#install.building.static\">2.2.2. Building pugixml as a standalone static library</a></h4>\n<div class=\"paragraph\">\n<p>It&#8217;s possible to compile pugixml as a standalone static library. This process depends on the method of building your application; pugixml distribution comes with project files for several popular IDEs/build systems. There are project files for Apple XCode, Code::Blocks, Codelite, Microsoft Visual Studio 2005, 2008, 2010+, and configuration scripts for CMake and premake4. You&#8217;re welcome to submit project files/build scripts for other software; see <a href=\"#overview.feedback\">Feedback</a>.</p>\n</div>\n<div class=\"paragraph\">\n<p>There are two projects for each version of Microsoft Visual Studio: one for dynamically linked CRT, which has a name like <code>pugixml_vs2008.vcproj</code>, and another one for statically linked CRT, which has a name like <code>pugixml_vs2008_static.vcproj</code>. You should select the version that matches the CRT used in your application; the default option for new projects created by Microsoft Visual Studio is dynamically linked CRT, so unless you changed the defaults, you should use the version with dynamic CRT (i.e. <code>pugixml_vs2008.vcproj</code> for Microsoft Visual Studio 2008).</p>\n</div>\n<div class=\"paragraph\">\n<p>In addition to adding pugixml project to your workspace, you&#8217;ll have to make sure that your application links with pugixml library. If you&#8217;re using Microsoft Visual Studio 2005/2008, you can add a dependency from your application project to pugixml one. If you&#8217;re using Microsoft Visual Studio 2010+, you&#8217;ll have to add a reference to your application project instead. For other IDEs/systems, consult the relevant documentation.</p>\n</div>\n<table class=\"tableblock frame-none grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n<col style=\"width: 25%;\">\n</colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\" colspan=\"2\">Microsoft Visual Studio 2005/2008</th>\n<th class=\"tableblock halign-left valign-top\" colspan=\"2\">Microsoft Visual Studio 2010+</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_link1.png\"><img src=\"images/vs2005_link1.png\" alt=\"vs2005 link1\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2005_link2.png\"><img src=\"images/vs2005_link2.png\" alt=\"vs2005 link2\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2010_link1.png\"><img src=\"images/vs2010_link1.png\" alt=\"vs2010 link1\"></a>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/vs2010_link2.png\"><img src=\"images/vs2010_link2.png\" alt=\"vs2010 link2\"></a>\n</div>\n</div></div></td>\n</tr>\n</tbody>\n</table>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.building.shared\"><a class=\"anchor\" href=\"#install.building.shared\"></a><a class=\"link\" href=\"#install.building.shared\">2.2.3. Building pugixml as a standalone shared library</a></h4>\n<div class=\"paragraph\">\n<p>It&#8217;s possible to compile pugixml as a standalone shared library. The process is usually similar to the static library approach; however, no preconfigured projects/scripts are included into pugixml distribution, so you&#8217;ll have to do it yourself. Generally, if you&#8217;re using GCC-based toolchain, the process does not differ from building any other library as DLL (adding -shared to compilation flags should suffice); if you&#8217;re using MSVC-based toolchain, you&#8217;ll have to explicitly mark exported symbols with a declspec attribute. You can do it by defining <a href=\"#PUGIXML_API\">PUGIXML_API</a> macro, i.e. via <code>pugiconfig.hpp</code>:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-cp\">#ifdef _DLL</span>\n<span class=\"tok-w\">    </span><span class=\"tok-cp\">#define PUGIXML_API __declspec(dllexport)</span>\n<span class=\"tok-cp\">#else</span>\n<span class=\"tok-w\">    </span><span class=\"tok-cp\">#define PUGIXML_API __declspec(dllimport)</span>\n<span class=\"tok-cp\">#endif</span></code></pre>\n</div>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nIf you&#8217;re using STL-related functions, you should use the shared runtime library to ensure that a single heap is used for STL allocations in your application and in pugixml; in MSVC, this means selecting the 'Multithreaded DLL' or 'Multithreaded Debug DLL' to 'Runtime library' property (<code>/MD</code> or <code>/MDd</code> linker switch). You should also make sure that your runtime library choice is consistent between different projects.\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.building.header\"><a class=\"anchor\" href=\"#install.building.header\"></a><a class=\"link\" href=\"#install.building.header\">2.2.4. Using pugixml in header-only mode</a></h4>\n<div id=\"PUGIXML_HEADER_ONLY\" class=\"paragraph\">\n<p>It&#8217;s possible to use pugixml in header-only mode. This means that all source code for pugixml will be included in every translation unit that includes <code>pugixml.hpp</code>. This is how most of Boost and STL libraries work.</p>\n</div>\n<div class=\"paragraph\">\n<p>Note that there are advantages and drawbacks of this approach. Header mode may improve tree traversal/modification performance (because many simple functions will be inlined), if your compiler toolchain does not support link-time optimization, or if you have it turned off (with link-time optimization the performance should be similar to non-header mode). However, since compiler now has to compile pugixml source once for each translation unit that includes it, compilation times may increase noticeably. If you want to use pugixml in header mode but do not need XPath support, you can consider disabling it by using <a href=\"#PUGIXML_NO_XPATH\">PUGIXML_NO_XPATH</a> define to improve compilation time.</p>\n</div>\n<div class=\"paragraph\">\n<p>To enable header-only mode, you have to define <code>PUGIXML_HEADER_ONLY</code>. You can either do it in <code>pugiconfig.hpp</code>, or provide them via compiler command-line.</p>\n</div>\n<div class=\"paragraph\">\n<p>Note that it is safe to compile <code>pugixml.cpp</code> if <code>PUGIXML_HEADER_ONLY</code> is defined - so if you want to i.e. use header-only mode only in Release configuration, you\ncan include pugixml.cpp in your project (see <a href=\"#install.building.embed\">Building pugixml as a part of another static library/executable</a>), and conditionally enable header-only mode in <code>pugiconfig.hpp</code> like this:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-cp\">#ifndef _DEBUG</span>\n<span class=\"tok-w\">    </span><span class=\"tok-cp\">#define PUGIXML_HEADER_ONLY</span>\n<span class=\"tok-cp\">#endif</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"install.building.config\"><a class=\"anchor\" href=\"#install.building.config\"></a><a class=\"link\" href=\"#install.building.config\">2.2.5. Additional configuration options</a></h4>\n<div class=\"paragraph\">\n<p>pugixml uses several defines to control the compilation process. There are two ways to define them: either put the needed definitions to <code>pugiconfig.hpp</code> (it has some examples that are commented out) or provide them via compiler command-line. Consistency is important: the definitions should match in all source files that include <code>pugixml.hpp</code> (including pugixml sources) throughout the application. Adding defines to <code>pugiconfig.hpp</code> lets you guarantee this, unless your macro definition is wrapped in preprocessor <code>#if</code>/<code>#ifdef</code> directive and this directive is not consistent. <code>pugiconfig.hpp</code> will never contain anything but comments, which means that when upgrading to a new version, you can safely leave your modified version intact.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_WCHAR_MODE\"></a><code>PUGIXML_WCHAR_MODE</code> define toggles between UTF-8 style interface (the in-memory text encoding is assumed to be UTF-8, most functions use <code>char</code> as character type) and UTF-16/32 style interface (the in-memory text encoding is assumed to be UTF-16/32, depending on <code>wchar_t</code> size, most functions use <code>wchar_t</code> as character type). See <a href=\"#dom.unicode\">Unicode interface</a> for more details.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_COMPACT\"></a><code>PUGIXML_COMPACT</code> define activates a different internal representation of document storage that is much more memory efficient for documents with a lot of markup (i.e. nodes and attributes), but is slightly slower to parse and access. For details see <a href=\"#dom.memory.compact\">Compact mode</a>.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_NO_XPATH\"></a><code>PUGIXML_NO_XPATH</code> define disables XPath. Both XPath interfaces and XPath implementation are excluded from compilation. This option is provided in case you do not need XPath functionality and need to save code space.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_NO_STL\"></a><code>PUGIXML_NO_STL</code> define disables use of STL in pugixml. The functions that operate on STL types are no longer present (i.e. load/save via iostream) if this macro is defined. This option is provided in case your target platform does not have a standard-compliant STL implementation.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_NO_EXCEPTIONS\"></a><code>PUGIXML_NO_EXCEPTIONS</code> define disables use of exceptions in pugixml. This option is provided in case your target platform does not have exception handling capabilities.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_API\"></a><code>PUGIXML_API</code>, <a id=\"PUGIXML_CLASS\"></a><code>PUGIXML_CLASS</code> and <a id=\"PUGIXML_FUNCTION\"></a><code>PUGIXML_FUNCTION</code> defines let you specify custom attributes (i.e. declspec or calling conventions) for pugixml classes and non-member functions. In absence of <code>PUGIXML_CLASS</code> or <code>PUGIXML_FUNCTION</code> definitions, <code>PUGIXML_API</code> definition is used instead. For example, to specify fixed calling convention, you can define <code>PUGIXML_FUNCTION</code> to i.e. <code>__fastcall</code>. Another example is DLL import/export attributes in MSVC (see <a href=\"#install.building.shared\">Building pugixml as a standalone shared library</a>).</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nIn that example <code>PUGIXML_API</code> is inconsistent between several source files; this is an exception to the consistency rule.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_MEMORY_PAGE_SIZE\"></a><code>PUGIXML_MEMORY_PAGE_SIZE</code>, <a id=\"PUGIXML_MEMORY_OUTPUT_STACK\"></a><code>PUGIXML_MEMORY_OUTPUT_STACK</code> and <a id=\"PUGIXML_MEMORY_XPATH_PAGE_SIZE\"></a><code>PUGIXML_MEMORY_XPATH_PAGE_SIZE</code> can be used to customize certain important sizes to optimize memory usage for the application-specific patterns. For details see <a href=\"#dom.memory.tuning\">Memory consumption tuning</a>.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_HAS_LONG_LONG\"></a><code>PUGIXML_HAS_LONG_LONG</code> define enables support for <code>long long</code> type in pugixml. This define is automatically enabled if your platform is known to have <code>long long</code> support (i.e. has C&#43;&#43;11 support or uses a reasonably modern version of a known compiler); if pugixml does not recognize that your platform supports <code>long long</code> but in fact it does, you can enable the define manually.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"PUGIXML_HAS_STRING_VIEW\"></a><code>PUGIXML_HAS_STRING_VIEW</code> define enables function overloads that accept <code>std::string_view</code> arguments. This define is automatically enabled if built targeting C&#43;&#43;17 or later; if pugixml does not recognize that your platform supports <code>std::string_view</code> but in fact it does, you can enable the define manually.</p>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"install.portability\"><a class=\"anchor\" href=\"#install.portability\"></a><a class=\"link\" href=\"#install.portability\">2.3. Portability</a></h3>\n<div class=\"paragraph\">\n<p>pugixml is written in standard-compliant C&#43;&#43; with some compiler-specific workarounds where appropriate. pugixml is compatible with the C&#43;&#43;11 standard, but does not require C&#43;&#43;11 support. Each version is tested with a unit test suite with code coverage exceeding 99%.</p>\n</div>\n<div class=\"paragraph\">\n<p>pugixml runs on a variety of desktop platforms (including Microsoft Windows, Linux, FreeBSD, Apple MacOSX and Sun Solaris), game consoles (inclusing Microsoft Xbox 360, Microsoft Xbox One, Nintendo Wii, Sony Playstation Portable and Sony Playstation 3) and mobile platforms (including Android, iOS, BlackBerry, Samsung bada and Microsoft Windows CE).</p>\n</div>\n<div class=\"paragraph\">\n<p>pugixml supports various architectures, such as x86/x86-64, PowerPC, ARM, MIPS and SPARC. In general it should run on any architecture since it does not use architecture-specific code and does not rely on features such as unaligned memory access.</p>\n</div>\n<div class=\"paragraph\">\n<p>pugixml can be compiled using any C++ compiler; it was tested with all versions of Microsoft Visual C&#43;&#43; from 6.0 up to 2015, GCC from 3.4 up to 5.2, Clang from 3.2 up to 3.7, as well as a variety of other compilers (e.g. Borland C&#43;&#43;, Digital Mars C&#43;&#43;, Intel C&#43;&#43;, Metrowerks CodeWarrior and PathScale). The code is written to avoid compilation warnings even on reasonably high warning levels.</p>\n</div>\n<div class=\"paragraph\">\n<p>Note that some platforms may have very bare-bones support of C++; in some cases you&#8217;ll have to use <code>PUGIXML_NO_STL</code> and/or <code>PUGIXML_NO_EXCEPTIONS</code> to compile without issues. This mostly applies to old game consoles and embedded systems.</p>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"dom\"><a class=\"anchor\" href=\"#dom\"></a><a class=\"link\" href=\"#dom\">3. Document object model</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml stores XML data in DOM-like way: the entire XML document (both document structure and element data) is stored in memory as a tree. The tree can be loaded from a character stream (file, string, C&#43;&#43; I/O stream), then traversed with the special API or XPath expressions. The whole tree is mutable: both node structure and node/attribute data can be changed at any time. Finally, the result of document transformations can be saved to a character stream (file, C&#43;&#43; I/O stream or custom transport).</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.tree\"><a class=\"anchor\" href=\"#dom.tree\"></a><a class=\"link\" href=\"#dom.tree\">3.1. Tree structure</a></h3>\n<div class=\"paragraph\">\n<p>The XML document is represented with a tree data structure. The root of the tree is the document itself, which corresponds to C&#43;&#43; type <a href=\"#xml_document\">xml_document</a>. Document has one or more child nodes, which correspond to C&#43;&#43; type <a href=\"#xml_node\">xml_node</a>. Nodes have different types; depending on a type, a node can have a collection of child nodes, a collection of attributes, which correspond to C&#43;&#43; type <a href=\"#xml_attribute\">xml_attribute</a>, and some additional data (i.e. name).</p>\n</div>\n<div id=\"xml_node_type\" class=\"paragraph\">\n<p>The tree nodes can be of one of the following types (which together form the enumeration <code>xml_node_type</code>):</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Document node (<a id=\"node_document\"></a><code>node_document</code>) - this is the root of the tree, which consists of several child nodes. This node corresponds to <a href=\"#xml_document\">xml_document</a> class; note that <a href=\"#xml_document\">xml_document</a> is a sub-class of <a href=\"#xml_node\">xml_node</a>, so the entire node interface is also available. However, document node is special in several ways, which are covered below. There can be only one document node in the tree; document node does not have any XML representation. Document generally has one child element node (see <a id=\"xml_document::document_element\"></a><code>document_element()</code>), although documents parsed from XML fragments (see <a id=\"parse_fragment\"></a><code>parse_fragment</code>) can have more than one.</p>\n</li>\n<li>\n<p>Element/tag node (<a id=\"node_element\"></a><code>node_element</code>) - this is the most common type of node, which represents XML elements. Element nodes have a name, a collection of attributes and a collection of child nodes (both of which may be empty). The attribute is a simple name/value pair. The example XML representation of element nodes is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;</span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-o\">=</span><span class=\"tok-s\">&quot;value&quot;</span><span class=\"tok-o\">&gt;&lt;</span><span class=\"tok-n\">child</span><span class=\"tok-o\">/&gt;&lt;/</span><span class=\"tok-n\">node</span><span class=\"tok-o\">&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>There are two element nodes here: one has name <code>\"node\"</code>, single attribute <code>\"attr\"</code> and single child <code>\"child\"</code>, another has name <code>\"child\"</code> and does not have any attributes or child nodes.</p>\n</div>\n</li>\n<li>\n<p>Plain character data nodes (<a id=\"node_pcdata\"></a><code>node_pcdata</code>) represent plain text in XML. PCDATA nodes have a value, but do not have a name or children/attributes. Note that <strong>plain character data is not a part of the element node but instead has its own node</strong>; an element node can have several child PCDATA nodes. The example XML representation of text nodes is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;</span><span class=\"tok-n\">node</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">text1</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-n\">child</span><span class=\"tok-o\">/&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">text2</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;/</span><span class=\"tok-n\">node</span><span class=\"tok-o\">&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Here <code>\"node\"</code> element has three children, two of which are PCDATA nodes with values <code>\" text1 \"</code> and <code>\" text2 \"</code>.</p>\n</div>\n</li>\n<li>\n<p>Character data nodes (<a id=\"node_cdata\"></a><code>node_cdata</code>) represent text in XML that is quoted in a special way. CDATA nodes do not differ from PCDATA nodes except in XML representation - the above text example looks like this with CDATA:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;</span><span class=\"tok-n\">node</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;!</span><span class=\"tok-p\">[</span><span class=\"tok-n\">CDATA</span><span class=\"tok-p\">[</span><span class=\"tok-n\">text1</span><span class=\"tok-p\">]]</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-n\">child</span><span class=\"tok-o\">/&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;!</span><span class=\"tok-p\">[</span><span class=\"tok-n\">CDATA</span><span class=\"tok-p\">[</span><span class=\"tok-n\">text2</span><span class=\"tok-p\">]]</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;/</span><span class=\"tok-n\">node</span><span class=\"tok-o\">&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>CDATA nodes make it easy to include non-escaped <code>&lt;</code>, <code>&amp;</code> and <code>&gt;</code> characters in plain text. CDATA value can not contain the character sequence <code>]]&gt;</code>, since it is used to determine the end of node contents.</p>\n</div>\n</li>\n<li>\n<p>Comment nodes (<a id=\"node_comment\"></a><code>node_comment</code>) represent comments in XML. Comment nodes have a value, but do not have a name or children/attributes. The example XML representation of a comment node is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;!--</span><span class=\"tok-w\"> </span><span class=\"tok-n\">comment</span><span class=\"tok-w\"> </span><span class=\"tok-n\">text</span><span class=\"tok-w\"> </span><span class=\"tok-o\">--&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Here the comment node has value <code>\"comment text\"</code>. By default comment nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with <a href=\"#parse_comments\">parse_comments</a> flag.</p>\n</div>\n</li>\n<li>\n<p>Processing instruction node (<a id=\"node_pi\"></a><code>node_pi</code>) represent processing instructions (PI) in XML. PI nodes have a name and an optional value, but do not have children/attributes. The example XML representation of a PI node is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;?</span><span class=\"tok-n\">name</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-o\">?&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Here the name (also called PI target) is <code>\"name\"</code>, and the value is <code>\"value\"</code>. By default PI nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with <a href=\"#parse_pi\">parse_pi</a> flag.</p>\n</div>\n</li>\n<li>\n<p>Declaration node (<a id=\"node_declaration\"></a><code>node_declaration</code>) represents document declarations in XML. Declaration nodes have a name (<code>\"xml\"</code>) and an optional collection of attributes, but do not have value or children. There can be only one declaration node in a document; moreover, it should be the topmost node (its parent should be the document). The example XML representation of a declaration node is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;?</span><span class=\"tok-n\">xml</span><span class=\"tok-w\"> </span><span class=\"tok-n\">version</span><span class=\"tok-o\">=</span><span class=\"tok-s\">&quot;1.0&quot;</span><span class=\"tok-o\">?&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Here the node has name <code>\"xml\"</code> and a single attribute with name <code>\"version\"</code> and value <code>\"1.0\"</code>. By default declaration nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with <a href=\"#parse_declaration\">parse_declaration</a> flag. Also, by default a dummy declaration is output when XML document is saved unless there is already a declaration in the document; you can disable this with <a href=\"#format_no_declaration\">format_no_declaration</a> flag.</p>\n</div>\n</li>\n<li>\n<p>Document type declaration node (<a id=\"node_doctype\"></a><code>node_doctype</code>) represents document type declarations in XML. Document type declaration nodes have a value, which corresponds to the entire document type contents; no additional nodes are created for inner elements like <code>&lt;!ENTITY&gt;</code>. There can be only one document type declaration node in a document; moreover, it should be the topmost node (its parent should be the document). The example XML representation of a document type declaration node is as follows:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-o\">&lt;!</span><span class=\"tok-n\">DOCTYPE</span><span class=\"tok-w\"> </span><span class=\"tok-n\">greeting</span><span class=\"tok-w\"> </span><span class=\"tok-p\">[</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;!</span><span class=\"tok-n\">ELEMENT</span><span class=\"tok-w\"> </span><span class=\"tok-n\">greeting</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-err\">#</span><span class=\"tok-n\">PCDATA</span><span class=\"tok-p\">)</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-p\">]</span><span class=\"tok-o\">&gt;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Here the node has value <code>\"greeting [ &lt;!ELEMENT greeting (#PCDATA)&gt; ]\"</code>. By default document type declaration nodes are treated as non-essential part of XML markup and are not loaded during XML parsing. You can override this behavior with <a href=\"#parse_doctype\">parse_doctype</a> flag.</p>\n</div>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Finally, here is a complete example of XML document and the corresponding tree representation (<a href=\"samples/tree.xml\" class=\"bare\">samples/tree.xml</a>):</p>\n</div>\n<table class=\"tableblock frame-none grid-all stretch\">\n<colgroup>\n<col style=\"width: 50%;\">\n<col style=\"width: 50%;\">\n</colgroup>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"xml\"><span></span><span class=\"tok-cp\">&lt;?xml version=&quot;1.0&quot;?&gt;</span>\n<span class=\"tok-nt\">&lt;mesh</span><span class=\"tok-w\"> </span><span class=\"tok-na\">name=</span><span class=\"tok-s\">&quot;mesh_root&quot;</span><span class=\"tok-nt\">&gt;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-cm\">&lt;!-- here is a mesh node --&gt;</span>\n<span class=\"tok-w\">    </span>some<span class=\"tok-w\"> </span>text\n<span class=\"tok-w\">    </span><span class=\"tok-cp\">&lt;![CDATA[someothertext]]&gt;</span>\n<span class=\"tok-w\">    </span>some<span class=\"tok-w\"> </span>more<span class=\"tok-w\"> </span>text\n<span class=\"tok-w\">    </span><span class=\"tok-nt\">&lt;node</span><span class=\"tok-w\"> </span><span class=\"tok-na\">attr1=</span><span class=\"tok-s\">&quot;value1&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-na\">attr2=</span><span class=\"tok-s\">&quot;value2&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-nt\">/&gt;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-nt\">&lt;node</span><span class=\"tok-w\"> </span><span class=\"tok-na\">attr1=</span><span class=\"tok-s\">&quot;value2&quot;</span><span class=\"tok-nt\">&gt;</span>\n<span class=\"tok-w\">        </span><span class=\"tok-nt\">&lt;innernode/&gt;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-nt\">&lt;/node&gt;</span>\n<span class=\"tok-nt\">&lt;/mesh&gt;</span>\n<span class=\"tok-cp\">&lt;?include somedata?&gt;</span></code></pre>\n</div>\n</div></div></td>\n<td class=\"tableblock halign-left valign-top\"><div class=\"content\"><div class=\"imageblock\">\n<div class=\"content\">\n<a class=\"image\" href=\"images/dom_tree.png\"><img src=\"images/dom_tree.png\" alt=\"dom tree\"></a>\n</div>\n</div></div></td>\n</tr>\n</tbody>\n</table>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.cpp\"><a class=\"anchor\" href=\"#dom.cpp\"></a><a class=\"link\" href=\"#dom.cpp\">3.2. C&#43;&#43; interface</a></h3>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nAll pugixml classes and functions are located in the <code>pugi</code> namespace; you have to either use explicit name qualification (i.e. <code>pugi::xml_node</code>), or to gain access to relevant symbols via <code>using</code> directive (i.e. <code>using pugi::xml_node;</code> or <code>using namespace pugi;</code>). The namespace will be omitted from all declarations in this documentation hereafter; all code examples will use fully qualified names.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>Despite the fact that there are several node types, there are only three C&#43;&#43; classes representing the tree (<code>xml_document</code>, <code>xml_node</code>, <code>xml_attribute</code>); some operations on <code>xml_node</code> are only valid for certain node types. The classes are described below.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_document\"></a><a id=\"xml_document::document_element\"></a>\n<code>xml_document</code> is the owner of the entire document structure; it is a non-copyable class. The interface of <code>xml_document</code> consists of loading functions (see <a href=\"#loading\">Loading document</a>), saving functions (see <a href=\"#saving\">Saving document</a>) and the entire interface of <code>xml_node</code>, which allows for document inspection and/or modification. Note that while <code>xml_document</code> is a sub-class of <code>xml_node</code>, <code>xml_node</code> is not a polymorphic type; the inheritance is present only to simplify usage. Alternatively you can use the <code>document_element</code> function to get the element node that&#8217;s the immediate child of the document.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_document::ctor\"></a><a id=\"xml_document::dtor\"></a><a id=\"xml_document::reset\"></a>\nDefault constructor of <code>xml_document</code> initializes the document to the tree with only a root node (document node). You can then populate it with data using either tree modification functions or loading functions; all loading functions destroy the previous tree with all occupied memory, which puts existing node/attribute handles for this document to invalid state. If you want to destroy the previous tree, you can use the <code>xml_document::reset</code> function; it destroys the tree and replaces it with either an empty one or a copy of the specified document. Destructor of <code>xml_document</code> also destroys the tree, thus the lifetime of the document object should exceed the lifetimes of any node/attribute handles that point to the tree.</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nWhile technically node/attribute handles can be alive when the tree they&#8217;re referring to is destroyed, calling any member function for these handles results in undefined behavior. Thus it is recommended to make sure that the document is destroyed only after all references to its nodes/attributes are destroyed.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_node\"></a><a id=\"xml_node::type\"></a>\n<code>xml_node</code> is the handle to document node; it can point to any node in the document, including the document node itself. There is a common interface for nodes of all types; the actual <a href=\"#xml_node_type\">node type</a> can be queried via the <code>xml_node::type()</code> method. Note that <code>xml_node</code> is only a handle to the actual node, not the node itself - you can have several <code>xml_node</code> handles pointing to the same underlying object. Destroying <code>xml_node</code> handle does not destroy the node and does not remove it from the tree. The size of <code>xml_node</code> is equal to that of a pointer, so it is nothing more than a lightweight wrapper around a pointer; you can safely pass or return <code>xml_node</code> objects by value without additional overhead.</p>\n</div>\n<div id=\"node_null\" class=\"paragraph\">\n<p>There is a special value of <code>xml_node</code> type, known as null node or empty node (such nodes have type <code>node_null</code>). It does not correspond to any node in any document, and thus resembles null pointer. However, all operations are defined on empty nodes; generally the operations don&#8217;t do anything and return empty nodes/attributes or empty strings as their result (see documentation for specific functions for more detailed information). This is useful for chaining calls; i.e. you can get the grandparent of a node like so: <code>node.parent().parent()</code>; if a node is a null node or it does not have a parent, the first <code>parent()</code> call returns null node; the second <code>parent()</code> call then also returns null node, which makes error handling easier.</p>\n</div>\n<div id=\"xml_attribute\" class=\"paragraph\">\n<p><code>xml_attribute</code> is the handle to an XML attribute; it has the same semantics as <code>xml_node</code>, i.e. there can be several <code>xml_attribute</code> handles pointing to the same underlying object and there is a special null attribute value, which propagates to function results.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::ctor\"></a><a id=\"xml_node::ctor\"></a>\nBoth <code>xml_node</code> and <code>xml_attribute</code> have the default constructor which initializes them to null objects.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::comparison\"></a><a id=\"xml_node::comparison\"></a>\n<code>xml_node</code> and <code>xml_attribute</code> try to behave like pointers, that is, they can be compared with other objects of the same type, making it possible to use them as keys in associative containers. All handles to the same underlying object are equal, and any two handles to different underlying objects are not equal. Null handles only compare as equal to null handles. The result of relational comparison can not be reliably determined from the order of nodes in file or in any other way. Do not use relational comparison operators except for search optimization (i.e. associative container keys).</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::hash_value\"></a><a id=\"xml_node::hash_value\"></a>\nIf you want to use <code>xml_node</code> or <code>xml_attribute</code> objects as keys in hash-based associative containers, you can use the <code>hash_value</code> member functions. They return the hash values that are guaranteed to be the same for all handles to the same underlying object. The hash value for null handles is 0. Note that hash value does not depend on the content of the node, only on the location of the underlying structure in memory - this means that loading the same document twice will likely produce different hash values, and copying the node will not preserve the hash.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::unspecified_bool_type\"></a><a id=\"xml_node::unspecified_bool_type\"></a><a id=\"xml_attribute::empty\"></a><a id=\"xml_node::empty\"></a>\nFinally handles can be implicitly cast to boolean-like objects, so that you can test if the node/attribute is empty with the following code: <code>if (node) { &#8230;&#8203; }</code> or <code>if (!node) { &#8230;&#8203; } else { &#8230;&#8203; }</code>. Alternatively you can check if a given <code>xml_node</code>/<code>xml_attribute</code> handle is null by calling the following methods:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::empty</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::empty</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Nodes and attributes do not exist without a document tree, so you can&#8217;t create them without adding them to some document. Once underlying node/attribute objects are destroyed, the handles to those objects become invalid. While this means that destruction of the entire tree invalidates all node/attribute handles, it also means that destroying a subtree (by calling <a href=\"#xml_node::remove_child\">xml_node::remove_child</a>) or removing an attribute invalidates the corresponding handles. There is no way to check handle validity; you have to ensure correctness through external mechanisms.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.unicode\"><a class=\"anchor\" href=\"#dom.unicode\"></a><a class=\"link\" href=\"#dom.unicode\">3.3. Unicode interface</a></h3>\n<div class=\"paragraph\">\n<p>There are two choices of interface and internal representation when configuring pugixml: you can either choose the UTF-8 (also called char) interface or UTF-16/32 (also called wchar_t) one. The choice is controlled via <a href=\"#PUGIXML_WCHAR_MODE\">PUGIXML_WCHAR_MODE</a> define; you can set it via <code>pugiconfig.hpp</code> or via preprocessor options, as discussed in <a href=\"#install.building.config\">Additional configuration options</a>. If this define is set, the wchar_t interface is used; otherwise (by default) the char interface is used. The exact wide character encoding is assumed to be either UTF-16 or UTF-32 and is determined based on the size of <code>wchar_t</code> type.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nIf the size of <code>wchar_t</code> is 2, pugixml assumes UTF-16 encoding instead of UCS-2, which means that some characters are represented as two code points.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>All tree functions that work with strings work with either C-style null terminated strings or STL strings of the selected character type. For example, node name accessors look like this in char mode:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>and like this in wchar_t mode:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"char_t\"></a><a id=\"string_t\"></a><a id=\"string_view_t\"></a>\nThere is a special type, <code>pugi::char_t</code>, that is defined as the character type and depends on the library configuration; it will be also used in the documentation hereafter. There is also a type <code>pugi::string_t</code>, which is defined as the STL string of the character type; it corresponds to <code>std::string</code> in char mode and to <code>std::wstring</code> in wchar_t mode. Similarly, <code>string_view_t</code> is defined to be <code>std::basic_string_view&lt;char_t&gt;</code>. Overloads for <code>string_view_t</code> are only available when building for C++17 or later (see <code>PUGIXML_HAS_STRING_VIEW</code>).</p>\n</div>\n<div class=\"paragraph\">\n<p>In addition to the interface, the internal implementation changes to store XML data as <code>pugi::char_t</code>; this means that these two modes have different memory usage characteristics - generally UTF-8 mode is more memory and performance efficient, especially if <code>sizeof(wchar_t)</code> is 4. The conversion to <code>pugi::char_t</code> upon document loading and from <code>pugi::char_t</code> upon document saving happen automatically, which also carries minor performance penalty. The general advice however is to select the character mode based on usage scenario, i.e. if UTF-8 is inconvenient to process and most of your XML data is non-ASCII, wchar_t mode is probably a better choice.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"as_utf8\"></a><a id=\"as_wide\"></a>\nThere are cases when you&#8217;ll have to convert string data between UTF-8 and wchar_t encodings; the following helper functions are provided for such purposes:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">as_utf8</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">as_wide</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Both functions accept a null-terminated string as an argument <code>str</code>, and return the converted string. <code>as_utf8</code> performs conversion from UTF-16/32 to UTF-8; <code>as_wide</code> performs conversion from UTF-8 to UTF-16/32. Invalid UTF sequences are silently discarded upon conversion. <code>str</code> has to be a valid string; passing null pointer results in undefined behavior. There are also two overloads with the same semantics which accept a string as an argument:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">as_utf8</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">as_wide</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\n<div class=\"paragraph\">\n<p>Most examples in this documentation assume char interface and therefore will not compile with <a href=\"#PUGIXML_WCHAR_MODE\">PUGIXML_WCHAR_MODE</a>. This is done to simplify the documentation; usually the only changes you&#8217;ll have to make is to pass <code>wchar_t</code> string literals, i.e. instead of</p>\n</div>\n<div class=\"paragraph\">\n<p><code>xml_node node = doc.child(\"bookstore\").find_child_by_attribute(\"book\", \"id\", \"12345\");</code></p>\n</div>\n<div class=\"paragraph\">\n<p>you&#8217;ll have to use</p>\n</div>\n<div class=\"paragraph\">\n<p><code>xml_node node = doc.child(L\"bookstore\").find_child_by_attribute(L\"book\", L\"id\", L\"12345\");</code></p>\n</div>\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.thread\"><a class=\"anchor\" href=\"#dom.thread\"></a><a class=\"link\" href=\"#dom.thread\">3.4. Thread-safety guarantees</a></h3>\n<div class=\"paragraph\">\n<p>Almost all functions in pugixml have the following thread-safety guarantees:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>it is safe to call free (non-member) functions from multiple threads</p>\n</li>\n<li>\n<p>it is safe to perform concurrent read-only accesses to the same tree (all constant member functions do not modify the tree)</p>\n</li>\n<li>\n<p>it is safe to perform concurrent read/write accesses on multiple trees, as long as each tree is only accessed from a single thread at a time</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Concurrent read/write access to a single tree requires synchronization, for example via a reader-writer lock. Modification includes altering document structure and altering individual node/attribute data, i.e. changing names/values.</p>\n</div>\n<div class=\"paragraph\">\n<p>The only exception is <a href=\"#set_memory_management_functions\">set_memory_management_functions</a>; it modifies global variables and as such is not thread-safe. Its usage policy has more restrictions, see <a href=\"#dom.memory.custom\">Custom memory allocation/deallocation functions</a>.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.exception\"><a class=\"anchor\" href=\"#dom.exception\"></a><a class=\"link\" href=\"#dom.exception\">3.5. Exception guarantees</a></h3>\n<div class=\"paragraph\">\n<p>With the exception of XPath, pugixml itself does not throw any exceptions. Additionally, most pugixml functions have a no-throw exception guarantee.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is not applicable to functions that operate on STL strings or IOstreams; such functions have either strong guarantee (functions that operate on strings) or basic guarantee (functions that operate on streams). Also functions that call user-defined callbacks (i.e. <a href=\"#xml_node::traverse\">xml_node::traverse</a> or <a href=\"#xml_node::find_node\">xml_node::find_node</a>) do not provide any exception guarantees beyond the ones provided by the callback.</p>\n</div>\n<div class=\"paragraph\">\n<p>If exception handling is not disabled with <a href=\"#PUGIXML_NO_EXCEPTIONS\">PUGIXML_NO_EXCEPTIONS</a> define, XPath functions may throw <a href=\"#xpath_exception\">xpath_exception</a> on parsing errors; also, XPath functions may throw <code>std::bad_alloc</code> in low memory conditions. Still, XPath functions provide strong exception guarantee.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"dom.memory\"><a class=\"anchor\" href=\"#dom.memory\"></a><a class=\"link\" href=\"#dom.memory\">3.6. Memory management</a></h3>\n<div class=\"paragraph\">\n<p>pugixml requests the memory needed for document storage in big chunks, and allocates document data inside those chunks. This section discusses replacing functions used for chunk allocation and internal memory management implementation.</p>\n</div>\n<div class=\"sect3\">\n<h4 id=\"dom.memory.custom\"><a class=\"anchor\" href=\"#dom.memory.custom\"></a><a class=\"link\" href=\"#dom.memory.custom\">3.6.1. Custom memory allocation/deallocation functions</a></h4>\n<div class=\"paragraph\">\n<p><a id=\"allocation_function\"></a><a id=\"deallocation_function\"></a>\nAll memory for tree structure, tree data and XPath objects is allocated via globally specified functions, which default to malloc/free. You can set your own allocation functions with set_memory_management function. The function interfaces are the same as that of malloc/free:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">*</span><span class=\"tok-n\">allocation_function</span><span class=\"tok-p\">)(</span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">*</span><span class=\"tok-n\">deallocation_function</span><span class=\"tok-p\">)(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ptr</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"set_memory_management_functions\"></a><a id=\"get_memory_allocation_function\"></a><a id=\"get_memory_deallocation_function\"></a>\nYou can use the following accessor functions to change or get current memory management functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">set_memory_management_functions</span><span class=\"tok-p\">(</span><span class=\"tok-n\">allocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-n\">allocate</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">deallocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-n\">deallocate</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">allocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">get_memory_allocation_function</span><span class=\"tok-p\">();</span>\n<span class=\"tok-n\">deallocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">get_memory_deallocation_function</span><span class=\"tok-p\">();</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Allocation function is called with the size (in bytes) as an argument and should return a pointer to a memory block with alignment that is suitable for storage of primitive types (usually a maximum of <code>void*</code> and <code>double</code> types alignment is sufficient) and size that is greater than or equal to the requested one. If the allocation fails, the function has to either return null pointer or to throw an exception.</p>\n</div>\n<div class=\"paragraph\">\n<p>Deallocation function is called with the pointer that was returned by some call to allocation function; it is never called with a null pointer. If memory management functions are not thread-safe, library thread safety is not guaranteed.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of custom memory management (<a href=\"samples/custom_memory_management.cpp\" class=\"bare\">samples/custom_memory_management.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">custom_allocate</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-k\">new</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">nothrow</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-p\">[</span><span class=\"tok-n\">size</span><span class=\"tok-p\">];</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">custom_deallocate</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ptr</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">delete</span><span class=\"tok-p\">[]</span><span class=\"tok-w\"> </span><span class=\"tok-k\">static_cast</span><span class=\"tok-o\">&lt;</span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*&gt;</span><span class=\"tok-p\">(</span><span class=\"tok-n\">ptr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">set_memory_management_functions</span><span class=\"tok-p\">(</span><span class=\"tok-n\">custom_allocate</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">custom_deallocate</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>When setting new memory management functions, care must be taken to make sure that there are no live pugixml objects. Otherwise when the objects are destroyed, the new deallocation function will be called with the memory obtained by the old allocation function, resulting in undefined behavior.</p>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"dom.memory.tuning\"><a class=\"anchor\" href=\"#dom.memory.tuning\"></a><a class=\"link\" href=\"#dom.memory.tuning\">3.6.2. Memory consumption tuning</a></h4>\n<div class=\"paragraph\">\n<p>There are several important buffering optimizations in pugixml that rely on predefined constants. These constants have default values that were tuned for common usage patterns; for some applications, changing these constants might improve memory consumption or increase performance. Changing these constants is not recommended unless their default values result in visible problems.</p>\n</div>\n<div class=\"paragraph\">\n<p>These constants can be tuned via configuration defines, as discussed in <a href=\"#install.building.config\">Additional configuration options</a>; it is recommended to set them in <code>pugiconfig.hpp</code>.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><code>PUGIXML_MEMORY_PAGE_SIZE</code> controls the page size for document memory allocation. Memory for node/attribute objects is allocated in pages of the specified size. The default size is 32 Kb; for some applications the size is too large (i.e. embedded systems with little heap space or applications that keep lots of XML documents in memory). A minimum size of 1 Kb is recommended.</p>\n</li>\n<li>\n<p><code>PUGIXML_MEMORY_OUTPUT_STACK</code> controls the cumulative stack space required to output the node. Any output operation (i.e. saving a subtree to file) uses an internal buffering scheme for performance reasons. The default size is 10 Kb; if you&#8217;re using node output from threads with little stack space, decreasing this value can prevent stack overflows. A minimum size of 1 Kb is recommended.</p>\n</li>\n<li>\n<p><code>PUGIXML_MEMORY_XPATH_PAGE_SIZE</code> controls the page size for XPath memory allocation. Memory for XPath query objects as well as internal memory for XPath evaluation is allocated in pages of the specified size. The default size is 4 Kb; if you have a lot of resident XPath query objects, you might need to decrease the size to improve memory consumption. A minimum size of 256 bytes is recommended.</p>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"dom.memory.internals\"><a class=\"anchor\" href=\"#dom.memory.internals\"></a><a class=\"link\" href=\"#dom.memory.internals\">3.6.3. Document memory management internals</a></h4>\n<div class=\"paragraph\">\n<p>Constructing a document object using the default constructor does not result in any allocations; document node is stored inside the <a href=\"#xml_document\">xml_document</a> object.</p>\n</div>\n<div class=\"paragraph\">\n<p>When the document is loaded from file/buffer, unless an inplace loading function is used (see <a href=\"#loading.memory\">Loading document from memory</a>), a complete copy of character stream is made; all names/values of nodes and attributes are allocated in this buffer. This buffer is allocated via a single large allocation and is only freed when document memory is reclaimed (i.e. if the <a href=\"#xml_document\">xml_document</a> object is destroyed or if another document is loaded in the same object). Also when loading from file or stream, an additional large allocation may be performed if encoding conversion is required; a temporary buffer is allocated, and it is freed before load function returns.</p>\n</div>\n<div class=\"paragraph\">\n<p>All additional memory, such as memory for document structure (node/attribute objects) and memory for node/attribute names/values is allocated in pages on the order of 32 Kb; actual objects are allocated inside the pages using a memory management scheme optimized for fast allocation/deallocation of many small objects. Because of the scheme specifics, the pages are only destroyed if all objects inside them are destroyed; also, generally destroying an object does not mean that subsequent object creation will reuse the same memory. This means that it is possible to devise a usage scheme which will lead to higher memory usage than expected; one example is adding a lot of nodes, and them removing all even numbered ones; not a single page is reclaimed in the process. However this is an example specifically crafted to produce unsatisfying behavior; in all practical usage scenarios the memory consumption is less than that of a general-purpose allocator because allocation meta-data is very small in size.</p>\n</div>\n</div>\n<div class=\"sect3\">\n<h4 id=\"dom.memory.compact\"><a class=\"anchor\" href=\"#dom.memory.compact\"></a><a class=\"link\" href=\"#dom.memory.compact\">3.6.4. Compact mode</a></h4>\n<div class=\"paragraph\">\n<p>By default nodes and attributes are optimized for efficiency of access. This can cause them to take a significant amount of memory - for documents with a lot of nodes and not a lot of contents (short attribute values/node text), and depending on the pointer size, the document structure can take noticeably more memory than the document itself (e.g. on a 64-bit platform in UTF-8 mode a markup-heavy document with the file size of 2.1 Mb can use 2.1 Mb for document buffer and 8.3 Mb for document structure).</p>\n</div>\n<div class=\"paragraph\">\n<p>If you are processing big documents or your platform is memory constrained and you&#8217;re willing to sacrifice a bit of performance for memory, you can compile pugixml with <code>PUGIXML_COMPACT</code> define which will activate compact mode. Compact mode uses a different representation of the document structure that assumes locality of reference between nodes and attributes to optimize memory usage. As a result you get significantly smaller node/attribute objects; usually most objects in most documents don&#8217;t require additional storage, but in the worst case - if assumptions about locality of reference don&#8217;t hold - additional memory will be allocated to store the extra data required.</p>\n</div>\n<div class=\"paragraph\">\n<p>The compact storage supports all existing operations - including tree modification - with the same amortized complexity (that is, all basic document manipulations are still O(1) on average). The operations are slightly slower; you can usually expect 10-50% slowdown in terms of processing time unless your processing was memory-bound.</p>\n</div>\n<div class=\"paragraph\">\n<p>On 32-bit architectures document structure in compact mode is typically reduced by around 2.5x; on 64-bit architectures the ratio is around 5x. Thus for big markup-heavy documents compact mode can make the difference between the processing of a multi-gigabyte document running completely from RAM vs requiring swapping to disk. Even if the document fits into memory, compact storage can use CPU caches more efficiently by taking less space and causing less cache/TLB misses.</p>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"loading\"><a class=\"anchor\" href=\"#loading\"></a><a class=\"link\" href=\"#loading\">4. Loading document</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml provides several functions for loading XML data from various places - files, C&#43;&#43; iostreams, memory buffers. All functions use an extremely fast non-validating parser. This parser is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed for performance reasons. Also some XML transformations (i.e. EOL handling or attribute value normalization) can impact parsing speed and thus can be disabled. However for vast majority of XML documents there is no performance difference between different parsing options. Parsing options also control whether certain XML nodes are parsed; see <a href=\"#loading.options\">Parsing options</a> for more information.</p>\n</div>\n<div class=\"paragraph\">\n<p>XML data is always converted to internal character format (see <a href=\"#dom.unicode\">Unicode interface</a>) before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it&#8217;s a strict subset of UTF-16) as well as some non-Unicode encodings (Latin-1) and handles all encoding conversions automatically. Unless explicit encoding is specified, loading functions perform automatic encoding detection based on source XML data, so in most cases you do not have to specify document encoding. Encoding conversion is described in more detail in <a href=\"#loading.encoding\">Encodings</a>.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.file\"><a class=\"anchor\" href=\"#loading.file\"></a><a class=\"link\" href=\"#loading.file\">4.1. Loading document from file</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_document::load_file\"></a><a id=\"xml_document::load_file_wide\"></a>\nThe most common source of XML data is files; pugixml provides dedicated functions for loading an XML document from file:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_file</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_file</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions accept the file path as its first argument, and also two optional arguments, which specify parsing options (see <a href=\"#loading.options\">Parsing options</a>) and input data encoding (see <a href=\"#loading.encoding\">Encodings</a>). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc.</p>\n</div>\n<div class=\"paragraph\">\n<p>File path is passed to the system file opening function as is in case of the first function (which accepts <code>const char* path</code>); the second function either uses a special file opening function if it is provided by the runtime library or converts the path to UTF-8 and uses the system file opening function.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>load_file</code> destroys the existing document tree and then tries to load the new tree from the specified file. The result of the operation is returned in an <a href=\"#xml_parse_result\">xml_parse_result</a> object; this object contains the operation status and the related information (i.e. last successfully parsed position in the input file, if parsing fails). See <a href=\"#loading.errors\">Handling parsing errors</a> for error handling details.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of loading XML document from file (<a href=\"samples/load_file.cpp\" class=\"bare\">samples/load_file.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_file</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;tree.xml&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Load result: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, mesh name: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;mesh&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.memory\"><a class=\"anchor\" href=\"#loading.memory\"></a><a class=\"link\" href=\"#loading.memory\">4.2. Loading document from memory</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_document::load_buffer\"></a><a id=\"xml_document::load_buffer_inplace\"></a><a id=\"xml_document::load_buffer_inplace_own\"></a>\nSometimes XML data should be loaded from some other source than a file, i.e. HTTP URL; also you may want to load XML data from file using non-standard functions, i.e. to use your virtual file system facilities or to load XML from GZip-compressed files. All these scenarios require loading document from memory. First you should prepare a contiguous memory block with all XML data; then you have to invoke one of buffer loading functions. These functions will handle the necessary encoding conversions, if any, and then will parse the data into the corresponding XML tree. There are several buffer loading functions, which differ in the behavior and thus in performance/memory usage:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_buffer</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_buffer_inplace</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_buffer_inplace_own</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>All functions accept the buffer which is represented by a pointer to XML data, <code>contents</code>, and data size in bytes. Also there are two optional arguments, which specify parsing options (see <a href=\"#loading.options\">Parsing options</a>) and input data encoding (see <a href=\"#loading.encoding\">Encodings</a>). The buffer does not have to be zero-terminated.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>load_buffer</code> function works with immutable buffer - it does not ever modify the buffer. Because of this restriction it has to create a private buffer and copy XML data to it before parsing (applying encoding conversions if necessary). This copy operation carries a performance penalty, so inplace functions are provided - <code>load_buffer_inplace</code> and <code>load_buffer_inplace_own</code> store the document data in the buffer, modifying it in the process. In order for the document to stay valid, you have to make sure that the buffer&#8217;s lifetime exceeds that of the tree if you&#8217;re using inplace functions. In addition to that, <code>load_buffer_inplace</code> does not assume ownership of the buffer, so you&#8217;ll have to destroy it yourself; <code>load_buffer_inplace_own</code> assumes ownership of the buffer and destroys it once it is not needed. This means that if you&#8217;re using <code>load_buffer_inplace_own</code>, you have to allocate memory with pugixml allocation function (you can get it via <a href=\"#get_memory_allocation_function\">get_memory_allocation_function</a>).</p>\n</div>\n<div class=\"paragraph\">\n<p>The best way from the performance/memory point of view is to load document using <code>load_buffer_inplace_own</code>; this function has maximum control of the buffer with XML data so it is able to avoid redundant copies and reduce peak memory usage while parsing. This is the recommended function if you have to load the document from memory and performance is critical.</p>\n</div>\n<div id=\"xml_document::load_string\" class=\"paragraph\">\n<p>There is also a simple helper function for cases when you want to load the XML document from null-terminated character string:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load_string</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>It is equivalent to calling <code>load_buffer</code> with <code>size</code> being either <code>strlen(contents)</code> or <code>wcslen(contents) * sizeof(wchar_t)</code>, depending on the character type. This function assumes native encoding for input data, so it does not do any encoding conversion. In general, this function is fine for loading small documents from string literals, but has more overhead and less functionality than the buffer loading functions.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of loading XML document from memory using different functions (<a href=\"samples/load_memory.cpp\" class=\"bare\">samples/load_memory.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-p\">[]</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&lt;mesh name=&#39;sphere&#39;&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-k\">sizeof</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// You can use load_buffer to load document from immutable memory block:</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_buffer</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// You can use load_buffer_inplace to load document from mutable memory block; the block&#39;s lifetime must exceed that of document</span>\n<span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-k\">new</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-p\">[</span><span class=\"tok-n\">size</span><span class=\"tok-p\">];</span>\n<span class=\"tok-n\">memcpy</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// The block can be allocated by any method; the block is modified during parsing</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_buffer_inplace</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// You have to destroy the block yourself after the document is no longer used</span>\n<span class=\"tok-k\">delete</span><span class=\"tok-p\">[]</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block</span>\n<span class=\"tok-c1\">// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect</span>\n<span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-k\">static_cast</span><span class=\"tok-o\">&lt;</span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*&gt;</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">get_memory_allocation_function</span><span class=\"tok-p\">()(</span><span class=\"tok-n\">size</span><span class=\"tok-p\">));</span>\n<span class=\"tok-n\">memcpy</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// The block will be deleted by the document</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_buffer_inplace_own</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// You can use load to load document from null-terminated strings, for example literals:</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;&lt;mesh name=&#39;sphere&#39;&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;&quot;</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.stream\"><a class=\"anchor\" href=\"#loading.stream\"></a><a class=\"link\" href=\"#loading.stream\">4.3. Loading document from C&#43;&#43; IOstreams</a></h3>\n<div id=\"xml_document::load_stream\" class=\"paragraph\">\n<p>To enhance interoperability, pugixml provides functions for loading document from any object which implements C&#43;&#43; <code>std::istream</code> interface. This allows you to load documents from any standard C&#43;&#43; stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). There are two functions, one works with narrow character streams, another handles wide character ones:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">istream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_document::load</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wistream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>load</code> with <code>std::istream</code> argument loads the document from stream from the current read position to the end, treating the stream contents as a byte stream of the specified encoding (with encoding autodetection as necessary). Thus calling <code>xml_document::load</code> on an opened <code>std::ifstream</code> object is equivalent to calling <code>xml_document::load_file</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>load</code> with <code>std::wstream</code> argument treats the stream contents as a wide character stream (encoding is always <a href=\"#encoding_wchar\">encoding_wchar</a>). Because of this, using <code>load</code> with wide character streams requires careful (usually platform-specific) stream setup (i.e. using the <code>imbue</code> function). Generally use of wide streams is discouraged, however it provides you the ability to load documents from non-Unicode encodings, i.e. you can load Shift-JIS encoded data if you set the correct locale.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of loading XML document from file using streams (<a href=\"samples/load_stream.cpp\" class=\"bare\">samples/load_stream.cpp</a>); read the sample code for more complex examples involving wide streams and locales:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ifstream</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;weekly-utf-8.xml&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load</span><span class=\"tok-p\">(</span><span class=\"tok-n\">stream</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.errors\"><a class=\"anchor\" href=\"#loading.errors\"></a><a class=\"link\" href=\"#loading.errors\">4.4. Handling parsing errors</a></h3>\n<div id=\"xml_parse_result\" class=\"paragraph\">\n<p>All document loading functions return the parsing result via <code>xml_parse_result</code> object. It contains parsing status, the offset of last successfully parsed character from the beginning of the source stream, and the encoding of the source stream:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_parse_result</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_status</span><span class=\"tok-w\"> </span><span class=\"tok-n\">status</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">offset</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_parse_status\"></a><a id=\"xml_parse_result::status\"></a>\nParsing status is represented as the <code>xml_parse_status</code> enumeration and can be one of the following:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"status_ok\"></a><code>status_ok</code> means that no error was encountered during parsing; the source stream represents the valid XML document which was fully parsed and converted to a tree.</p>\n</li>\n<li>\n<p><a id=\"status_file_not_found\"></a><code>status_file_not_found</code> is only returned by <code>load_file</code> function and means that file could not be opened.</p>\n</li>\n<li>\n<p><a id=\"status_io_error\"></a><code>status_io_error</code> is returned by <code>load_file</code> function and by <code>load</code> functions with <code>std::istream</code>/<code>std::wstream</code> arguments; it means that some I/O error has occurred during reading the file/stream.</p>\n</li>\n<li>\n<p><a id=\"status_out_of_memory\"></a><code>status_out_of_memory</code> means that there was not enough memory during some allocation; any allocation failure during parsing results in this error.</p>\n</li>\n<li>\n<p><a id=\"status_internal_error\"></a><code>status_internal_error</code> means that something went horribly wrong; currently this error does not occur</p>\n</li>\n<li>\n<p><a id=\"status_unrecognized_tag\"></a><code>status_unrecognized_tag</code> means that parsing stopped due to a tag with either an empty name or a name which starts with incorrect character, such as <code>#</code>.</p>\n</li>\n<li>\n<p><a id=\"status_bad_pi\"></a><code>status_bad_pi</code> means that parsing stopped due to incorrect document declaration/processing instruction</p>\n</li>\n<li>\n<p><a id=\"status_bad_comment\"></a><code>status_bad_comment</code>, <a id=\"status_bad_cdata\"></a><code>status_bad_cdata</code>, <a id=\"status_bad_doctype\"></a><code>status_bad_doctype</code> and <a id=\"status_bad_pcdata\"></a><code>status_bad_pcdata</code> mean that parsing stopped due to the invalid construct of the respective type</p>\n</li>\n<li>\n<p><a id=\"status_bad_start_element\"></a><code>status_bad_start_element</code> means that parsing stopped because starting tag either had no closing <code>&gt;</code> symbol or contained some incorrect symbol</p>\n</li>\n<li>\n<p><a id=\"status_bad_attribute\"></a><code>status_bad_attribute</code> means that parsing stopped because there was an incorrect attribute, such as an attribute without value or with value that is not quoted (note that <code>&lt;node attr=1&gt;</code> is incorrect in XML)</p>\n</li>\n<li>\n<p><a id=\"status_bad_end_element\"></a><code>status_bad_end_element</code> means that parsing stopped because ending tag had incorrect syntax (i.e. extra non-whitespace symbols between tag name and <code>&gt;</code>)</p>\n</li>\n<li>\n<p><a id=\"status_end_element_mismatch\"></a><code>status_end_element_mismatch</code> means that parsing stopped because the closing tag did not match the opening one (i.e. <code>&lt;node&gt;&lt;/nedo&gt;</code>) or because some tag was not closed at all</p>\n</li>\n<li>\n<p><a id=\"status_no_document_element\"></a><code>status_no_document_element</code> means that no element nodes were discovered during parsing; this usually indicates an empty or invalid document</p>\n</li>\n</ul>\n</div>\n<div id=\"xml_parse_result::description\" class=\"paragraph\">\n<p><code>description()</code> member function can be used to convert parsing status to a string; the returned message is always in English, so you&#8217;ll have to write your own function if you need a localized string. However please note that the exact messages returned by <code>description()</code> function may change from version to version, so any complex status handling should be based on <code>status</code> value. Note that <code>description()</code> returns a <code>char</code> string even in <code>PUGIXML_WCHAR_MODE</code>; you&#8217;ll have to call <a href=\"#as_wide\">as_wide</a> to get the <code>wchar_t</code> string.</p>\n</div>\n<div class=\"paragraph\">\n<p>If parsing failed because the source data was not a valid XML, the resulting tree is not destroyed - despite the fact that load function returns error, you can use the part of the tree that was successfully parsed. Obviously, the last element may have an unexpected name/value; for example, if the attribute value does not end with the necessary quotation mark, like in <code>&lt;node attr=\"value&gt;some data&lt;/node&gt;</code> example, the value of attribute <code>attr</code> will contain the string <code>value&gt;some data&lt;/node&gt;</code>.</p>\n</div>\n<div id=\"xml_parse_result::offset\" class=\"paragraph\">\n<p>In addition to the status code, parsing result has an <code>offset</code> member, which contains the offset of last successfully parsed character if parsing failed because of an error in source data; otherwise <code>offset</code> is 0. For parsing efficiency reasons, pugixml does not track the current line during parsing; this offset is in units of <a href=\"#char_t\">pugi::char_t</a> (bytes for character mode, wide characters for wide character mode). Many text editors support 'Go To Position' feature - you can use it to locate the exact error position. Alternatively, if you&#8217;re loading the document from memory, you can display the error chunk along with the error description (see the example code below).</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nOffset is calculated in the XML buffer in native encoding; if encoding conversion is performed during parsing, offset can not be used to reliably track the error position.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"xml_parse_result::encoding\" class=\"paragraph\">\n<p>Parsing result also has an <code>encoding</code> member, which can be used to check that the source data encoding was correctly guessed. It is equal to the exact encoding used during parsing (i.e. with the exact endianness); see <a href=\"#loading.encoding\">Encodings</a> for more information.</p>\n</div>\n<div id=\"xml_parse_result::bool\" class=\"paragraph\">\n<p>Parsing result object can be implicitly converted to <code>bool</code>; if you do not want to handle parsing errors thoroughly, you can just check the return value of load functions as if it was a <code>bool</code>: <code>if (doc.load_file(\"file.xml\")) { &#8230;&#8203; } else { &#8230;&#8203; }</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of handling loading errors (<a href=\"samples/load_error_handling.cpp\" class=\"bare\">samples/load_error_handling.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">result</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;XML [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;] parsed without errors, attr value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;attr&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n<span class=\"tok-k\">else</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;XML [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;] parsed with errors, attr value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;attr&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Error description: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Error offset: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">offset</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; (error at [...&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">+</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">offset</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.options\"><a class=\"anchor\" href=\"#loading.options\"></a><a class=\"link\" href=\"#loading.options\">4.5. Parsing options</a></h3>\n<div class=\"paragraph\">\n<p>All document loading functions accept the optional parameter <code>options</code>. This is a bitmask that customizes the parsing process: you can select the node types that are parsed and various transformations that are performed with the XML text. Disabling certain transformations can improve parsing performance for some documents; however, the code for all transformations is very well optimized, and thus the majority of documents won&#8217;t get any performance benefit. As a rule of thumb, only modify parsing flags if you want to get some nodes in the document that are excluded by default (i.e. declaration or comment nodes).</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nYou should use the usual bitwise arithmetics to manipulate the bitmask: to enable a flag, use <code>mask | flag</code>; to disable a flag, use <code>mask &amp; ~flag</code>.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>These flags control the resulting tree contents:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"parse_declaration\"></a><code>parse_declaration</code> determines if XML document declaration (node with type <a href=\"#node_declaration\">node_declaration</a>) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_doctype\"></a><code>parse_doctype</code> determines if XML document type declaration (node with type <a href=\"#node_doctype\">node_doctype</a>) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_pi\"></a><code>parse_pi</code> determines if processing instructions (nodes with type <a href=\"#node_pi\">node_pi</a>) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. Note that <code>&lt;?xml &#8230;&#8203;?&gt;</code> (document declaration) is not considered to be a PI. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_comments\"></a><code>parse_comments</code> determines if comments (nodes with type <a href=\"#node_comment\">node_comment</a>) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_cdata\"></a><code>parse_cdata</code> determines if CDATA sections (nodes with type <a href=\"#node_cdata\">node_cdata</a>) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is <strong>on</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_trim_pcdata\"></a><code>parse_trim_pcdata</code> determines if leading and trailing whitespace characters are to be removed from PCDATA nodes. While for some applications leading/trailing whitespace is significant, often the application only cares about the non-whitespace contents so it&#8217;s easier to trim whitespace from text during parsing. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_ws_pcdata\"></a><code>parse_ws_pcdata</code> determines if PCDATA nodes (nodes with type <a href=\"#node_pcdata\">node_pcdata</a>) that consist only of whitespace characters are to be put in DOM tree. Often whitespace-only data is not significant for the application, and the cost of allocating and storing such nodes (both memory and speed-wise) can be significant. For example, after parsing XML string <code>&lt;node&gt; &lt;a/&gt; &lt;/node&gt;</code>, <code>&lt;node&gt;</code> element will have three children when <code>parse_ws_pcdata</code> is set (child with type <a href=\"#node_pcdata\">node_pcdata</a> and value <code>\" \"</code>, child with type <a href=\"#node_element\">node_element</a> and name <code>\"a\"</code>, and another child with type <a href=\"#node_pcdata\">node_pcdata</a> and value <code>\" \"</code>), and only one child when <code>parse_ws_pcdata</code> is not set. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_ws_pcdata_single\"></a><code>parse_ws_pcdata_single</code> determines if whitespace-only PCDATA nodes that have no sibling nodes are to be put in DOM tree. In some cases application needs to parse the whitespace-only contents of nodes, i.e. <code>&lt;node&gt;  &lt;/node&gt;</code>, but is not interested in whitespace markup elsewhere. It is possible to use <a href=\"#parse_ws_pcdata\">parse_ws_pcdata</a> flag in this case, but it results in excessive allocations and complicates document processing; this flag can be used to avoid that. As an example, after parsing XML string <code>&lt;node&gt; &lt;a&gt;  &lt;/a&gt; &lt;/node&gt;</code> with <code>parse_ws_pcdata_single</code> flag set, <code>&lt;node&gt;</code> element will have one child <code>&lt;a&gt;</code>, and <code>&lt;a&gt;</code> element will have one child with type <a href=\"#node_pcdata\">node_pcdata</a> and value <code>\"  \"</code>. This flag has no effect if <a href=\"#parse_ws_pcdata\">parse_ws_pcdata</a> is enabled. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_embed_pcdata\"></a><code>parse_embed_pcdata</code> determines if PCDATA contents is to be saved as element values. Normally element nodes have names but not values; this flag forces the parser to store the contents as a value if PCDATA is the first child of the element node (otherwise PCDATA node is created as usual). This can significantly reduce the memory required for documents with many PCDATA nodes. To retrieve the data you can use <code>xml_node::value()</code> on the element nodes or any of the higher-level functions like <code>child_value</code> or <code>text</code>. This flag is <strong>off</strong> by default.\nSince this flag significantly changes the DOM structure it is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_merge_pcdata\"></a><code>parse_merge_pcdata</code> determines if PCDATA contents is to be merged with the previous PCDATA node when no intermediary nodes are present between them. If the PCDATA contains CDATA sections, PI nodes, or comments in between, and either of the flags <a href=\"#parse_cdata\">parse_cdata</a> ,<a href=\"#parse_pi\">parse_pi</a> ,<a href=\"#parse_comments\">parse_comments</a> is not set, the contents of the PCDATA node will be merged with the previous one. This flag is <strong>off</strong> by default. Note that this flag is not compatible with <code>parse_embed_pcdata</code>.</p>\n</li>\n<li>\n<p><a id=\"parse_fragment\"></a><code>parse_fragment</code> determines if document should be treated as a fragment of a valid XML. Parsing document as a fragment leads to top-level PCDATA content (i.e. text that is not located inside a node) to be added to a tree, and additionally treats documents without element nodes as valid and permits multiple top-level element nodes (currently multiple top-level element nodes are also permitted when the flag is off, but that behavior should not be relied on). This flag is <strong>off</strong> by default.</p>\n</li>\n</ul>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nUsing in-place parsing (<a href=\"#xml_document::load_buffer_inplace\">load_buffer_inplace</a>) with <code>parse_fragment</code> flag may result in the loss of the last character of the buffer if it is a part of PCDATA. Since PCDATA values are null-terminated strings, the only way to resolve this is to provide a null-terminated buffer as an input to <code>load_buffer_inplace</code> - i.e. <code>doc.load_buffer_inplace(\"test\\0\", 5, pugi::parse_default | pugi::parse_fragment)</code>.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>These flags control the transformation of tree element contents:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"parse_escapes\"></a><code>parse_escapes</code> determines if character and entity references are to be expanded during the parsing process. Character references have the form <code>&amp;#&#8230;&#8203;;</code> or <code>&amp;#x&#8230;&#8203;;</code> (<code>&#8230;&#8203;</code> is Unicode numeric representation of character in either decimal (<code>&amp;#&#8230;&#8203;;</code>) or hexadecimal (<code>&amp;#x&#8230;&#8203;;</code>) form), entity references are <code>&amp;lt;</code>, <code>&amp;gt;</code>, <code>&amp;amp;</code>, <code>&amp;apos;</code> and <code>&amp;quot;</code> (note that as pugixml does not handle DTD, the only allowed entities are predefined ones). If character/entity reference can not be expanded, it is left as is, so you can do additional processing later. Reference expansion is performed on attribute values and PCDATA content. This flag is <strong>on</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_eol\"></a><code>parse_eol</code> determines if EOL handling (that is, replacing sequences <code>\\r\\n</code> by a single <code>\\n</code> character, and replacing all standalone <code>\\r</code> characters by <code>\\n</code>) is to be performed on input data (that is, comment contents, PCDATA/CDATA contents and attribute values). This flag is <strong>on</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_wconv_attribute\"></a><code>parse_wconv_attribute</code> determines if attribute value normalization should be performed for all attributes. This means, that whitespace characters (new line, tab and space) are replaced with space (<code>' '</code>). New line characters are always treated as if <a href=\"#parse_eol\">parse_eol</a> is set, i.e. <code>\\r\\n</code> is converted to a single space.  This flag is <strong>on</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"parse_wnorm_attribute\"></a><code>parse_wnorm_attribute</code> determines if extended attribute value normalization should be performed for all attributes. This means, that after attribute values are normalized as if <a href=\"#parse_wconv_attribute\">parse_wconv_attribute</a> was set, leading and trailing space characters are removed, and all sequences of space characters are replaced by a single space character. <a href=\"#parse_wconv_attribute\">parse_wconv_attribute</a> has no effect if this flag is on. This flag is <strong>off</strong> by default.</p>\n</li>\n</ul>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\n<code>parse_wconv_attribute</code> option performs transformations that are required by W3C specification for attributes that are declared as CDATA; <a href=\"#parse_wnorm_attribute\">parse_wnorm_attribute</a> performs transformations required for NMTOKENS attributes. In the absence of document type declaration all attributes should behave as if they are declared as CDATA, thus <a href=\"#parse_wconv_attribute\">parse_wconv_attribute</a> is the default option.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>Additionally there are three predefined option masks:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"parse_minimal\"></a><code>parse_minimal</code> has all options turned off. This option mask means that pugixml does not add declaration nodes, document type declaration nodes, PI nodes, CDATA sections and comments to the resulting tree and does not perform any conversion for input data, so theoretically it is the fastest mode. However, as mentioned above, in practice <a href=\"#parse_default\">parse_default</a> is usually equally fast.</p>\n</li>\n<li>\n<p><a id=\"parse_default\"></a><code>parse_default</code> is the default set of flags, i.e. it has all options set to their default values. It includes parsing CDATA sections (comments/PIs are not parsed), performing character and entity reference expansion, replacing whitespace characters with spaces in attribute values and performing EOL handling. Note, that PCDATA sections consisting only of whitespace characters are not parsed (by default) for performance reasons.</p>\n</li>\n<li>\n<p><a id=\"parse_full\"></a><code>parse_full</code> is the set of flags which adds nodes of all types to the resulting tree and performs default conversions for input data. It includes parsing CDATA sections, comments, PI nodes, document declaration node and document type declaration node, performing character and entity reference expansion, replacing whitespace characters with spaces in attribute values and performing EOL handling. Note, that PCDATA sections consisting only of whitespace characters are not parsed in this mode.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using different parsing options (<a href=\"samples/load_options.cpp\" class=\"bare\">samples/load_options.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&lt;!--comment--&gt;&lt;node&gt;&amp;lt;&lt;/node&gt;&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Parsing with default options; note that comment node is not added to the tree, and entity reference &amp;lt; is expanded</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;First node value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;], node child value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Parsing with additional parse_comments option; comment node is now added to the tree</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_default</span><span class=\"tok-w\"> </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_comments</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;First node value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;], node child value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Parsing with additional parse_comments option and without the (default) parse_escapes option; &amp;lt; is not expanded</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_default</span><span class=\"tok-w\"> </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_comments</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">~</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_escapes</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;First node value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;], node child value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Parsing with minimal option mask; comment node is not added to the tree, and &amp;lt; is not expanded</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_minimal</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;First node value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;], node child value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.encoding\"><a class=\"anchor\" href=\"#loading.encoding\"></a><a class=\"link\" href=\"#loading.encoding\">4.6. Encodings</a></h3>\n<div id=\"xml_encoding\" class=\"paragraph\">\n<p>pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it&#8217;s a strict subset of UTF-16) as well as some non-Unicode encodings (Latin-1) and handles all encoding conversions. Most loading functions accept the optional parameter <code>encoding</code>. This is a value of enumeration type <code>xml_encoding</code>, that can have the following values:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"encoding_auto\"></a><code>encoding_auto</code> means that pugixml will try to guess the encoding based on source XML data. The algorithm is a modified version of the one presented in <a href=\"http://www.w3.org/TR/REC-xml/#sec-guessing\">Appendix F of XML recommendation</a>. It tries to find a Byte Order Mark of one of the supported encodings first; if that fails, it checks if the first few bytes of the input data look like a representation of <code>&lt;</code> or <code>&lt;?</code> in one of UTF-16 or UTF-32 variants; if that fails as well, encoding is assumed to be either UTF-8 or one of the non-Unicode encodings - to make the final decision the algorithm tries to parse the <code>encoding</code> attribute of the XML document declaration, ultimately falling back to UTF-8 if document declaration is not present or does not specify a supported encoding.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf8\"></a><code>encoding_utf8</code> corresponds to UTF-8 encoding as defined in the Unicode standard; UTF-8 sequences with length equal to 5 or 6 are not standard and are rejected.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf16_le\"></a><code>encoding_utf16_le</code> corresponds to little-endian UTF-16 encoding as defined in the Unicode standard; surrogate pairs are supported.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf16_be\"></a><code>encoding_utf16_be</code> corresponds to big-endian UTF-16 encoding as defined in the Unicode standard; surrogate pairs are supported.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf16\"></a><code>encoding_utf16</code> corresponds to UTF-16 encoding as defined in the Unicode standard; the endianness is assumed to be that of the target platform.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf32_le\"></a><code>encoding_utf32_le</code> corresponds to little-endian UTF-32 encoding as defined in the Unicode standard.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf32_be\"></a><code>encoding_utf32_be</code> corresponds to big-endian UTF-32 encoding as defined in the Unicode standard.</p>\n</li>\n<li>\n<p><a id=\"encoding_utf32\"></a><code>encoding_utf32</code> corresponds to UTF-32 encoding as defined in the Unicode standard; the endianness is assumed to be that of the target platform.</p>\n</li>\n<li>\n<p><a id=\"encoding_wchar\"></a><code>encoding_wchar</code> corresponds to the encoding of <code>wchar_t</code> type; it has the same meaning as either <code>encoding_utf16</code> or <code>encoding_utf32</code>, depending on <code>wchar_t</code> size.</p>\n</li>\n<li>\n<p><a id=\"encoding_latin1\"></a><code>encoding_latin1</code> corresponds to ISO-8859-1 encoding (also known as Latin-1).</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>The algorithm used for <code>encoding_auto</code> correctly detects any supported Unicode encoding for all well-formed XML documents (since they start with document declaration) and for all other XML documents that start with <code>&lt;</code>; if your XML document does not start with <code>&lt;</code> and has encoding that is different from UTF-8, use the specific encoding.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nThe current behavior for Unicode conversion is to skip all invalid UTF sequences during conversion. This behavior should not be relied upon; moreover, in case no encoding conversion is performed, the invalid sequences are not removed, so you&#8217;ll get them as is in node/attribute contents.\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"loading.w3c\"><a class=\"anchor\" href=\"#loading.w3c\"></a><a class=\"link\" href=\"#loading.w3c\">4.7. Conformance to W3C specification</a></h3>\n<div class=\"paragraph\">\n<p>pugixml is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed because of performance reasons.</p>\n</div>\n<div class=\"paragraph\">\n<p>There is only one non-conformant behavior when dealing with valid XML documents: pugixml does not use information supplied in document type declaration for parsing. This means that entities declared in DOCTYPE are not expanded, and all attribute/PCDATA values are always processed in a uniform way that depends only on parsing options.</p>\n</div>\n<div class=\"paragraph\">\n<p>As for rejecting invalid XML documents, there are a number of incompatibilities with W3C specification, including:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Multiple attributes of the same node can have equal names.</p>\n</li>\n<li>\n<p>Tag and attribute names are not fully validated for consisting of allowed characters, so some invalid tags are not rejected</p>\n</li>\n<li>\n<p>Attribute values which contain <code>&lt;</code> are not rejected.</p>\n</li>\n<li>\n<p>Invalid entity/character references are not rejected and are instead left as is.</p>\n</li>\n<li>\n<p>Comment values can contain <code>--</code>.</p>\n</li>\n<li>\n<p>XML data is not required to begin with document declaration; additionally, document declaration can appear after comments and other nodes.</p>\n</li>\n<li>\n<p>Invalid document type declarations are silently ignored in some cases.</p>\n</li>\n<li>\n<p>Unicode validation is not performed so invalid UTF sequences are not rejected.</p>\n</li>\n<li>\n<p>Document can contain multiple top-level element nodes.</p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"access\"><a class=\"anchor\" href=\"#access\"></a><a class=\"link\" href=\"#access\">5. Accessing document data</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml features an extensive interface for getting various types of data from the document and for traversing the document. This section provides documentation for all such functions that do not modify the tree except for XPath-related functions; see <a href=\"#xpath\">XPath</a> for XPath reference. As discussed in <a href=\"#dom.cpp\">C&#43;&#43; interface</a>, there are two types of handles to tree data - <a href=\"#xml_node\">xml_node</a> and <a href=\"#xml_attribute\">xml_attribute</a>. The handles have special null (empty) values which propagate through various functions and thus are useful for writing more concise code; see <a href=\"#node_null\">this description</a> for details. The documentation in this section will explicitly state the results of all function in case of null inputs.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.basic\"><a class=\"anchor\" href=\"#access.basic\"></a><a class=\"link\" href=\"#access.basic\">5.1. Basic traversal functions</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::parent\"></a><a id=\"xml_node::first_child\"></a><a id=\"xml_node::last_child\"></a><a id=\"xml_node::next_sibling\"></a><a id=\"xml_node::previous_sibling\"></a><a id=\"xml_node::first_attribute\"></a><a id=\"xml_node::last_attribute\"></a><a id=\"xml_attribute::next_attribute\"></a><a id=\"xml_attribute::previous_attribute\"></a>\nThe internal representation of the document is a tree, where each node has a list of child nodes (the order of children corresponds to their order in the XML representation), and additionally element nodes have a list of attributes, which is also ordered. Several functions are provided in order to let you get from one node in the tree to the other. These functions roughly correspond to the internal representation, and thus are usually building blocks for other methods of traversing (i.e. XPath traversals are based on these functions).</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::parent</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::first_child</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::last_child</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::next_sibling</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::previous_sibling</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::first_attribute</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::last_attribute</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::next_attribute</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::previous_attribute</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>parent</code> function returns the node&#8217;s parent; all non-null nodes except the document have non-null parent. <code>first_child</code> and <code>last_child</code> return the first and last child of the node, respectively; note that only document nodes and element nodes can have non-empty child node list. If node has no children, both functions return null nodes. <code>next_sibling</code> and <code>previous_sibling</code> return the node that&#8217;s immediately to the right/left of this node in the children list, respectively - for example, in <code>&lt;a/&gt;&lt;b/&gt;&lt;c/&gt;</code>, calling <code>next_sibling</code> for a handle that points to <code>&lt;b/&gt;</code> results in a handle pointing to <code>&lt;c/&gt;</code>, and calling <code>previous_sibling</code> results in handle pointing to <code>&lt;a/&gt;</code>. If node does not have next/previous sibling (this happens if it is the last/first node in the list, respectively), the functions return null nodes. <code>first_attribute</code>, <code>last_attribute</code>, <code>next_attribute</code> and <code>previous_attribute</code> functions behave similarly to the corresponding child node functions and allow to iterate through attribute list in the same way.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nBecause of memory consumption reasons, attributes do not have a link to their parent nodes. Thus there is no <code>xml_attribute::parent()</code> function.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>Calling any of the functions above on the null handle results in a null handle - i.e. <code>node.first_child().next_sibling()</code> returns the second child of <code>node</code>, and null handle if <code>node</code> is null, has no children at all or if it has only one child node.</p>\n</div>\n<div class=\"paragraph\">\n<p>With these functions, you can iterate through all child nodes and display all attributes like this (<a href=\"samples/traverse_base.cpp\" class=\"bare\">samples/traverse_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">())</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool:&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_attribute</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_attribute</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.nodedata\"><a class=\"anchor\" href=\"#access.nodedata\"></a><a class=\"link\" href=\"#access.nodedata\">5.2. Getting node data</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::name\"></a><a id=\"xml_node::value\"></a>\nApart from structural information (parent, child nodes, attributes), nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. <a href=\"#node_document\">node_document</a> nodes do not have a name or value, <a href=\"#node_element\">node_element</a> and <a href=\"#node_declaration\">node_declaration</a> nodes always have a name but never have a value, <a href=\"#node_pcdata\">node_pcdata</a>, <a href=\"#node_cdata\">node_cdata</a>, <a href=\"#node_comment\">node_comment</a> and <a href=\"#node_doctype\">node_doctype</a> nodes never have a name but always have a value (it may be empty though), <a href=\"#node_pi\">node_pi</a> nodes always have a name and a value (again, value may be empty). In order to get node&#8217;s name or value, you can use the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>In case node does not have a name or value or if the node handle is null, both functions return empty strings - they never return null pointers.</p>\n</div>\n<div id=\"xml_node::child_value\" class=\"paragraph\">\n<p>It is common to store data as text contents of some node - i.e. <code>&lt;node&gt;&lt;description&gt;This is a node&lt;/description&gt;&lt;/node&gt;</code>. In this case, <code>&lt;description&gt;</code> node does not have a value, but instead has a child of type <a href=\"#node_pcdata\">node_pcdata</a> with value <code>\"This is a node\"</code>. pugixml provides several helper functions to parse such data:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::child_value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::child_value</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::text</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>child_value()</code> returns the value of the first child with type <a href=\"#node_pcdata\">node_pcdata</a> or <a href=\"#node_cdata\">node_cdata</a>; <code>child_value(name)</code> is a simple wrapper for <code>child(name).child_value()</code>. For the above example, calling <code>node.child_value(\"description\")</code> and <code>description.child_value()</code> will both produce string <code>\"This is a node\"</code>. If there is no child with relevant type, or if the handle is null, <code>child_value</code> functions return empty string.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>text()</code> returns a special object that can be used for working with PCDATA contents in more complex cases than just retrieving the value; it is described in <a href=\"#access.text\">Working with text contents</a> sections.</p>\n</div>\n<div class=\"paragraph\">\n<p>There is an example of using some of these functions <a href=\"#code_traverse_base_data\">at the end of the next section</a>.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.attrdata\"><a class=\"anchor\" href=\"#access.attrdata\"></a><a class=\"link\" href=\"#access.attrdata\">5.3. Getting attribute data</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::name\"></a><a id=\"xml_attribute::value\"></a>\nAll attributes have name and value, both of which are strings (value may be empty). There are two corresponding accessors, like for <code>xml_node</code>:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>In case the attribute handle is null, both functions return empty strings - they never return null pointers.</p>\n</div>\n<div id=\"xml_attribute::as_string\" class=\"paragraph\">\n<p>If you need a non-empty string if the attribute handle is null (for example, you need to get the option value from XML attribute, but if it is not specified, you need it to default to <code>\"sorted\"</code> instead of <code>\"\"</code>), you can use <code>as_string</code> accessor:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-n\">as_string</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>It returns <code>def</code> argument if the attribute handle is null. If you do not specify the argument, the function is equivalent to <code>value()</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::as_int\"></a><a id=\"xml_attribute::as_uint\"></a><a id=\"xml_attribute::as_double\"></a><a id=\"xml_attribute::as_float\"></a><a id=\"xml_attribute::as_bool\"></a><a id=\"xml_attribute::as_llong\"></a><a id=\"xml_attribute::as_ullong\"></a>\nIn many cases attribute values have types that are not strings - i.e. an attribute may always contain values that should be treated as integers, despite the fact that they are represented as strings in XML. pugixml provides several accessors that convert attribute value to some other type:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_int</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_uint</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_double</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_float</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_bool</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_llong</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::as_ullong</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>as_int</code>, <code>as_uint</code>, <code>as_llong</code>, <code>as_ullong</code>, <code>as_double</code> and <code>as_float</code> convert attribute values to numbers. If attribute handle is null <code>def</code> argument is returned (which is 0 by default). Otherwise, all leading whitespace characters are truncated, and the remaining string is parsed as an integer number in either decimal or hexadecimal form (applicable to <code>as_int</code>, <code>as_uint</code>, <code>as_llong</code> and <code>as_ullong</code>; hexadecimal format is used if the number has <code>0x</code> or <code>0X</code> prefix) or as a floating point number in either decimal or scientific form (<code>as_double</code> or <code>as_float</code>).</p>\n</div>\n<div class=\"paragraph\">\n<p>In case the input string contains a non-numeric character sequence or a number that is out of the target numeric range, the result is undefined.</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nNumber conversion functions depend on current C locale as set with <code>setlocale</code>, so may return unexpected results if the locale is different from <code>\"C\"</code>.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p><code>as_bool</code> converts attribute value to boolean as follows: if attribute handle is null, <code>def</code> argument is returned (which is <code>false</code> by default). If attribute value is empty, <code>false</code> is returned. Otherwise, <code>true</code> is returned if the first character is one of <code>'1', 't', 'T', 'y', 'Y'</code>. This means that strings like <code>\"true\"</code> and <code>\"yes\"</code> are recognized as <code>true</code>, while strings like <code>\"false\"</code> and <code>\"no\"</code> are recognized as <code>false</code>. For more complex matching you&#8217;ll have to write your own function.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\n<code>as_llong</code> and <code>as_ullong</code> are only available if your platform has reliable support for the <code>long long</code> type, including string conversions.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"code_traverse_base_data\" class=\"paragraph\">\n<p>This is an example of using these functions, along with node data retrieval ones (<a href=\"samples/traverse_base.cpp\" class=\"bare\">samples/traverse_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;: AllowRemote &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;AllowRemote&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_bool</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, Timeout &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Timeout&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_int</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, Description &#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Description&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.contents\"><a class=\"anchor\" href=\"#access.contents\"></a><a class=\"link\" href=\"#access.contents\">5.4. Contents-based traversal functions</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::child\"></a><a id=\"xml_node::attribute\"></a><a id=\"xml_node::next_sibling_name\"></a><a id=\"xml_node::previous_sibling_name\"></a>\nSince a lot of document traversal consists of finding the node/attribute with the correct name, there are special functions for that purpose:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::child</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::previous_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::previous_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>child</code> and <code>attribute</code> return the first child/attribute with the specified name; <code>next_sibling</code> and <code>previous_sibling</code> return the first sibling in the corresponding direction with the specified name. All string comparisons are case-sensitive. In case the node handle is null or there is no node/attribute with the specified name, null handle is returned.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>child</code> and <code>next_sibling</code> functions can be used together to loop through all child nodes with the desired name like this:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span></code></pre>\n</div>\n</div>\n<div id=\"xml_node::attribute_hinted\" class=\"paragraph\">\n<p><code>attribute</code> function needs to look for the target attribute by name. If a node has many attributes, finding each by name can be time consuming. If you have an idea of how attributes are ordered in the node, you can use a faster function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The extra <code>hint</code> argument is used to guess where the attribute might be, and is updated to the location of the next attribute so that if you search for multiple attributes in the right order, the performance is maximized. Note that <code>hint</code> has to be either null or has to belong to the node, otherwise the behavior is undefined.</p>\n</div>\n<div class=\"paragraph\">\n<p>You can use this function as follows:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">id</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;id&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">version</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This code is correct regardless of the order of the attributes, but it&#8217;s faster if <code>\"id\"</code>, <code>\"name\"</code> and <code>\"version\"</code> occur in that order.</p>\n</div>\n<div id=\"xml_node::find_child_by_attribute\" class=\"paragraph\">\n<p>Occasionally the needed node is specified not by the unique name but instead by the value of some attribute; for example, it is common to have node collections with each node having a unique id: <code>&lt;group&gt;&lt;item id=\"1\"/&gt; &lt;item id=\"2\"/&gt;&lt;/group&gt;</code>. There are two functions for finding child nodes based on the attribute values:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::find_child_by_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_value</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::find_child_by_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_value</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The three-argument function returns the first child node with the specified name which has an attribute with the specified name/value; the two-argument function skips the name test for the node, which can be useful for searching in heterogeneous collections. If the node handle is null or if no node is found, null handle is returned. All string comparisons are case-sensitive.</p>\n</div>\n<div class=\"paragraph\">\n<p>In all of the above functions, all arguments have to be valid strings; passing null pointers results in undefined behavior.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using these functions (<a href=\"samples/traverse_base.cpp\" class=\"bare\">samples/traverse_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool for *.dae generation: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">find_child_by_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;OutputFileMasks&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;*.dae&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.rangefor\"><a class=\"anchor\" href=\"#access.rangefor\"></a><a class=\"link\" href=\"#access.rangefor\">5.5. Range-based for-loop support</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::children\"></a><a id=\"xml_node::attributes\"></a>\nIf your C&#43;&#43; compiler supports range-based for-loop (this is a C&#43;&#43;11 feature, at the time of writing it&#8217;s supported by Microsoft Visual Studio 2012+, GCC 4.6+ and Clang 3.0+), you can use it to enumerate nodes/attributes. Additional helpers are provided to support this; note that they are also compatible with <a href=\"http://www.boost.org/libs/foreach/\">Boost Foreach</a>, and possibly other pre-C&#43;&#43;11 foreach facilities.</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\"><em>implementation</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>defined</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>type</em></span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">children</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\"><em>implementation</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>defined</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>type</em></span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">children</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\"><em>implementation</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>defined</em></span><span class=\"tok-o\">-</span><span class=\"tok-n\"><em>type</em></span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">attributes</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>children</code> function allows you to enumerate all child nodes; <code>children</code> function with <code>name</code> argument allows you to enumerate all child nodes with a specific name; <code>attributes</code> function allows you to enumerate all attributes of the node. Note that you can also use node object itself in a range-based for construct, which is equivalent to using <code>children()</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using these functions (<a href=\"samples/traverse_rangefor.cpp\" class=\"bare\">samples/traverse_rangefor.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">children</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool:&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attributes</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">children</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, child &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>While using <code>children()</code> makes the intent of the code clear, note that each node can be treated as a container of child nodes, since it provides <code>begin()</code>/<code>end()</code> member functions described in the next section. Because of this, you can iterate through node&#8217;s children simply by using the node itself:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-p\">...</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>When using C&#43;&#43;20, you can also use nodes as well as objects returned by <code>children()</code> and <code>attributes()</code> functions as ranges:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">auto</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tf</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">children</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">views</span><span class=\"tok-o\">::</span><span class=\"tok-n\">filter</span><span class=\"tok-p\">([](</span><span class=\"tok-k\">auto</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-p\">{</span><span class=\"tok-w\"> </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;AllowRemote&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_bool</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-p\">})</span>\n<span class=\"tok-w\">    </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">views</span><span class=\"tok-o\">::</span><span class=\"tok-n\">reverse</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tf</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-p\">...</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.iterators\"><a class=\"anchor\" href=\"#access.iterators\"></a><a class=\"link\" href=\"#access.iterators\">5.6. Traversing node/attribute lists via iterators</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node_iterator\"></a><a id=\"xml_attribute_iterator\"></a><a id=\"xml_node::begin\"></a><a id=\"xml_node::end\"></a><a id=\"xml_node::attributes_begin\"></a><a id=\"xml_node::attributes_end\"></a>\nChild node lists and attribute lists are simply double-linked lists; while you can use <code>previous_sibling</code>/<code>next_sibling</code> and other such functions for iteration, pugixml additionally provides node and attribute iterators, so that you can treat nodes as containers of other nodes or attributes:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">class</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_node_iterator</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">class</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_attribute_iterator</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">iterator</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::begin</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::end</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">attribute_iterator</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">attribute_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attributes_begin</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">attribute_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::attributes_end</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>begin</code> and <code>attributes_begin</code> return iterators that point to the first node/attribute, respectively; <code>end</code> and <code>attributes_end</code> return past-the-end iterator for node/attribute list, respectively - this iterator can&#8217;t be dereferenced, but decrementing it results in an iterator pointing to the last element in the list (except for empty lists, where decrementing past-the-end iterator results in undefined behavior). Past-the-end iterator is commonly used as a termination value for iteration loops (see sample below). If you want to get an iterator that points to an existing handle, you can construct the iterator with the handle as a single constructor argument, like so: <code>xml_node_iterator(node)</code>. For <code>xml_attribute_iterator</code>, you&#8217;ll have to provide both an attribute and its parent node.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>begin</code> and <code>end</code> return equal iterators if called on null node; such iterators can&#8217;t be dereferenced. <code>attributes_begin</code> and <code>attributes_end</code> behave the same way. For correct iterator usage this means that child node/attribute collections of null nodes appear to be empty.</p>\n</div>\n<div class=\"paragraph\">\n<p>Both types of iterators have bidirectional iterator semantics (i.e. they can be incremented and decremented, but efficient random access is not supported) and support all usual iterator operations - comparison, dereference, etc. The iterators are invalidated if the node/attribute objects they&#8217;re pointing to are removed from the tree; adding nodes/attributes does not invalidate any iterators.</p>\n</div>\n<div class=\"paragraph\">\n<p>Here is an example of using iterators for document traversal (<a href=\"samples/traverse_iter.cpp\" class=\"bare\">samples/traverse_iter.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">it</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool:&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">attributes_begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">attributes_end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">ait</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nNode and attribute iterators are somewhere in the middle between const and non-const iterators. While dereference operation yields a non-constant reference to the object, so that you can use it for tree modification operations, modifying this reference using assignment - i.e. passing iterators to a function like <code>std::sort</code> - will not give expected results, as assignment modifies local handle that&#8217;s stored in the iterator.\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.walker\"><a class=\"anchor\" href=\"#access.walker\"></a><a class=\"link\" href=\"#access.walker\">5.7. Recursive traversal with xml_tree_walker</a></h3>\n<div id=\"xml_tree_walker\" class=\"paragraph\">\n<p>The methods described above allow traversal of immediate children of some node; if you want to do a deep tree traversal, you&#8217;ll have to do it via a recursive function or some equivalent method. However, pugixml provides a helper for depth-first traversal of a subtree. In order to use it, you have to implement <code>xml_tree_walker</code> interface and to call <code>traverse</code> function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">class</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_tree_walker</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-k\">public</span><span class=\"tok-o\">:</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">begin</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">for_each</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">end</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">depth</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">};</span>\n\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::traverse</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_tree_walker</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">walker</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_tree_walker::begin\"></a><a id=\"xml_tree_walker::for_each\"></a><a id=\"xml_tree_walker::end\"></a><a id=\"xml_node::traverse\"></a>\nThe traversal is launched by calling <code>traverse</code> function on traversal root and proceeds as follows:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>First, <code>begin</code> function is called with traversal root as its argument.</p>\n</li>\n<li>\n<p>Then, <code>for_each</code> function is called for all nodes in the traversal subtree in depth first order, excluding the traversal root. Node is passed as an argument.</p>\n</li>\n<li>\n<p>Finally, <code>end</code> function is called with traversal root as its argument.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>If <code>begin</code>, <code>end</code> or any of the <code>for_each</code> calls return <code>false</code>, the traversal is terminated and <code>false</code> is returned as the traversal result; otherwise, the traversal results in <code>true</code>. Note that you don&#8217;t have to override <code>begin</code> or <code>end</code> functions; their default implementations return <code>true</code>.</p>\n</div>\n<div id=\"xml_tree_walker::depth\" class=\"paragraph\">\n<p>You can get the node&#8217;s depth relative to the traversal root at any point by calling <code>depth</code> function. It returns <code>-1</code> if called from <code>begin</code>/<code>end</code>, and returns 0-based depth if called from <code>for_each</code> - depth is 0 for all children of the traversal root, 1 for all grandchildren and so on.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of traversing tree hierarchy with xml_tree_walker (<a href=\"samples/traverse_walker.cpp\" class=\"bare\">samples/traverse_walker.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">simple_walker</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_tree_walker</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">for_each</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">i</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">i</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">i</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;  &quot;</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// indentation</span>\n\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_types</span><span class=\"tok-p\">[</span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">type</span><span class=\"tok-p\">()]</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;: name=&#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;, value=&#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">        </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// continue traversal</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">simple_walker</span><span class=\"tok-w\"> </span><span class=\"tok-n\">walker</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">traverse</span><span class=\"tok-p\">(</span><span class=\"tok-n\">walker</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.predicate\"><a class=\"anchor\" href=\"#access.predicate\"></a><a class=\"link\" href=\"#access.predicate\">5.8. Searching for nodes/attributes with predicates</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::find_attribute\"></a><a id=\"xml_node::find_child\"></a><a id=\"xml_node::find_node\"></a>\nWhile there are existing functions for getting a node/attribute with known contents, they are often not sufficient for simple queries. As an alternative for manual iteration through nodes/attributes until the needed one is found, you can make a predicate and call one of <code>find_</code> functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">find_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">find_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">find_node</span><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The predicate should be either a plain function or a function object which accepts one argument of type <code>xml_attribute</code> (for <code>find_attribute</code>) or <code>xml_node</code> (for <code>find_child</code> and <code>find_node</code>), and returns <code>bool</code>. The predicate is never called with null handle as an argument.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>find_attribute</code> function iterates through all attributes of the specified node, and returns the first attribute for which the predicate returned <code>true</code>. If the predicate returned <code>false</code> for all attributes or if there were no attributes (including the case where the node is null), null attribute is returned.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>find_child</code> function iterates through all child nodes of the specified node, and returns the first node for which the predicate returned <code>true</code>. If the predicate returned <code>false</code> for all nodes or if there were no child nodes (including the case where the node is null), null node is returned.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>find_node</code> function performs a depth-first traversal through the subtree of the specified node (excluding the node itself), and returns the first node for which the predicate returned <code>true</code>. If the predicate returned <code>false</code> for all nodes or if subtree was empty, null node is returned.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using predicate-based functions (<a href=\"samples/traverse_predicate.cpp\" class=\"bare\">samples/traverse_predicate.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">small_timeout</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Timeout&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_int</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">20</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">allow_remote_predicate</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">operator</span><span class=\"tok-p\">()(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-n\">strcmp</span><span class=\"tok-p\">(</span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">(),</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;AllowRemote&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">==</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">operator</span><span class=\"tok-p\">()(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;AllowRemote&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_bool</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// Find child via predicate (looks for direct children only)</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">find_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">allow_remote_predicate</span><span class=\"tok-p\">()).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Find node via predicate (looks for all descendants in depth-first order)</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">find_node</span><span class=\"tok-p\">(</span><span class=\"tok-n\">allow_remote_predicate</span><span class=\"tok-p\">()).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Find attribute via predicate</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">find_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">allow_remote_predicate</span><span class=\"tok-p\">()).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// We can use simple functions instead of function objects</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">find_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">small_timeout</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.text\"><a class=\"anchor\" href=\"#access.text\"></a><a class=\"link\" href=\"#access.text\">5.9. Working with text contents</a></h3>\n<div id=\"xml_text\" class=\"paragraph\">\n<p>It is common to store data as text contents of some node - i.e. <code>&lt;node&gt;&lt;description&gt;This is a node&lt;/description&gt;&lt;/node&gt;</code>. In this case, <code>&lt;description&gt;</code> node does not have a value, but instead has a child of type <a href=\"#node_pcdata\">node_pcdata</a> with value <code>\"This is a node\"</code>. pugixml provides a special class, <code>xml_text</code>, to work with such data. Working with text objects to modify data is described in <a href=\"#modify.text\">the documentation for modifying document data</a>; this section describes the access interface of <code>xml_text</code>.</p>\n</div>\n<div id=\"xml_node::text\" class=\"paragraph\">\n<p>You can get the text object from a node by using <code>text()</code> method:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_text</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::text</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If the node has a type <code>node_pcdata</code> or <code>node_cdata</code>, then the node itself is used to return data; otherwise, a first child node of type <code>node_pcdata</code> or <code>node_cdata</code> is used.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_text::empty\"></a><a id=\"xml_text::unspecified_bool_type\"></a>\nYou can check if the text object is bound to a valid PCDATA/CDATA node by using it as a boolean value, i.e. <code>if (text) { &#8230;&#8203; }</code> or <code>if (!text) { &#8230;&#8203; }</code>. Alternatively you can check it by using the <code>empty()</code> method:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::empty</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div id=\"xml_text::get\" class=\"paragraph\">\n<p>Given a text object, you can get the contents (i.e. the value of PCDATA/CDATA node) by using the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::get</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>In case text object is empty, the function returns an empty string - it never returns a null pointer.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_text::as_string\"></a><a id=\"xml_text::as_int\"></a><a id=\"xml_text::as_uint\"></a><a id=\"xml_text::as_double\"></a><a id=\"xml_text::as_float\"></a><a id=\"xml_text::as_bool\"></a><a id=\"xml_text::as_llong\"></a><a id=\"xml_text::as_ullong\"></a>\nIf you need a non-empty string if the text object is empty, or if the text contents is actually a number or a boolean that is stored as a string, you can use the following accessors:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-n\">as_string</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_int</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_uint</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_double</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_float</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_bool</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_llong</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::as_ullong</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>All of the above functions have the same semantics as similar <code>xml_attribute</code> members: they return the default argument if the text object is empty, they convert the text contents to a target type using the same rules and restrictions. You can <a href=\"#xml_attribute::as_int\">refer to documentation for the attribute functions</a> for details.</p>\n</div>\n<div id=\"xml_text::data\" class=\"paragraph\">\n<p><code>xml_text</code> is essentially a helper class that operates on <code>xml_node</code> values. It is bound to a node of type <a href=\"#node_pcdata\">node_pcdata</a> or <a href=\"#node_cdata\">node_cdata</a>. You can use the following function to retrieve this node:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::data</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Essentially, assuming <code>text</code> is an <code>xml_text</code> object, calling <code>text.get()</code> is equivalent to calling <code>text.data().value()</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using <code>xml_text</code> object (<a href=\"samples/text.cpp\" class=\"bare\">samples/text.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Project name: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">().</span><span class=\"tok-n\">get</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Project version: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">().</span><span class=\"tok-n\">as_double</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Project visibility: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;public&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">().</span><span class=\"tok-n\">as_bool</span><span class=\"tok-p\">(</span><span class=\"tok-cm\">/* def= */</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">?</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;public&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;private&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Project description: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">().</span><span class=\"tok-n\">get</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"access.misc\"><a class=\"anchor\" href=\"#access.misc\"></a><a class=\"link\" href=\"#access.misc\">5.10. Miscellaneous functions</a></h3>\n<div id=\"xml_node::root\" class=\"paragraph\">\n<p>If you need to get the document root of some node, you can use the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::root</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This function returns the node with type <a href=\"#node_document\">node_document</a>, which is the root node of the document the node belongs to (unless the node is null, in which case null node is returned).</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::path\"></a><a id=\"xml_node::first_element_by_path\"></a>\nWhile pugixml supports complex XPath expressions, sometimes a simple path handling facility is needed. There are two functions, for getting node path and for converting path to a node:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">string_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">path</span><span class=\"tok-p\">(</span><span class=\"tok-n\">char_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">delimiter</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-sc\">&#39;/&#39;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">first_element_by_path</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">delimiter</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-sc\">&#39;/&#39;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Node paths consist of node names, separated with a delimiter (which is <code>/</code> by default); also paths can contain self (<code>.</code>) and parent (<code>..</code>) pseudo-names, so that this is a valid path: <code>\"../../foo/./bar\"</code>. <code>path</code> returns the path to the node from the document root, <code>first_element_by_path</code> looks for a node represented by a given path; a path can be an absolute one (absolute paths start with the delimiter), in which case the rest of the path is treated as document root relative, and relative to the given node. For example, in the following document: <code>&lt;a&gt;&lt;b&gt;&lt;c/&gt;&lt;/b&gt;&lt;/a&gt;</code>, node <code>&lt;c/&gt;</code> has path <code>\"a/b/c\"</code>; calling <code>first_element_by_path</code> for document with path <code>\"a/b\"</code> results in node <code>&lt;b/&gt;</code>; calling <code>first_element_by_path</code> for node <code>&lt;a/&gt;</code> with path <code>\"../a/./b/../.\"</code> results in node <code>&lt;a/&gt;</code>; calling <code>first_element_by_path</code> with path <code>\"/a\"</code> results in node <code>&lt;a/&gt;</code> for any node.</p>\n</div>\n<div class=\"paragraph\">\n<p>In case path component is ambiguous (if there are two nodes with given name), the first one is selected; paths are not guaranteed to uniquely identify nodes in a document. If any component of a path is not found, the result of <code>first_element_by_path</code> is null node; also <code>first_element_by_path</code> returns null node for null nodes, in which case the path does not matter. <code>path</code> returns an empty string for null nodes.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\n<code>path</code> function returns the result as STL string, and thus is not available if <a href=\"#PUGIXML_NO_STL\">PUGIXML_NO_STL</a> is defined.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"xml_node::offset_debug\" class=\"paragraph\">\n<p>pugixml does not record row/column information for nodes upon parsing for efficiency reasons. However, if the node has not changed in a significant way since parsing (the name/value are not changed, and the node itself is the original one, i.e. it was not deleted from the tree and re-added later), it is possible to get the offset from the beginning of XML buffer:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::offset_debug</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If the offset is not available (this happens if the node is null, was not originally parsed from a stream, or has changed in a significant way), the function returns -1. Otherwise it returns the offset to node&#8217;s data from the beginning of XML buffer in <a href=\"#char_t\">pugi::char_t</a> units. For more information on parsing offsets, see <a href=\"#xml_parse_result::offset\">parsing error handling documentation</a>.</p>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"modify\"><a class=\"anchor\" href=\"#modify\"></a><a class=\"link\" href=\"#modify\">6. Modifying document data</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The document in pugixml is fully mutable: you can completely change the document structure and modify the data of nodes/attributes. This section provides documentation for the relevant functions. All functions take care of memory management and structural integrity themselves, so they always result in structurally valid tree - however, it is possible to create an invalid XML tree (for example, by adding two attributes with the same name or by setting attribute/node name to empty/invalid string). Tree modification is optimized for performance and for memory consumption, so if you have enough memory you can create documents from scratch with pugixml and later save them to file/stream instead of relying on error-prone manual text writing and without too much overhead.</p>\n</div>\n<div class=\"paragraph\">\n<p>All member functions that change node/attribute data or structure are non-constant and thus can not be called on constant handles. However, you can easily convert constant handle to non-constant one by simple assignment: <code>void foo(const pugi::xml_node&amp; n) { pugi::xml_node nc = n; }</code>, so const-correctness here mainly provides additional documentation.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.nodedata\"><a class=\"anchor\" href=\"#modify.nodedata\"></a><a class=\"link\" href=\"#modify.nodedata\">6.1. Setting node data</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::set_name\"></a><a id=\"xml_node::set_value\"></a>\nAs discussed before, nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. <a href=\"#node_document\">node_document</a> nodes do not have a name or value, <a href=\"#node_element\">node_element</a> and <a href=\"#node_declaration\">node_declaration</a> nodes always have a name but never have a value, <a href=\"#node_pcdata\">node_pcdata</a>, <a href=\"#node_cdata\">node_cdata</a>, <a href=\"#node_comment\">node_comment</a> and <a href=\"#node_doctype\">node_doctype</a> nodes never have a name but always have a value (it may be empty though), <a href=\"#node_pi\">node_pi</a> nodes always have a name and a value (again, value may be empty). In order to set node&#8217;s name or value, you can use the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">sz</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Both functions try to set the name/value to the specified string, and return the operation result. The operation fails if the node can not have name or value (for instance, when trying to call <code>set_name</code> on a <a href=\"#node_pcdata\">node_pcdata</a> node), if the node handle is null, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to these functions). The name/value content is not verified, so take care to use only valid XML names, or the document may become malformed.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of setting node name and value (<a href=\"samples/modify_base.cpp\" class=\"bare\">samples/modify_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// change node name</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;notnode&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new node name: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// change comment text</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;useless comment&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new comment text: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can&#39;t change value of the element or name of the comment</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;1&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;2&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.attrdata\"><a class=\"anchor\" href=\"#modify.attrdata\"></a><a class=\"link\" href=\"#modify.attrdata\">6.2. Setting attribute data</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_attribute::set_name\"></a><a id=\"xml_attribute::set_value\"></a>\nAll attributes have name and value, both of which are strings (value may be empty). You can set them with the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">sz</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_name</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Both functions try to set the name/value to the specified string, and return the operation result. The operation fails if the attribute handle is null, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to these functions). The name/value content is not verified, so take care to use only valid XML names, or the document may become malformed.</p>\n</div>\n<div class=\"paragraph\">\n<p>In addition to string functions, several functions are provided for handling attributes with numbers and booleans as values:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">precision</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">precision</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_attribute::set_value</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The above functions convert the argument to string and then call the base <code>set_value</code> function. Integers are converted to a decimal form, floating-point numbers are converted to either decimal or scientific form, depending on the number magnitude, boolean values are converted to either <code>\"true\"</code> or <code>\"false\"</code>.</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nNumber conversion functions depend on current C locale as set with <code>setlocale</code>, so may generate unexpected results if the locale is different from <code>\"C\"</code>.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\n<code>set_value</code> overloads with <code>long long</code> type are only available if your platform has reliable support for the type, including string conversions.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"xml_attribute::assign\" class=\"paragraph\">\n<p>For convenience, all <code>set_value</code> functions have the corresponding assignment operators:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These operators simply call the right <code>set_value</code> function and return the attribute they&#8217;re called on; the return value of <code>set_value</code> is ignored, so errors are ignored.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of setting attribute name and value (<a href=\"samples/modify_base.cpp\" class=\"bare\">samples/modify_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;id&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// change attribute name/value</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;key&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;345&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new attribute: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can use numbers or booleans</span>\n<span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-mf\">1.234</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;new attribute value: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can also use assignment operators for more concise code</span>\n<span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;final attribute value: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.add\"><a class=\"anchor\" href=\"#modify.add\"></a><a class=\"link\" href=\"#modify.add\">6.3. Adding nodes/attributes</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::prepend_attribute\"></a><a id=\"xml_node::append_attribute\"></a><a id=\"xml_node::insert_attribute_after\"></a><a id=\"xml_node::insert_attribute_before\"></a><a id=\"xml_node::prepend_child\"></a><a id=\"xml_node::append_child\"></a><a id=\"xml_node::insert_child_after\"></a><a id=\"xml_node::insert_child_before\"></a>\nNodes and attributes do not exist without a document tree, so you can&#8217;t create them without adding them to some document. A node or attribute can be created at the end of node/attribute list or before/after some other node:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_attribute_after</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_attribute_after</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_attribute_before</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_attribute_before</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_element</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_element</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_after</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_child</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_child</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_after</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_after</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>append_attribute</code> and <code>append_child</code> create a new node/attribute at the end of the corresponding list of the node the method is called on; <code>prepend_attribute</code> and <code>prepend_child</code> create a new node/attribute at the beginning of the list; <code>insert_attribute_after</code>, <code>insert_attribute_before</code>, <code>insert_child_after</code> and <code>insert_attribute_before</code> add the node/attribute before or after the specified node/attribute.</p>\n</div>\n<div class=\"paragraph\">\n<p>Attribute functions create an attribute with the specified name; you can specify the empty name and change the name later if you want to. Node functions with the <code>type</code> argument create the node with the specified type; since node type can&#8217;t be changed, you have to know the desired type beforehand. Also note that not all types can be added as children; see below for clarification. Node functions with the <code>name</code> argument create the element node (<a href=\"#node_element\">node_element</a>) with the specified name.</p>\n</div>\n<div class=\"paragraph\">\n<p>All functions return the handle to the created object on success, and null handle on failure. There are several reasons for failure:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Adding fails if the target node is null;</p>\n</li>\n<li>\n<p>Only <a href=\"#node_element\">node_element</a> nodes can contain attributes, so attribute adding fails if node is not an element;</p>\n</li>\n<li>\n<p>Only <a href=\"#node_document\">node_document</a> and <a href=\"#node_element\">node_element</a> nodes can contain children, so child node adding fails if the target node is not an element or a document;</p>\n</li>\n<li>\n<p><a href=\"#node_document\">node_document</a> and <a href=\"#node_null\">node_null</a> nodes can not be inserted as children, so passing <a href=\"#node_document\">node_document</a> or <a href=\"#node_null\">node_null</a> value as <code>type</code> results in operation failure;</p>\n</li>\n<li>\n<p><a href=\"#node_declaration\">node_declaration</a> nodes can only be added as children of the document node; attempt to insert declaration node as a child of an element node fails;</p>\n</li>\n<li>\n<p>Adding node/attribute results in memory allocation, which may fail;</p>\n</li>\n<li>\n<p>Insertion functions fail if the specified node or attribute is null or is not in the target node&#8217;s children/attribute list.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Even if the operation fails, the document remains in consistent state, but the requested node/attribute is not added.</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\n<code>attribute()</code> and <code>child()</code> functions do not add attributes or nodes to the tree, so code like <code>node.attribute(\"id\") = 123;</code> will not do anything if <code>node</code> does not have an attribute with name <code>\"id\"</code>. Make sure you&#8217;re operating with existing attributes/nodes by adding them if necessary.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of adding new attributes/nodes to the document (<a href=\"samples/modify_add.cpp\" class=\"bare\">samples/modify_add.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// add node with some name</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add description node with text child</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">descr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">descr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">node_pcdata</span><span class=\"tok-p\">).</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Simple node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add param node before the description</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;param&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">descr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add attributes to param node</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;value&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mf\">1.1</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_attribute_after</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;type&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;float&quot;</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.remove\"><a class=\"anchor\" href=\"#modify.remove\"></a><a class=\"link\" href=\"#modify.remove\">6.4. Removing nodes/attributes</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::remove_attribute\"></a><a id=\"xml_node::remove_attributes\"></a><a id=\"xml_node::remove_child\"></a><a id=\"xml_node::remove_children\"></a>\nIf you do not want your document to contain some node or attribute, you can remove it with one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">a</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_attributes</span><span class=\"tok-p\">();</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_children</span><span class=\"tok-p\">();</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>remove_attribute</code> removes the attribute from the attribute list of the node, and returns the operation result. <code>remove_child</code> removes the child node with the entire subtree (including all descendant nodes and attributes) from the document, and returns the operation result. <code>remove_attributes</code> removes all the attributes of the node, and returns the operation result. <code>remove_children</code> removes all the child nodes of the node, and returns the operation result. Removing fails if one of the following is true:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>The node the function is called on is null;</p>\n</li>\n<li>\n<p>The attribute/node to be removed is null;</p>\n</li>\n<li>\n<p>The attribute/node to be removed is not in the node&#8217;s attribute/child list.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Removing the attribute or node invalidates all handles to the same underlying object, and also invalidates all iterators pointing to the same object. Removing node also invalidates all past-the-end iterators to its attribute or child node list. Be careful to ensure that all such handles and iterators either do not exist or are not used after the attribute/node is removed.</p>\n</div>\n<div class=\"paragraph\">\n<p>If you want to remove the attribute or child node by its name, two additional helper functions are available:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions look for the first attribute or child with the specified name, and then remove it, returning the result. If there is no attribute or child with such name, the function returns <code>false</code>; if there are two nodes with the given name, only the first node is deleted. If you want to delete all nodes with the specified name, you can use code like this: <code>while (node.remove_child(\"tool\")) ;</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of removing attributes/nodes from the document (<a href=\"samples/modify_remove.cpp\" class=\"bare\">samples/modify_remove.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// remove description node with the whole subtree</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// remove id attribute</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;param&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;value&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// we can also remove nodes/attributes by handles</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">id</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">id</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.text\"><a class=\"anchor\" href=\"#modify.text\"></a><a class=\"link\" href=\"#modify.text\">6.5. Working with text contents</a></h3>\n<div class=\"paragraph\">\n<p>pugixml provides a special class, <code>xml_text</code>, to work with text contents stored as a value of some node, i.e. <code>&lt;node&gt;&lt;description&gt;This is a node&lt;/description&gt;&lt;/node&gt;</code>. Working with text objects to retrieve data is described in <a href=\"#access.text\">the documentation for accessing document data</a>; this section describes the modification interface of <code>xml_text</code>.</p>\n</div>\n<div id=\"xml_text::set\" class=\"paragraph\">\n<p>Once you have an <code>xml_text</code> object, you can set the text contents using the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This function tries to set the contents to the specified string, and returns the operation result. The operation fails if the text object was retrieved from a node that can not have a value and is not an element node (i.e. it is a <a href=\"#node_declaration\">node_declaration</a> node), if the text object is empty, or if there is insufficient memory to handle the request. The provided string is copied into document managed memory and can be destroyed after the function returns (for example, you can safely pass stack-allocated buffers to this function). Note that if the text object was retrieved from an element node, this function creates the PCDATA child node if necessary (i.e. if the element node does not have a PCDATA/CDATA child already).</p>\n</div>\n<div id=\"xml_text::set_value\" class=\"paragraph\">\n<p>In addition to a string function, several functions are provided for handling text with numbers and booleans as contents:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">precision</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">precision</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_text::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The above functions convert the argument to string and then call the base <code>set</code> function. These functions have the same semantics as similar <code>xml_attribute</code> functions. You can <a href=\"#xml_attribute::set_value\">refer to documentation for the attribute functions</a> for details.</p>\n</div>\n<div id=\"xml_text::assign\" class=\"paragraph\">\n<p>For convenience, all <code>set</code> functions have the corresponding assignment operators:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-o\">=</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These operators simply call the right <code>set</code> function and return the attribute they&#8217;re called on; the return value of <code>set</code> is ignored, so errors are ignored.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using <code>xml_text</code> object to modify text contents (<a href=\"samples/text.cpp\" class=\"bare\">samples/text.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// change project version</span>\n<span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mf\">1.2</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// add description element and set the contents</span>\n<span class=\"tok-c1\">// note that we do not have to explicitly add the node_pcdata child</span>\n<span class=\"tok-n\">project</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">text</span><span class=\"tok-p\">().</span><span class=\"tok-n\">set</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;a test project&quot;</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.clone\"><a class=\"anchor\" href=\"#modify.clone\"></a><a class=\"link\" href=\"#modify.clone\">6.6. Cloning nodes/attributes</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::prepend_copy\"></a><a id=\"xml_node::append_copy\"></a><a id=\"xml_node::insert_copy_after\"></a><a id=\"xml_node::insert_copy_before\"></a>\nWith the help of previously described functions, it is possible to create trees with any contents and structure, including cloning the existing data. However since this is an often needed operation, pugixml provides built-in node/attribute cloning facilities. Since nodes and attributes do not exist without a document tree, you can&#8217;t create a standalone copy - you have to immediately insert it somewhere in the tree. For this, you can use one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_copy</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_copy</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_copy_after</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_copy_before</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_copy</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_copy</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_copy_after</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_copy_before</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions mirror the structure of <code>append_child</code>, <code>prepend_child</code>, <code>insert_child_before</code> and related functions - they take the handle to the prototype object, which is to be cloned, insert a new attribute/node at the appropriate place, and then copy the attribute data or the whole node subtree to the new object. The functions return the handle to the resulting duplicate object, or null handle on failure.</p>\n</div>\n<div class=\"paragraph\">\n<p>The attribute is copied along with the name and value; the node is copied along with its type, name and value; additionally attribute list and all children are recursively cloned, resulting in the deep subtree clone. The prototype object can be a part of the same document, or a part of any other document.</p>\n</div>\n<div class=\"paragraph\">\n<p>The failure conditions resemble those of <code>append_child</code>, <code>insert_child_before</code> and related functions, <a href=\"#xml_node::append_child\">consult their documentation for more information</a>. There are additional caveats specific to cloning functions:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Cloning null handles results in operation failure;</p>\n</li>\n<li>\n<p>Node cloning starts with insertion of the node of the same type as that of the prototype; for this reason, cloning functions can not be directly used to clone entire documents, since <a href=\"#node_document\">node_document</a> is not a valid insertion type. The example below provides a workaround.</p>\n</li>\n<li>\n<p>It is possible to copy a subtree as a child of some node inside this subtree, i.e. <code>node.append_copy(node.parent().parent());</code>. This is a valid operation, and it results in a clone of the subtree in the state before cloning started, i.e. no infinite recursion takes place.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>This is an example with one possible implementation of include tags in XML (<a href=\"samples/include.cpp\" class=\"bare\">samples/include.cpp</a>). It illustrates node cloning and usage of other document modification functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">load_preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">type</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">==</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">node_pi</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&amp;&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">strcmp</span><span class=\"tok-p\">(</span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">(),</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;include&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">==</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">        </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">            </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">include</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-c1\">// load new preprocessed document (note: ideally this should handle relative paths)</span>\n<span class=\"tok-w\">            </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">include</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">            </span><span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">!</span><span class=\"tok-n\">load_preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-c1\">// insert the comment marker above include directive</span>\n<span class=\"tok-w\">            </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">node_comment</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">include</span><span class=\"tok-p\">).</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-n\">path</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-c1\">// copy the document above the include directive (this retains the original order!)</span>\n<span class=\"tok-w\">            </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ic</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ic</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ic</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ic</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">            </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">                </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_copy_before</span><span class=\"tok-p\">(</span><span class=\"tok-n\">ic</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">include</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">            </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-c1\">// remove the include node and move to the next child</span>\n<span class=\"tok-w\">            </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">include</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">        </span><span class=\"tok-p\">}</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">else</span>\n<span class=\"tok-w\">        </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">            </span><span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">!</span><span class=\"tok-n\">preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">child</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">            </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">        </span><span class=\"tok-p\">}</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">load_preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_file</span><span class=\"tok-p\">(</span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_default</span><span class=\"tok-w\"> </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">parse_pi</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// for &lt;?include?&gt;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">?</span><span class=\"tok-w\"> </span><span class=\"tok-n\">preprocess</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.move\"><a class=\"anchor\" href=\"#modify.move\"></a><a class=\"link\" href=\"#modify.move\">6.7. Moving nodes</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::prepend_move\"></a><a id=\"xml_node::append_move\"></a><a id=\"xml_node::insert_move_after\"></a><a id=\"xml_node::insert_move_before\"></a>\nSometimes instead of cloning a node you need to move an existing node to a different position in a tree. This can be accomplished by copying the node and removing the original; however, this is expensive since it results in a lot of extra operations. For moving nodes within the same document tree, you can use of the following functions instead:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_move</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::prepend_move</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_move_after</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::insert_move_before</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions mirror the structure of <code>append_copy</code>, <code>prepend_copy</code>, <code>insert_copy_before</code> and <code>insert_copy_after</code> - they take the handle to the moved object and move it to the appropriate place with all attributes and/or child nodes. The functions return the handle to the resulting object (which is the same as the moved object), or null handle on failure.</p>\n</div>\n<div class=\"paragraph\">\n<p>The failure conditions resemble those of <code>append_child</code>, <code>insert_child_before</code> and related functions, <a href=\"#xml_node::append_child\">consult their documentation for more information</a>. There are additional caveats specific to moving functions:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Moving null handles results in operation failure;</p>\n</li>\n<li>\n<p>Moving is only possible for nodes that belong to the same document; attempting to move nodes between documents will fail.</p>\n</li>\n<li>\n<p><code>insert_move_after</code> and <code>insert_move_before</code> functions fail if the moved node is the same as the <code>node</code> argument (this operation would be a no-op otherwise).</p>\n</li>\n<li>\n<p>It is impossible to move a subtree to a child of some node inside this subtree, i.e. <code>node.append_move(node.parent().parent());</code> will fail.</p>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"modify.fragments\"><a class=\"anchor\" href=\"#modify.fragments\"></a><a class=\"link\" href=\"#modify.fragments\">6.8. Assembling document from fragments</a></h3>\n<div id=\"xml_node::append_buffer\" class=\"paragraph\">\n<p>pugixml provides several ways to assemble an XML document from other XML documents. Assuming there is a set of document fragments, represented as in-memory buffers, the implementation choices are as follows:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Use a temporary document to parse the data from a string, then clone the nodes to a destination node. For example:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">append_fragment</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">target</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">!</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_buffer</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">target</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_copy</span><span class=\"tok-p\">(</span><span class=\"tok-n\">child</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</li>\n<li>\n<p>Cache the parsing step - instead of keeping in-memory buffers, keep document objects that already contain the parsed fragment:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">append_fragment</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">target</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">cached_fragment</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">cached_fragment</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_child</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">target</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_copy</span><span class=\"tok-p\">(</span><span class=\"tok-n\">child</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</li>\n<li>\n<p>Use <code>xml_node::append_buffer</code> directly:</p>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::append_buffer</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>The first method is more convenient, but slower than the other two. The relative performance of <code>append_copy</code> and <code>append_buffer</code> depends on the buffer format - usually <code>append_buffer</code> is faster if the buffer is in native encoding (UTF-8 or wchar_t, depending on <code>PUGIXML_WCHAR_MODE</code>). At the same time it might be less efficient in terms of memory usage - the implementation makes a copy of the provided buffer, and the copy has the same lifetime as the document - the memory used by that copy will be reclaimed after the document is destroyed, but no sooner. Even deleting all nodes in the document, including the appended ones, won&#8217;t reclaim the memory.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>append_buffer</code> behaves in the same way as <a href=\"#xml_document::load_buffer\">xml_document::load_buffer</a> - the input buffer is a byte buffer, with size in bytes; the buffer is not modified and can be freed after the function returns.</p>\n</div>\n<div id=\"status_append_invalid_root\" class=\"paragraph\">\n<p>Since <code>append_buffer</code> needs to append child nodes to the current node, it only works if the current node is either document or element node. Calling <code>append_buffer</code> on a node with any other type results in an error with <code>status_append_invalid_root</code> status.</p>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"saving\"><a class=\"anchor\" href=\"#saving\"></a><a class=\"link\" href=\"#saving\">7. Saving document</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Often after creating a new document or loading the existing one and processing it, it is necessary to save the result back to file. Also it is occasionally useful to output the whole document or a subtree to some stream; use cases include debug printing, serialization via network or other text-oriented medium, etc. pugixml provides several functions to output any subtree of the document to a file, stream or another generic transport interface; these functions allow to customize the output format (see <a href=\"#saving.options\">Output options</a>), and also perform necessary encoding conversions (see <a href=\"#saving.encoding\">Encodings</a>). This section documents the relevant functionality.</p>\n</div>\n<div class=\"paragraph\">\n<p>Before writing to the destination the node/attribute data is properly formatted according to the node type; all special XML symbols, such as <code>&lt;</code> and <code>&amp;</code>, are properly escaped (unless <a href=\"#format_no_escapes\">format_no_escapes</a> flag is set). In order to guard against forgotten node/attribute names, empty node/attribute names are printed as <code>\":anonymous\"</code>. For well-formed output, make sure all node and attribute names are set to meaningful values.</p>\n</div>\n<div class=\"paragraph\">\n<p>CDATA sections with values that contain <code>\"]]&gt;\"</code> are split into several sections as follows: section with value <code>\"pre]]&gt;post\"</code> is written as <code>&lt;![CDATA[pre]]]]&gt;&lt;![CDATA[&gt;post]]&gt;</code>. While this alters the structure of the document (if you load the document after saving it, there will be two CDATA sections instead of one), this is the only way to escape CDATA contents.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.file\"><a class=\"anchor\" href=\"#saving.file\"></a><a class=\"link\" href=\"#saving.file\">7.1. Saving document to a file</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_document::save_file\"></a><a id=\"xml_document::save_file_wide\"></a>\nIf you want to save the whole document to a file, you can use one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">::</span><span class=\"tok-n\">save_file</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">::</span><span class=\"tok-n\">save_file</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions accept file path as its first argument, and also three optional arguments, which specify indentation and other output options (see <a href=\"#saving.options\">Output options</a>) and output data encoding (see <a href=\"#saving.encoding\">Encodings</a>). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc. The functions return <code>true</code> on success and <code>false</code> if the file could not be opened or written to.</p>\n</div>\n<div class=\"paragraph\">\n<p>File path is passed to the system file opening function as is in case of the first function (which accepts <code>const char* path</code>); the second function either uses a special file opening function if it is provided by the runtime library or converts the path to UTF-8 and uses the system file opening function.</p>\n</div>\n<div id=\"xml_writer_file\" class=\"paragraph\">\n<p><code>save_file</code> opens the target file for writing, outputs the requested header (by default a document declaration is output, unless the document already has one), and then saves the document contents. Calling <code>save_file</code> is equivalent to creating an <code>xml_writer_file</code> object with <code>FILE*</code> handle as the only constructor argument and then calling <code>save</code>; see <a href=\"#saving.writer\">Saving document via writer interface</a> for writer interface details.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of saving XML document to file (<a href=\"samples/save_file.cpp\" class=\"bare\">samples/save_file.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// save document to file</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Saving result: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save_file</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;save_file_output.xml&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.stream\"><a class=\"anchor\" href=\"#saving.stream\"></a><a class=\"link\" href=\"#saving.stream\">7.2. Saving document to C&#43;&#43; IOstreams</a></h3>\n<div id=\"xml_document::save_stream\" class=\"paragraph\">\n<p>To enhance interoperability pugixml provides functions for saving document to any object which implements C&#43;&#43; <code>std::ostream</code> interface. This allows you to save documents to any standard C&#43;&#43; stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). Most notably, this allows for easy debug output, since you can use <code>std::cout</code> stream as saving target. There are two functions, one works with narrow character streams, another handles wide character ones:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">::</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">::</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>save</code> with <code>std::ostream</code> argument saves the document to the stream in the same way as <code>save_file</code> (i.e. with requested header and with encoding conversions). On the other hand, <code>save</code> with <code>std::wstream</code> argument saves the document to the wide stream with <a href=\"#encoding_wchar\">encoding_wchar</a> encoding.  Because of this, using <code>save</code> with wide character streams requires careful (usually platform-specific) stream setup (i.e. using the <code>imbue</code> function). Generally use of wide streams is discouraged, however it provides you with the ability to save documents to non-Unicode encodings, i.e. you can save Shift-JIS encoded data if you set the correct locale.</p>\n</div>\n<div id=\"xml_writer_stream\" class=\"paragraph\">\n<p>Calling <code>save</code> with stream target is equivalent to creating an <code>xml_writer_stream</code> object with stream as the only constructor argument and then calling <code>save</code>; see <a href=\"#saving.writer\">Saving document via writer interface</a> for writer interface details.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of saving XML document to standard output (<a href=\"samples/save_stream.cpp\" class=\"bare\">samples/save_stream.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// save document to standard output</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Document:</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.writer\"><a class=\"anchor\" href=\"#saving.writer\"></a><a class=\"link\" href=\"#saving.writer\">7.3. Saving document via writer interface</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_document::save\"></a><a id=\"xml_writer\"></a><a id=\"xml_writer::write\"></a>\nAll of the above saving functions are implemented in terms of writer interface. This is a simple interface with a single function, which is called several times during output process with chunks of document data as input:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">class</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_writer</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-k\">public</span><span class=\"tok-o\">:</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">write</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">data</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">};</span>\n\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">::</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_writer</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">writer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>In order to output the document via some custom transport, for example sockets, you should create an object which implements <code>xml_writer</code> interface and pass it to <code>save</code> function. <code>xml_writer::write</code> function is called with a buffer as an input, where <code>data</code> points to buffer start, and <code>size</code> is equal to the buffer size in bytes. <code>write</code> implementation must write the buffer to the transport; it can not save the passed buffer pointer, as the buffer contents will change after <code>write</code> returns. The buffer contains the chunk of document data in the desired encoding.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>write</code> function is called with relatively large blocks (size is usually several kilobytes, except for the last block that may be small), so there is often no need for additional buffering in the implementation.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of custom writer for saving document data to STL string (<a href=\"samples/save_custom_writer.cpp\" class=\"bare\">samples/save_custom_writer.cpp</a>); read the sample code for more complex examples:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_string_writer</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_writer</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">write</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">data</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append</span><span class=\"tok-p\">(</span><span class=\"tok-k\">static_cast</span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*&gt;</span><span class=\"tok-p\">(</span><span class=\"tok-n\">data</span><span class=\"tok-p\">),</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.subtree\"><a class=\"anchor\" href=\"#saving.subtree\"></a><a class=\"link\" href=\"#saving.subtree\">7.4. Saving a single subtree</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::print\"></a><a id=\"xml_node::print_stream\"></a>\nWhile the previously described functions save the whole document to the destination, it is easy to save a single subtree. The following functions are provided:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">os</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">os</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">::</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_writer</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">writer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions have the same arguments with the same meaning as the corresponding <code>xml_document::save</code> functions, and allow you to save the subtree to either a C&#43;&#43; IOstream or to any object that implements <code>xml_writer</code> interface.</p>\n</div>\n<div class=\"paragraph\">\n<p>Saving a subtree differs from saving the whole document: the process behaves as if <a href=\"#format_write_bom\">format_write_bom</a> is off, and <a href=\"#format_no_declaration\">format_no_declaration</a> is on, even if actual values of the flags are different. This means that BOM is not written to the destination, and document declaration is only written if it is the node itself or is one of node&#8217;s children. Note that this also holds if you&#8217;re saving a document; this example (<a href=\"samples/save_subtree.cpp\" class=\"bare\">samples/save_subtree.cpp</a>) illustrates the difference:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// get a test document</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;&lt;foo bar=&#39;baz&#39;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// print document to standard output (prints &lt;?xml version=&quot;1.0&quot;?&gt;&lt;foo bar=&quot;baz&quot;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;)</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_raw</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// print document to standard output as a regular node (prints &lt;foo bar=&quot;baz&quot;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;)</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_raw</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// print a subtree to standard output (prints &lt;call&gt;hey&lt;/call&gt;)</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;foo&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;call&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_raw</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.options\"><a class=\"anchor\" href=\"#saving.options\"></a><a class=\"link\" href=\"#saving.options\">7.5. Output options</a></h3>\n<div class=\"paragraph\">\n<p>All saving functions accept the optional parameter <code>flags</code>. This is a bitmask that customizes the output format; you can select the way the document nodes are printed and select the needed additional information that is output before the document contents.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nYou should use the usual bitwise arithmetics to manipulate the bitmask: to enable a flag, use <code>mask | flag</code>; to disable a flag, use <code>mask &amp; ~flag</code>.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>These flags control the resulting tree contents:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"format_indent\"></a><code>format_indent</code> determines if all nodes should be indented with the indentation string (this is an additional parameter for all saving functions, and is <code>\"\\t\"</code> by default). If this flag is on, the indentation string is printed several times before every node, where the amount of indentation depends on the node&#8217;s depth relative to the output subtree. This flag has no effect if <a href=\"#format_raw\">format_raw</a> is enabled. This flag is <strong>on</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_indent_attributes\"></a><code>format_indent_attributes</code> determines if all attributes should be printed on a new line, indented with the indentation string according to the attribute&#8217;s depth. This flag implies <a href=\"#format_indent\">format_indent</a>. This flag has no effect if <a href=\"#format_raw\">format_raw</a> is enabled. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_raw\"></a><code>format_raw</code> switches between formatted and raw output. If this flag is on, the nodes are not indented in any way, and also no newlines that are not part of document text are printed. Raw mode can be used for serialization where the result is not intended to be read by humans; also it can be useful if the document was parsed with <a href=\"#parse_ws_pcdata\">parse_ws_pcdata</a> flag, to preserve the original document formatting as much as possible. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_no_escapes\"></a><code>format_no_escapes</code> disables output escaping for attribute values and PCDATA contents. If this flag is off, special symbols (<code>\"</code>, <code>&amp;</code>, <code>&lt;</code>, <code>&gt;</code>) and all non-printable characters (those with codepoint values less than 32) are converted to XML escape sequences (i.e. <code>&amp;amp;</code>) during output. If this flag is on, no text processing is performed; therefore, output XML can be malformed if output contents contains invalid symbols (i.e. having a stray <code>&lt;</code> in the PCDATA will make the output malformed). This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_no_empty_element_tags\"></a><code>format_no_empty_element_tags</code> determines if start/end tags should be output instead of empty element tags for empty elements (that is, elements with no children). This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_skip_control_chars\"></a><code>format_skip_control_chars</code> enables skipping characters belonging to range [0; 32) instead of \"&amp;#xNN;\" encoding. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_attribute_single_quote\"></a><code>format_attribute_single_quote</code> enables using single quotes <code>'</code> instead of double quotes <code>\"</code> for enclosing attribute values. This flag is <strong>off</strong> by default.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>These flags control the additional output information:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"format_no_declaration\"></a><code>format_no_declaration</code> disables default node declaration output. By default, if the document is saved via <code>save</code> or <code>save_file</code> function, and it does not have any document declaration, a default declaration is output before the document contents. Enabling this flag disables this declaration. This flag has no effect in <code>xml_node::print</code> functions: they never output the default declaration. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_write_bom\"></a><code>format_write_bom</code> enables Byte Order Mark (BOM) output. By default, no BOM is output, so in case of non UTF-8 encodings the resulting document&#8217;s encoding may not be recognized by some parsers and text editors, if they do not implement sophisticated encoding detection. Enabling this flag adds an encoding-specific BOM to the output. This flag has no effect in <code>xml_node::print</code> functions: they never output the BOM. This flag is <strong>off</strong> by default.</p>\n</li>\n<li>\n<p><a id=\"format_save_file_text\"></a><code>format_save_file_text</code> changes the file mode when using <code>save_file</code> function. By default, file is opened in binary mode, which means that the output file will\ncontain platform-independent newline <code>\\n</code> (ASCII 10). If this flag is on, file is opened in text mode, which on some systems changes the newline format (i.e. on Windows you can use this flag to output XML documents with <code>\\r\\n</code> (ASCII 13 10) newlines. This flag is <strong>off</strong> by default.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Additionally, there is one predefined option mask:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a id=\"format_default\"></a><code>format_default</code> is the default set of flags, i.e. it has all options set to their default values. It sets formatted output with indentation, without BOM and with default node declaration, if necessary.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>This is an example that shows the outputs of different output options (<a href=\"samples/save_options.cpp\" class=\"bare\">samples/save_options.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// get a test document</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;&lt;foo bar=&#39;baz&#39;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// default options; prints</span>\n<span class=\"tok-c1\">// &lt;?xml version=&quot;1.0&quot;?&gt;</span>\n<span class=\"tok-c1\">// &lt;foo bar=&quot;baz&quot;&gt;</span>\n<span class=\"tok-c1\">//         &lt;call&gt;hey&lt;/call&gt;</span>\n<span class=\"tok-c1\">// &lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// default options with custom indentation string; prints</span>\n<span class=\"tok-c1\">// &lt;?xml version=&quot;1.0&quot;?&gt;</span>\n<span class=\"tok-c1\">// &lt;foo bar=&quot;baz&quot;&gt;</span>\n<span class=\"tok-c1\">// --&lt;call&gt;hey&lt;/call&gt;</span>\n<span class=\"tok-c1\">// &lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;--&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// default options without indentation; prints</span>\n<span class=\"tok-c1\">// &lt;?xml version=&quot;1.0&quot;?&gt;</span>\n<span class=\"tok-c1\">// &lt;foo bar=&quot;baz&quot;&gt;</span>\n<span class=\"tok-c1\">// &lt;call&gt;hey&lt;/call&gt;</span>\n<span class=\"tok-c1\">// &lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_default</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">~</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_indent</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// can also pass &quot;&quot; instead of indentation string for the same effect</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// raw output; prints</span>\n<span class=\"tok-c1\">// &lt;?xml version=&quot;1.0&quot;?&gt;&lt;foo bar=&quot;baz&quot;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_raw</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// raw output without declaration; prints</span>\n<span class=\"tok-c1\">// &lt;foo bar=&quot;baz&quot;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_raw</span><span class=\"tok-w\"> </span><span class=\"tok-o\">|</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">format_no_declaration</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.encoding\"><a class=\"anchor\" href=\"#saving.encoding\"></a><a class=\"link\" href=\"#saving.encoding\">7.6. Encodings</a></h3>\n<div class=\"paragraph\">\n<p>pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it&#8217;s a strict subset of UTF-16) and handles all encoding conversions during output. The output encoding is set via the <code>encoding</code> parameter of saving functions, which is of type <code>xml_encoding</code>. The possible values for the encoding are documented in <a href=\"#loading.encoding\">Encodings</a>; the only flag that has a different meaning is <code>encoding_auto</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>While all other flags set the exact encoding, <code>encoding_auto</code> is meant for automatic encoding detection. The automatic detection does not make sense for output encoding, since there is usually nothing to infer the actual encoding from, so here <code>encoding_auto</code> means UTF-8 encoding, which is the most popular encoding for XML data storage. This is also the default value of output encoding; specify another value if you do not want UTF-8 encoded output.</p>\n</div>\n<div class=\"paragraph\">\n<p>Also note that wide stream saving functions do not have <code>encoding</code> argument and always assume <a href=\"#encoding_wchar\">encoding_wchar</a> encoding.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nThe current behavior for Unicode conversion is to skip all invalid UTF sequences during conversion. This behavior should not be relied upon; if your node/attribute names do not contain any valid UTF sequences, they may be output as if they are empty, which will result in malformed XML document.\n</td>\n</tr>\n</table>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"saving.declaration\"><a class=\"anchor\" href=\"#saving.declaration\"></a><a class=\"link\" href=\"#saving.declaration\">7.7. Customizing document declaration</a></h3>\n<div class=\"paragraph\">\n<p>When you are saving the document using <code>xml_document::save()</code> or <code>xml_document::save_file()</code>, a default XML document declaration is output, if <code>format_no_declaration</code> is not specified and if the document does not have a declaration node. However, the default declaration is not customizable. If you want to customize the declaration output, you need to create the declaration node yourself.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nBy default the declaration node is not added to the document during parsing. If you just need to preserve the original declaration node, you have to add the flag <a href=\"#parse_declaration\">parse_declaration</a> to the parsing flags; the resulting document will contain the original declaration node, which will be output during saving.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>Declaration node is a node with type <a href=\"#node_declaration\">node_declaration</a>; it behaves like an element node in that it has attributes with values (but it does not have child nodes). Therefore setting custom version, encoding or standalone declaration involves adding attributes and setting attribute values.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example that shows how to create a custom declaration node (<a href=\"samples/save_declaration.cpp\" class=\"bare\">samples/save_declaration.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// get a test document</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;&lt;foo bar=&#39;baz&#39;&gt;&lt;call&gt;hey&lt;/call&gt;&lt;/foo&gt;&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add a custom declaration node</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">decl</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">prepend_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">node_declaration</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">decl</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;1.0&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">decl</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;encoding&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;UTF-8&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">decl</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;standalone&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;no&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;</span>\n<span class=\"tok-c1\">// &lt;foo bar=&quot;baz&quot;&gt;</span>\n<span class=\"tok-c1\">//         &lt;call&gt;hey&lt;/call&gt;</span>\n<span class=\"tok-c1\">// &lt;/foo&gt;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"xpath\"><a class=\"anchor\" href=\"#xpath\"></a><a class=\"link\" href=\"#xpath\">8. XPath</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If the task at hand is to select a subset of document nodes that match some criteria, it is possible to code a function using the existing traversal functionality for any practical criteria. However, often either a data-driven approach is desirable, in case the criteria are not predefined and come from a file, or it is inconvenient to use traversal interfaces and a higher-level DSL is required. There is a standard language for XML processing, XPath, that can be useful for these cases. pugixml implements an almost complete subset of XPath 1.0. Because of differences in document object model and some performance implications, there are minor violations of the official specifications, which can be found in <a href=\"#xpath.w3c\">Conformance to W3C specification</a>. The rest of this section describes the interface for XPath functionality. Please note that if you wish to learn to use XPath language, you have to look for other tutorials or manuals; for example, you can read <a href=\"https://www.w3schools.com/xml/xpath_intro.asp\">W3Schools XPath tutorial</a> or <a href=\"https://www.w3.org/TR/xpath-10/\">the XPath 1.0 specification</a>.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.types\"><a class=\"anchor\" href=\"#xpath.types\"></a><a class=\"link\" href=\"#xpath.types\">8.1. XPath types</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xpath_value_type\"></a><a id=\"xpath_type_number\"></a><a id=\"xpath_type_string\"></a><a id=\"xpath_type_boolean\"></a><a id=\"xpath_type_node_set\"></a><a id=\"xpath_type_none\"></a>\nEach XPath expression can have one of the following types: boolean, number, string or node set. Boolean type corresponds to <code>bool</code> type, number type corresponds to <code>double</code> type, string type corresponds to either <code>std::string</code> or <code>std::wstring</code>, depending on whether <a href=\"#dom.unicode\">wide character interface is enabled</a>, and node set corresponds to <a href=\"#xpath_node_set\">xpath_node_set</a> type. There is an enumeration, <code>xpath_value_type</code>, which can take the values <code>xpath_type_boolean</code>, <code>xpath_type_number</code>, <code>xpath_type_string</code> or <code>xpath_type_node_set</code>, accordingly.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_node\"></a><a id=\"xpath_node::node\"></a><a id=\"xpath_node::attribute\"></a><a id=\"xpath_node::parent\"></a>\nBecause an XPath node can be either a node or an attribute, there is a special type, <code>xpath_node</code>, which is a discriminated union of these types. A value of this type contains two node handles, one of <code>xml_node</code> type, and another one of <code>xml_attribute</code> type; at most one of them can be non-null. The accessors to get these handles are available:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node::node</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node::attribute</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>XPath nodes can be null, in which case both accessors return null handles.</p>\n</div>\n<div class=\"paragraph\">\n<p>Note that as per XPath specification, each XPath node has a parent, which can be retrieved via this function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node::parent</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>parent</code> function returns the node&#8217;s parent if the XPath node corresponds to <code>xml_node</code> handle (equivalent to <code>node().parent()</code>), or the node to which the attribute belongs to, if the XPath node corresponds to <code>xml_attribute</code> handle. For null nodes, <code>parent</code> returns null handle.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_node::unspecified_bool_type\"></a><a id=\"xpath_node::comparison\"></a>\nLike node and attribute handles, XPath node handles can be implicitly cast to boolean-like object to check if it is a null node, and also can be compared for equality with each other.</p>\n</div>\n<div id=\"xpath_node::ctor\" class=\"paragraph\">\n<p>You can also create XPath nodes with one of the three constructors: the default constructor, the constructor that takes node argument, and the constructor that takes attribute and node arguments (in which case the attribute must belong to the attribute list of the node). The constructor from <code>xml_node</code> is implicit, so you can usually pass <code>xml_node</code> to functions that expect <code>xpath_node</code>. Apart from that you usually don&#8217;t need to create your own XPath node objects, since they are returned to you via selection functions.</p>\n</div>\n<div id=\"xpath_node_set\" class=\"paragraph\">\n<p>XPath expressions operate not on single nodes, but instead on node sets. A node set is a collection of nodes, which can be optionally ordered in either a forward document order or a reverse one. Document order is defined in XPath specification; an XPath node is before another node in document order if it appears before it in XML representation of the corresponding document.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_node_set::const_iterator\"></a><a id=\"xpath_node_set::begin\"></a><a id=\"xpath_node_set::end\"></a>\nNode sets are represented by <code>xpath_node_set</code> object, which has an interface that resembles one of sequential random-access containers. It has an iterator type along with usual begin/past-the-end iterator accessors:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-n\">const_iterator</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::begin</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::end</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_node_set::index\"></a><a id=\"xpath_node_set::size\"></a><a id=\"xpath_node_set::empty\"></a>\nAnd it also can be iterated via indices, just like <code>std::vector</code>:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-k\">operator</span><span class=\"tok-p\">[](</span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">index</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::size</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::empty</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>All of the above operations have the same semantics as that of <code>std::vector</code>: the iterators are random-access, all of the above operations are constant time, and accessing the element at index that is greater or equal than the set size results in undefined behavior. You can use both iterator-based and index-based access for iteration, however the iterator-based one can be faster.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_node_set::type\"></a><a id=\"xpath_node_set::type_unsorted\"></a><a id=\"xpath_node_set::type_sorted\"></a><a id=\"xpath_node_set::type_sorted_reverse\"></a><a id=\"xpath_node_set::sort\"></a>\nThe order of iteration depends on the order of nodes inside the set; the order can be queried via the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-n\">type_t</span><span class=\"tok-w\"> </span><span class=\"tok-p\">{</span><span class=\"tok-n\">type_unsorted</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_sorted</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_sorted_reverse</span><span class=\"tok-p\">};</span>\n<span class=\"tok-n\">type_t</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::type</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>type</code> function returns the current order of nodes; <code>type_sorted</code> means that the nodes are in forward document order, <code>type_sorted_reverse</code> means that the nodes are in reverse document order, and <code>type_unsorted</code> means that neither order is guaranteed (nodes can accidentally be in a sorted order even if <code>type()</code> returns <code>type_unsorted</code>). If you require a specific order of iteration, you can change it via <code>sort</code> function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::sort</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">reverse</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Calling <code>sort</code> sorts the nodes in either forward or reverse document order, depending on the argument; after this call <code>type()</code> will return <code>type_sorted</code> or <code>type_sorted_reverse</code>.</p>\n</div>\n<div id=\"xpath_node_set::first\" class=\"paragraph\">\n<p>Often the actual iteration is not needed; instead, only the first element in document order is required. For this, a special accessor is provided:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_node_set::first</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This function returns the first node in forward document order from the set, or null node if the set is empty. Note that while the result of the node does not depend on the order of nodes in the set (i.e. on the result of <code>type()</code>), the complexity does - if the set is sorted, the complexity is constant, otherwise it is linear in the number of elements or worse.</p>\n</div>\n<div id=\"xpath_node_set::ctor\" class=\"paragraph\">\n<p>While in the majority of cases the node set is returned by XPath functions, sometimes there is a need to manually construct a node set. For such cases, a constructor is provided which takes an iterator range (<code>const_iterator</code> is a typedef for <code>const xpath_node*</code>), and an optional type:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-p\">(</span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">begin</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">end</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_unsorted</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The constructor copies the specified range and sets the specified type. The objects in the range are not checked in any way; you&#8217;ll have to ensure that the range contains no duplicates, and that the objects are sorted according to the <code>type</code> parameter. Otherwise XPath operations with this set may produce unexpected results.</p>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.select\"><a class=\"anchor\" href=\"#xpath.select\"></a><a class=\"link\" href=\"#xpath.select\">8.2. Selecting nodes via XPath expression</a></h3>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::select_node\"></a><a id=\"xml_node::select_nodes\"></a>\nIf you want to select nodes that match some XPath expression, you can do it with the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_node</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>select_nodes</code> function compiles the expression and then executes it with the node as a context node, and returns the resulting node set. <code>select_node</code> returns only the first node in document order from the result, and is equivalent to calling <code>select_nodes(query).first()</code>. If the XPath expression does not match anything, or the node handle is null, <code>select_nodes</code> returns an empty set, and <code>select_node</code> returns null XPath node.</p>\n</div>\n<div class=\"paragraph\">\n<p>If exception handling is not disabled, both functions throw <a href=\"#xpath_exception\">xpath_exception</a> if the query can not be compiled or if it returns a value with type other than node set; see <a href=\"#xpath.errors\">Error handling</a> for details.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xml_node::select_node_precomp\"></a><a id=\"xml_node::select_nodes_precomp\"></a>\nWhile compiling expressions is fast, the compilation time can introduce a significant overhead if the same expression is used many times on small subtrees. If you&#8217;re doing many similar queries, consider compiling them into query objects (see <a href=\"#xpath.query\">Using query objects</a> for further reference). Once you get a compiled query object, you can pass it to select functions instead of an expression string:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_node</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If exception handling is not disabled, both functions throw <a href=\"#xpath_exception\">xpath_exception</a> if the query returns a value with type other than node set.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of selecting nodes using XPath expressions (<a href=\"samples/xpath_select.cpp\" class=\"bare\">samples/xpath_select.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;/Profile/Tools/Tool[@AllowRemote=&#39;true&#39; and @DeriveCaptionFrom=&#39;lastparam&#39;]&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tools:</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">it</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-o\">*</span><span class=\"tok-n\">it</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">build_tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_node</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;//Tool[contains(Description, &#39;build system&#39;)]&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">build_tool</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Build tool: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">build_tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.query\"><a class=\"anchor\" href=\"#xpath.query\"></a><a class=\"link\" href=\"#xpath.query\">8.3. Using query objects</a></h3>\n<div id=\"xpath_query\" class=\"paragraph\">\n<p>When you call <code>select_nodes</code> with an expression string as an argument, a query object is created behind the scenes. A query object represents a compiled XPath expression. Query objects can be needed in the following circumstances:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>You can precompile expressions to query objects to save compilation time if it becomes an issue;</p>\n</li>\n<li>\n<p>You can use query objects to evaluate XPath expressions which result in booleans, numbers or strings;</p>\n</li>\n<li>\n<p>You can get the type of expression value via query object.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Query objects correspond to <code>xpath_query</code> type. They are immutable and non-copyable: they are bound to the expression at creation time and can not be cloned. If you want to put query objects in a container, either allocate them on heap via <code>new</code> operator and store pointers to <code>xpath_query</code> in the container, or use a C11 compiler (query objects are movable in C11).</p>\n</div>\n<div id=\"xpath_query::ctor\" class=\"paragraph\">\n<p>You can create a query object with the constructor that takes XPath expression as an argument:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">explicit</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div id=\"xpath_query::return_type\" class=\"paragraph\">\n<p>The expression is compiled and the compiled representation is stored in the new query object. If compilation fails, <a href=\"#xpath_exception\">xpath_exception</a> is thrown if exception handling is not disabled (see <a href=\"#xpath.errors\">Error handling</a> for details). After the query is created, you can query the type of the evaluation result using the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::return_type</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_query::evaluate_boolean\"></a><a id=\"xpath_query::evaluate_number\"></a><a id=\"xpath_query::evaluate_string\"></a><a id=\"xpath_query::evaluate_node_set\"></a><a id=\"xpath_query::evaluate_node\"></a>\nYou can evaluate the query using one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_boolean</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_number</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">string_t</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_string</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_node_set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_node</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>All functions take the context node as an argument, compute the expression and return the result, converted to the requested type. According to XPath specification, value of any type can be converted to boolean, number or string value, but no type other than node set can be converted to node set. Because of this, <code>evaluate_boolean</code>, <code>evaluate_number</code> and <code>evaluate_string</code> always return a result, but <code>evaluate_node_set</code> and <code>evaluate_node</code> result in an error if the return type is not node set (see <a href=\"#xpath.errors\">Error handling</a>).</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nCalling <code>node.select_nodes(\"query\")</code> is equivalent to calling <code>xpath_query(\"query\").evaluate_node_set(node)</code>. Calling <code>node.select_node(\"query\")</code> is equivalent to calling <code>xpath_query(\"query\").evaluate_node(node)</code>.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"xpath_query::evaluate_string_buffer\" class=\"paragraph\">\n<p>Note that <code>evaluate_string</code> function returns the STL string; as such, it&#8217;s not available in <a href=\"#PUGIXML_NO_STL\">PUGIXML_NO_STL</a> mode and also usually allocates memory. There is another string evaluation function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::evaluate_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">capacity</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This function evaluates the string, and then writes the result to <code>buffer</code> (but at most <code>capacity</code> characters); then it returns the full size of the result in characters, including the terminating zero. If <code>capacity</code> is not 0, the resulting buffer is always zero-terminated. You can use this function as follows:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>First call the function with <code>buffer = 0</code> and <code>capacity = 0</code>; then allocate the returned amount of characters, and call the function again, passing the allocated storage and the amount of characters;</p>\n</li>\n<li>\n<p>First call the function with small buffer and buffer capacity; then, if the result is larger than the capacity, the output has been trimmed, so allocate a larger buffer and call the function again.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using query objects (<a href=\"samples/xpath_query.cpp\" class=\"bare\">samples/xpath_query.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// Select nodes via compiled query</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_remote_tools</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;/Profile/Tools/Tool[@AllowRemote=&#39;true&#39;]&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_remote_tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_node_set</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Remote tool: &quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">tools</span><span class=\"tok-p\">[</span><span class=\"tok-mi\">2</span><span class=\"tok-p\">].</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// Evaluate numbers via compiled query</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_timeouts</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;sum(//Tool/@Timeout)&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_timeouts</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_number</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// Evaluate strings via compiled query for different context nodes</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_name_valid</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;string-length(substring-before(@Filename, &#39;_&#39;)) &gt; 0 and @OutputFileMasks&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;concat(substring-before(@Filename, &#39;_&#39;), &#39; produces &#39;, @OutputFileMasks)&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">first_element_by_path</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Profile/Tools/Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">())</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><span class=\"tok-n\">s</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_name</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">tool</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">query_name_valid</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_boolean</span><span class=\"tok-p\">(</span><span class=\"tok-n\">tool</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">s</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.variables\"><a class=\"anchor\" href=\"#xpath.variables\"></a><a class=\"link\" href=\"#xpath.variables\">8.4. Using variables</a></h3>\n<div class=\"paragraph\">\n<p>XPath queries may contain references to variables; this is useful if you want to use queries that depend on some dynamic parameter without manually preparing the complete query string, or if you want to reuse the same query object for similar queries.</p>\n</div>\n<div class=\"paragraph\">\n<p>Variable references have the form <code>$name</code>; in order to use them, you have to provide a variable set, which includes all variables present in the query with correct types. This set is passed to <code>xpath_query</code> constructor or to <code>select_nodes</code>/<code>select_node</code> functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">explicit</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_node</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xml_node::select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If you&#8217;re using query objects, you can change the variable values before <code>evaluate</code>/<code>select</code> calls to change the query behavior.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nThe variable set pointer is stored in the query object; you have to ensure that the lifetime of the set exceeds that of query object.\n</td>\n</tr>\n</table>\n</div>\n<div id=\"xpath_variable_set\" class=\"paragraph\">\n<p>Variable sets correspond to <code>xpath_variable_set</code> type, which is essentially a variable container.</p>\n</div>\n<div id=\"xpath_variable_set::add\" class=\"paragraph\">\n<p>You can add new variables with the following function:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::add</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The function tries to add a new variable with the specified name and type; if the variable with such name does not exist in the set, the function adds a new variable and returns the variable handle; if there is already a variable with the specified name, the function returns the variable handle if variable has the specified type. Otherwise the function returns null pointer; it also returns null pointer on allocation failure.</p>\n</div>\n<div class=\"paragraph\">\n<p>New variables are assigned the default value which depends on the type: <code>0</code> for numbers, <code>false</code> for booleans, empty string for strings and empty set for node sets.</p>\n</div>\n<div id=\"xpath_variable_set::get\" class=\"paragraph\">\n<p>You can get the existing variables with the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::get</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::get</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The functions return the variable handle, or null pointer if the variable with the specified name is not found.</p>\n</div>\n<div id=\"xpath_variable_set::set\" class=\"paragraph\">\n<p>Additionally, there are the helper functions for setting the variable value by name; they try to add the variable with the corresponding type, if it does not exist, and to set the value. If the variable with the same name but with different type is already present, they return <code>false</code>; they also return <code>false</code> on allocation failure. Note that these functions do not perform any type conversions.</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable_set::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The variable values are copied to the internal variable storage, so you can modify or destroy them after the functions return.</p>\n</div>\n<div id=\"xpath_variable\" class=\"paragraph\">\n<p>If setting variables by name is not efficient enough, or if you have to inspect variable information or get variable values, you can use variable handles. A variable corresponds to the <code>xpath_variable</code> type, and a variable handle is simply a pointer to <code>xpath_variable</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_variable::type\"></a><a id=\"xpath_variable::name\"></a>\nIn order to get variable information, you can use one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::type</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Note that each variable has a distinct type which is specified upon variable creation and can not be changed later.</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_variable::get_boolean\"></a><a id=\"xpath_variable::get_number\"></a><a id=\"xpath_variable::get_string\"></a><a id=\"xpath_variable::get_node_set\"></a>\nIn order to get variable value, you should use one of the following functions, depending on the variable type:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::get_boolean</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::get_number</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::get_string</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::get_node_set</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions return the value of the variable. Note that no type conversions are performed; if the type mismatch occurs, a dummy value is returned (<code>false</code> for booleans, <code>NaN</code> for numbers, empty string for strings and empty set for node sets).</p>\n</div>\n<div id=\"xpath_variable::set\" class=\"paragraph\">\n<p>In order to set variable value, you should use one of the following functions, depending on the variable type:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::set</span><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_variable::set</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>These functions modify the variable value. Note that no type conversions are performed; if the type mismatch occurs, the functions return <code>false</code>; they also return <code>false</code> on allocation failure. The variable values are copied to the internal variable storage, so you can modify or destroy them after the functions return.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using variables in XPath queries (<a href=\"samples/xpath_variables.cpp\" class=\"bare\">samples/xpath_variables.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// Select nodes via compiled query</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">vars</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">vars</span><span class=\"tok-p\">.</span><span class=\"tok-n\">add</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;remote&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_type_boolean</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_query</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_remote_tools</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;/Profile/Tools/Tool[@AllowRemote = string($remote)]&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&amp;</span><span class=\"tok-n\">vars</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">vars</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;remote&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools_remote</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_remote_tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_node_set</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">vars</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;remote&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools_local</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query_remote_tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">evaluate_node_set</span><span class=\"tok-p\">(</span><span class=\"tok-n\">doc</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Remote tool: &quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">tools_remote</span><span class=\"tok-p\">[</span><span class=\"tok-mi\">2</span><span class=\"tok-p\">].</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Local tool: &quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">tools_local</span><span class=\"tok-p\">[</span><span class=\"tok-mi\">0</span><span class=\"tok-p\">].</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// You can pass the context directly to select_nodes/select_node</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools_local_imm</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;/Profile/Tools/Tool[@AllowRemote = string($remote)]&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&amp;</span><span class=\"tok-n\">vars</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Local tool imm: &quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">tools_local_imm</span><span class=\"tok-p\">[</span><span class=\"tok-mi\">0</span><span class=\"tok-p\">].</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">print</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.errors\"><a class=\"anchor\" href=\"#xpath.errors\"></a><a class=\"link\" href=\"#xpath.errors\">8.5. Error handling</a></h3>\n<div class=\"paragraph\">\n<p>There are two different mechanisms for error handling in XPath implementation; the mechanism used depends on whether exception support is disabled (this is controlled with <a href=\"#PUGIXML_NO_EXCEPTIONS\">PUGIXML_NO_EXCEPTIONS</a> define).</p>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_exception\"></a><a id=\"xpath_exception::result\"></a><a id=\"xpath_exception::what\"></a>\nBy default, XPath functions throw <code>xpath_exception</code> object in case of errors; additionally, in the event any memory allocation fails, an <code>std::bad_alloc</code> exception is thrown. Also <code>xpath_exception</code> is thrown if the query is evaluated to a node set, but the return type is not node set. If the query constructor succeeds (i.e. no exception is thrown), the query object is valid. Otherwise you can get the error details via one of the following functions:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_exception::what</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-k\">noexcept</span><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_parse_result</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_exception::result</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><a id=\"xpath_query::unspecified_bool_type\"></a><a id=\"xpath_query::result\"></a>\nIf exceptions are disabled, then in the event of parsing failure the query is initialized to invalid state; you can test if the query object is valid by using it in a boolean expression: <code>if (query) { &#8230;&#8203; }</code>. Additionally, you can get parsing result via the result() accessor:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_parse_result</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">xpath_query::result</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Without exceptions, evaluating invalid query results in <code>false</code>, empty string, <code>NaN</code> or an empty node set, depending on the type; evaluating a query as a node set results in an empty node set if the return type is not node set.</p>\n</div>\n<div id=\"xpath_parse_result\" class=\"paragraph\">\n<p>The information about parsing result is returned via <code>xpath_parse_result</code> object. It contains parsing status and the offset of last successfully parsed character from the beginning of the source stream:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xpath_parse_result</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">error</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">offset</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div id=\"xpath_parse_result::error\" class=\"paragraph\">\n<p>Parsing result is represented as the error message; it is either a null pointer, in case there is no error, or the error message in the form of ASCII zero-terminated string.</p>\n</div>\n<div id=\"xpath_parse_result::description\" class=\"paragraph\">\n<p><code>description()</code> member function can be used to get the error message; it never returns the null pointer, so you can safely use <code>description()</code> even if query parsing succeeded. Note that <code>description()</code> returns a <code>char</code> string even in <code>PUGIXML_WCHAR_MODE</code>; you&#8217;ll have to call <a href=\"#as_wide\">as_wide</a> to get the <code>wchar_t</code> string.</p>\n</div>\n<div id=\"xpath_parse_result::offset\" class=\"paragraph\">\n<p>In addition to the error message, parsing result has an <code>offset</code> member, which contains the offset of last successfully parsed character. This offset is in units of <a href=\"#char_t\">pugi::char_t</a> (bytes for character mode, wide characters for wide character mode).</p>\n</div>\n<div id=\"xpath_parse_result::bool\" class=\"paragraph\">\n<p>Parsing result object can be implicitly converted to <code>bool</code> like this: <code>if (result) { &#8230;&#8203; } else { &#8230;&#8203; }</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of XPath error handling (<a href=\"samples/xpath_error.cpp\" class=\"bare\">samples/xpath_error.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// Exception is thrown for incorrect query syntax</span>\n<span class=\"tok-k\">try</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;//nodes[#true()]&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span>\n<span class=\"tok-k\">catch</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_exception</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Select failed: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">.</span><span class=\"tok-n\">what</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-c1\">// Exception is thrown for incorrect query semantics</span>\n<span class=\"tok-k\">try</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;(123)/next&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span>\n<span class=\"tok-k\">catch</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_exception</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Select failed: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">.</span><span class=\"tok-n\">what</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-c1\">// Exception is thrown for query with incorrect return type</span>\n<span class=\"tok-k\">try</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;123&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-p\">}</span>\n<span class=\"tok-k\">catch</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_exception</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Select failed: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">e</span><span class=\"tok-p\">.</span><span class=\"tok-n\">what</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"xpath.w3c\"><a class=\"anchor\" href=\"#xpath.w3c\"></a><a class=\"link\" href=\"#xpath.w3c\">8.6. Conformance to W3C specification</a></h3>\n<div class=\"paragraph\">\n<p>Because of the differences in document object models, performance considerations and implementation complexity, pugixml does not provide a fully conformant XPath 1.0 implementation. This is the current list of incompatibilities:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Consecutive text nodes sharing the same parent are not merged, i.e. in <code>&lt;node&gt;text1 &lt;![CDATA[data]]&gt; text2&lt;/node&gt;</code> node should have one text node child, but instead has three.</p>\n</li>\n<li>\n<p>Since the document type declaration is not used for parsing, <code>id()</code> function always returns an empty node set.</p>\n</li>\n<li>\n<p>Namespace nodes are not supported (affects <code>namespace::</code> axis).</p>\n</li>\n<li>\n<p>Name tests are performed on QNames in XML document instead of expanded names; for <code>&lt;foo xmlns:ns1='uri' xmlns:ns2='uri'&gt;&lt;ns1:child/&gt;&lt;ns2:child/&gt;&lt;/foo&gt;</code>, query <code>foo/ns1:*</code> will return only the first child, not both of them. Compliant XPath implementations can return both nodes if the user provides appropriate namespace declarations.</p>\n</li>\n<li>\n<p>String functions consider a character to be either a single <code>char</code> value or a single <code>wchar_t</code> value, depending on the library configuration; this means that some string functions are not fully Unicode-aware. This affects <code>substring()</code>, <code>string-length()</code> and <code>translate()</code> functions.</p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"changes\"><a class=\"anchor\" href=\"#changes\"></a><a class=\"link\" href=\"#changes\">9. Changelog</a></h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"v1.15\"><a class=\"anchor\" href=\"#v1.15\"></a><a class=\"link\" href=\"#v1.15\">v1.15 <sup>2024-01-10</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Many <code>xml_attribute::</code> and <code>xml_node::</code> functions now transparently support <code>std::string_view</code> and <code>std::string</code> when C++17 support is detected.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>CMake improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Improve <code>pkg-config</code> file generation for NixOS</p>\n</li>\n<li>\n<p><code>PUGIXML_BUILD_APPLE_FRAMEWORK</code> CMake option can be used to build pugixml as <code>.xcframework</code></p>\n</li>\n<li>\n<p><code>PUGIXML_INSTALL</code> CMake option can be used to disable installation targets</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix clang/gcc warnings <code>-Wzero-as-null-pointer-constant</code>, <code>-Wuseless-cast</code>, <code>-Wshorten-64-to-32</code></p>\n</li>\n<li>\n<p>Fix unreferenced function warnings in <code>PUGIXML_NO_STL</code> configuration</p>\n</li>\n<li>\n<p>Fix CMake 3.31 deprecation warnings</p>\n</li>\n<li>\n<p>Stop using deprecated <code>throw()</code> when <code>noexcept</code> is available</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.14\"><a class=\"anchor\" href=\"#v1.14\"></a><a class=\"link\" href=\"#v1.14\">v1.14 <sup>2023-10-01</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xml_attribute::set_name</code> and <code>xml_node::set_name</code> now have overloads that accept pointer to non-null-terminated string and size</p>\n</li>\n<li>\n<p>Implement <code>parse_merge_pcdata</code> parsing mode in which PCDATA contents is merged into a single node when original document had comments that were skipped during parsing</p>\n</li>\n<li>\n<p><code>xml_document::load_file</code> now returns a more consistent error status when given a path to a folder</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix assertion in XPath number&#8594;string conversion when using non-English locales</p>\n</li>\n<li>\n<p>Fix PUGIXML_STATIC_CRT CMake option to correctly select static CRT when using MSVC and recent CMake</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix GCC 2.95/3.3 builds</p>\n</li>\n<li>\n<p>Fix CMake 3.27 deprecation warnings</p>\n</li>\n<li>\n<p>Fix XCode 14 sprintf deprecation warning when compiling in C++03 mode</p>\n</li>\n<li>\n<p>Fix clang/gcc warnings <code>-Wweak-vtables</code>, <code>-Wreserved-macro-identifier</code></p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.13\"><a class=\"anchor\" href=\"#v1.13\"></a><a class=\"link\" href=\"#v1.13\">v1.13 <sup>2022-11-01</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xml_attribute::set_value</code>, <code>xml_node::set_value</code> and <code>xml_text::set</code> now have overloads that accept pointer to non-null-terminated string and size</p>\n</li>\n<li>\n<p>Improve performance of tree traversal when using compact mode (<code>PUGIXML_COMPACT</code>)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix error handling in <code>xml_document::save_file</code> that could result in the function succeeding while running out of disk space</p>\n</li>\n<li>\n<p>Fix memory leak during error handling of some out-of-memory conditions during <code>xml_document::load</code></p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix exported symbols in CMake DLL builds when using CMake</p>\n</li>\n<li>\n<p>Fix exported symbols in CMake shared object builds when using -fvisibility=hidden</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.12\"><a class=\"anchor\" href=\"#v1.12\"></a><a class=\"link\" href=\"#v1.12\">v1.12 <sup>2022-02-09</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix a bug in xml_document move construction when the source of the move is empty</p>\n</li>\n<li>\n<p>Fix const-correctness issues with iterator objects to support C++20 ranges</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>XPath improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Improved detection of overly complex queries that may result in stack overflow during parsing</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix Cygwin support for DLL builds</p>\n</li>\n<li>\n<p>Fix Windows CE support</p>\n</li>\n<li>\n<p>Add NuGet builds and project files for VS2022</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Build system changes</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>All CMake options now have the prefix <code>PUGIXML_</code>. This may require changing dependent build configurations.</p>\n</li>\n<li>\n<p>Many build settings are now exposed via CMake settings, most notably <code>PUGIXML_COMPACT</code> and <code>PUGIXML_WCHAR_MODE</code> can be set without changing <code>pugiconfig.hpp</code></p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.11\"><a class=\"anchor\" href=\"#v1.11\"></a><a class=\"link\" href=\"#v1.11\">v1.11 <sup>2020-11-26</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Add xml_node::remove_attributes and xml_node::remove_children</p>\n</li>\n<li>\n<p>Add a way to customize floating point precision via xml_attribute::set and xml_text::set overloads</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>XPath improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>XPath parser now limits recursion depth which prevents stack overflow on malicious queries</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix Visual Studio warnings when built using clang-cl compiler</p>\n</li>\n<li>\n<p>Fix Wconversion warnings in gcc</p>\n</li>\n<li>\n<p>Fix Wzero-as-null-pointer-constant warnings in pugixml.hpp</p>\n</li>\n<li>\n<p>Work around several static analysis false positives</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Build system changes</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>The CMake package for pugixml now provides a <code>pugixml::pugixml</code> target rather than a <code>pugixml</code> target. A compatibility <code>pugixml</code> target is provided if at least version 1.11 is not requested.</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.10\"><a class=\"anchor\" href=\"#v1.10\"></a><a class=\"link\" href=\"#v1.10\">v1.10 <sup>2019-09-15</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Behavior changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Tab characters (ASCII 9) in attribute values are now encoded as '&amp;#9;' to survive roundtripping</p>\n</li>\n<li>\n<p><code>&gt;</code> characters are no longer escaped in attribute values</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Add Visual Studio .natvis files to improve debugging experience</p>\n</li>\n<li>\n<p>CMake improvements (USE_POSTFIX and BUILD_SHARED_AND_STATIC_LIBS options for building multiple versions and pkg-config tweaks)</p>\n</li>\n<li>\n<p>Add format_skip_control_chars formatting flag to skip non-printable ASCII characters that are invalid to use in well-formed XML files</p>\n</li>\n<li>\n<p>Add format_attribute_single_quote formatting flag to use single quotes for attribute values instead of default double quotes.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>XPath improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>XPath union now results in a stable order that doesn&#8217;t depend on memory allocations; crucially, this may require sorting the output of XPath query operation if you rely on the document-ordered traversal</p>\n</li>\n<li>\n<p>Improve performance of XPath union operation, making it ~2x faster</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix Visual Studio warnings when built in a DLL configuration</p>\n</li>\n<li>\n<p>Fix static analysis false positives in Coverity and clang</p>\n</li>\n<li>\n<p>Fix Wdouble-promotion warnings in gcc</p>\n</li>\n<li>\n<p>Add Visual Studio 2019 support for NuGet packages</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.9\"><a class=\"anchor\" href=\"#v1.9\"></a><a class=\"link\" href=\"#v1.9\">v1.9 <sup>2018-04-04</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xml_document::load(const char*)</code> (deprecated in 1.5) now has <code>deprecated</code> attribute; use <code>xml_document::load_string</code> instead</p>\n</li>\n<li>\n<p><code>xml_node::select_single_node</code> (deprecated in 1.5) now has <code>deprecated</code> attribute; use <code>xml_node::select_node</code> instead</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Add move semantics support for xml_document and improve move semantics support for other objects</p>\n</li>\n<li>\n<p>CMake build now exports include directories</p>\n</li>\n<li>\n<p>CMake build with BUILD_SHARED_LIBS=ON now uses dllexport attribute for MSVC</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>XPath improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Rework parser/evaluator to not rely on exceptional control flow; longjmp is no longer used when exceptions are disabled</p>\n</li>\n<li>\n<p>Improve error messages for certain invalid expressions such as <code>.[1]</code> or <code>(1</code></p>\n</li>\n<li>\n<p>Minor performance improvements</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix Texas Instruments compiler warnings</p>\n</li>\n<li>\n<p>Fix compilation issues with limits.h for some versions of gcc</p>\n</li>\n<li>\n<p>Fix compilation issues with Clang/C2</p>\n</li>\n<li>\n<p>Fix implicit fallthrough warnings in gcc 7</p>\n</li>\n<li>\n<p>Fix unknown attribute directive warnings in gcc 8</p>\n</li>\n<li>\n<p>Fix cray++ compiler errors</p>\n</li>\n<li>\n<p>Fix unsigned integer overflow errors with -fsanitize=integer</p>\n</li>\n<li>\n<p>Fix undefined behavior sanitizer issues in compact mode</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.8\"><a class=\"anchor\" href=\"#v1.8\"></a><a class=\"link\" href=\"#v1.8\">v1.8 <sup>2016-11-24</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>When printing empty elements, a space is no longer added before / in format_raw mode</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added parse_embed_pcdata parsing mode in which PCDATA value is stored in the element node if possible (significantly reducing memory consumption for some documents)</p>\n</li>\n<li>\n<p>Added auto-detection support for Latin-1 (ISO-8859-1) encoding during parsing</p>\n</li>\n<li>\n<p>Added format_no_empty_element_tags formatting flag that outputs start/end tags instead of empty element tags for empty elements</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Performance improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Minor memory allocation improvements (yielding up to 1% memory savings in some cases)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed compilation issues for Borland C++ 5.4</p>\n</li>\n<li>\n<p>Fixed compilation issues for some distributions of MinGW 3.8</p>\n</li>\n<li>\n<p>Fixed various Clang/GCC warnings</p>\n</li>\n<li>\n<p>Enabled move semantics support for XPath objects for MSVC 2010 and above</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.7\"><a class=\"anchor\" href=\"#v1.7\"></a><a class=\"link\" href=\"#v1.7\">v1.7 <sup>2015-10-19</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring performance and memory improvements along with some new features. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Compact mode:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Introduced a new tree storage mode that takes significantly less memory (2-5x smaller DOM) at some performance cost.</p>\n</li>\n<li>\n<p>The mode can be enabled using <code>PUGIXML_COMPACT</code> define.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New integer parsing/formatting implementation:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Functions that convert from and to integers (e.g. <code>as_int</code>/<code>set_value</code>) do not rely on CRT any more.</p>\n</li>\n<li>\n<p>New implementation is 3-5x faster and is always correct wrt overflow or underflow. This is a behavior change - where previously <code>as_uint()</code> would return UINT_MAX on a value \"-1\", it now returns 0.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>XPath objects (<code>xpath_query</code>, <code>xpath_node_set</code>, <code>xpath_variable_set</code>) are now movable if your compiler supports C++11. Additionally, <code>xpath_variable_set</code> is copyable.</p>\n</li>\n<li>\n<p>Added <code>format_indent_attributes</code> that makes the resulting XML friendlier to line diff/merge tools.</p>\n</li>\n<li>\n<p>Added a variant of <code>xml_node::attribute</code> function with a hint that can improve lookup performance.</p>\n</li>\n<li>\n<p>Custom allocation functions are now allowed (but not required) to throw instead of returning a null pointer.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fix Clang 3.7 crashes in out-of-memory cases (C++ DR 1748)</p>\n</li>\n<li>\n<p>Fix XPath crashes on SPARC64 (and other 32-bit architectures where doubles have to be aligned to 8 bytes)</p>\n</li>\n<li>\n<p>Fix xpath_node_set assignment to provide strong exception guarantee</p>\n</li>\n<li>\n<p>Fix saving for custom xml_writer implementations that can throw from write()</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.6\"><a class=\"anchor\" href=\"#v1.6\"></a><a class=\"link\" href=\"#v1.6\">v1.6 <sup>2015-04-10</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Attribute/text values now use more digits when printing floating point numbers to guarantee round-tripping.</p>\n</li>\n<li>\n<p>Text nodes no longer get extra surrounding whitespace when pretty-printing nodes with mixed contents</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed translate and normalize-space XPath functions to no longer return internal NUL characters</p>\n</li>\n<li>\n<p>Fixed buffer overrun on malformed comments inside DOCTYPE sections</p>\n</li>\n<li>\n<p>DOCTYPE parsing can no longer run out of stack space on malformed inputs (XML parsing is now using bounded stack space)</p>\n</li>\n<li>\n<p>Adjusted processing instruction output to avoid malformed documents if the PI value contains <code>?&gt;</code></p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.5\"><a class=\"anchor\" href=\"#v1.5\"></a><a class=\"link\" href=\"#v1.5\">v1.5 <sup>2014-11-27</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring a lot of performance improvements and some new features.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xml_document::load(const char_t*)</code> was renamed to <code>load_string</code>; the old method is still available and will be deprecated in a future release</p>\n</li>\n<li>\n<p><code>xml_node::select_single_node</code> was renamed to <code>select_node</code>; the old method is still available and will be deprecated in a future release.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added <code>xml_node::append_move</code> and other functions for moving nodes within a document</p>\n</li>\n<li>\n<p>Added <code>xpath_query::evaluate_node</code> for evaluating queries with a single node as a result</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Performance improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Optimized XML parsing (10-40% faster with clang/gcc, up to 10% faster with MSVC)</p>\n</li>\n<li>\n<p>Optimized memory consumption when copying nodes in the same document (string contents is now shared)</p>\n</li>\n<li>\n<p>Optimized node copying (10% faster for cross-document copies, 3x faster for inter-document copies; also it now consumes a constant amount of stack space)</p>\n</li>\n<li>\n<p>Optimized node output (60% faster; also it now consumes a constant amount of stack space)</p>\n</li>\n<li>\n<p>Optimized XPath allocation (query evaluation now results in fewer temporary allocations)</p>\n</li>\n<li>\n<p>Optimized XPath sorting (node set sorting is 2-3x faster in some cases)</p>\n</li>\n<li>\n<p>Optimized XPath evaluation (XPathMark suite is 100x faster; some commonly used queries are 3-4x faster)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed <code>xml_node::offset_debug</code> for corner cases</p>\n</li>\n<li>\n<p>Fixed undefined behavior while calling memcpy in some cases</p>\n</li>\n<li>\n<p>Fixed MSVC 2015 compilation warnings</p>\n</li>\n<li>\n<p>Fixed <code>contrib/foreach.hpp</code> for Boost 1.56.0</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Adjusted comment output to avoid malformed documents if the comment value contains <code>--</code></p>\n</li>\n<li>\n<p>Fix XPath sorting for documents that were constructed using append_buffer</p>\n</li>\n<li>\n<p>Fix <code>load_file</code> for wide-character paths with non-ASCII characters in MinGW with C&#43;&#43;11 mode enabled</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.4\"><a class=\"anchor\" href=\"#v1.4\"></a><a class=\"link\" href=\"#v1.4\">v1.4 <sup>2014-02-27</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring various new features, bug fixes and compatibility improvements.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Documents without element nodes are now rejected with <code>status_no_document_element</code> error, unless <code>parse_fragment</code> option is used</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added XML fragment parsing (<code>parse_fragment</code> flag)</p>\n</li>\n<li>\n<p>Added PCDATA whitespace trimming (<code>parse_trim_pcdata</code> flag)</p>\n</li>\n<li>\n<p>Added long long support for <code>xml_attribute</code> and <code>xml_text</code> (<code>as_llong</code>, <code>as_ullong</code> and <code>set_value</code>/<code>set</code> overloads)</p>\n</li>\n<li>\n<p>Added hexadecimal integer parsing support for <code>as_int</code>/<code>as_uint</code>/<code>as_llong</code>/<code>as_ullong</code></p>\n</li>\n<li>\n<p>Added <code>xml_node::append_buffer</code> to improve performance of assembling documents from fragments</p>\n</li>\n<li>\n<p><code>xml_named_node_iterator</code> is now bidirectional</p>\n</li>\n<li>\n<p>Reduced XPath stack consumption during compilation and evaluation (useful for embedded systems)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Improved support for platforms without wchar_t support</p>\n</li>\n<li>\n<p>Fixed several false positives in clang static analysis</p>\n</li>\n<li>\n<p>Fixed several compilation warnings for various GCC versions</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed undefined pointer arithmetic in XPath implementation</p>\n</li>\n<li>\n<p>Fixed non-seekable iostream support for certain stream types, i.e. Boost <code>file_source</code> with pipe input</p>\n</li>\n<li>\n<p>Fixed <code>xpath_query::return_type</code> for some expressions</p>\n</li>\n<li>\n<p>Fixed dllexport issues with <code>xml_named_node_iterator</code></p>\n</li>\n<li>\n<p>Fixed <code>find_child_by_attribute</code> assertion for attributes with null name/value</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.2\"><a class=\"anchor\" href=\"#v1.2\"></a><a class=\"link\" href=\"#v1.2\">v1.2 <sup>2012-05-01</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring header-only mode, various interface enhancements (i.e. PCDATA manipulation and C&#43;&#43;11 iteration), many other features and compatibility improvements.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added <code>xml_text</code> helper class for working with PCDATA/CDATA contents of an element node</p>\n</li>\n<li>\n<p>Added optional header-only mode (controlled by <code>PUGIXML_HEADER_ONLY</code> define)</p>\n</li>\n<li>\n<p>Added <code>xml_node::children()</code> and <code>xml_node::attributes()</code> for C&#43;&#43;11 ranged for loop or <code>BOOST_FOREACH</code></p>\n</li>\n<li>\n<p>Added support for Latin-1 (ISO-8859-1) encoding conversion during loading and saving</p>\n</li>\n<li>\n<p>Added custom default values for <code>xml_attribute::as_*</code> (they are returned if the attribute does not exist)</p>\n</li>\n<li>\n<p>Added <code>parse_ws_pcdata_single</code> flag for preserving whitespace-only PCDATA in case it&#8217;s the only child</p>\n</li>\n<li>\n<p>Added <code>format_save_file_text</code> for <code>xml_document::save_file</code> to open files as text instead of binary (changes newlines on Windows)</p>\n</li>\n<li>\n<p>Added <code>format_no_escapes</code> flag to disable special symbol escaping (complements <code>~parse_escapes</code>)</p>\n</li>\n<li>\n<p>Added support for loading document from streams that do not support seeking</p>\n</li>\n<li>\n<p>Added <code>PUGIXML_MEMORY_*</code> constants for tweaking allocation behavior (useful for embedded systems)</p>\n</li>\n<li>\n<p>Added <code>PUGIXML_VERSION</code> preprocessor define</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Parser does not require setjmp support (improves compatibility with some embedded platforms, enables <code>/clr:pure</code> compilation)</p>\n</li>\n<li>\n<p>STL forward declarations are no longer used (fixes SunCC/RWSTL compilation, fixes clang compilation in C&#43;&#43;11 mode)</p>\n</li>\n<li>\n<p>Fixed AirPlay SDK, Android, Windows Mobile (WinCE) and C&#43;&#43;/CLI compilation</p>\n</li>\n<li>\n<p>Fixed several compilation warnings for various GCC versions, Intel C&#43;&#43; compiler and Clang</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed unsafe bool conversion to avoid problems on C&#43;&#43;/CLI</p>\n</li>\n<li>\n<p>Iterator dereference operator is const now (fixes Boost <code>filter_iterator</code> support)</p>\n</li>\n<li>\n<p><code>xml_document::save_file</code> now checks for file I/O errors during saving</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v1.0\"><a class=\"anchor\" href=\"#v1.0\"></a><a class=\"link\" href=\"#v1.0\">v1.0 <sup>2010-11-01</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring many XPath enhancements, wide character filename support, miscellaneous performance improvements, bug fixes and more.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>XPath:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>XPath implementation is moved to <code>pugixml.cpp</code> (which is the only source file now); use <code>PUGIXML_NO_XPATH</code> if you want to disable XPath to reduce code size</p>\n</li>\n<li>\n<p>XPath is now supported without exceptions (<code>PUGIXML_NO_EXCEPTIONS</code>); the error handling mechanism depends on the presence of exception support</p>\n</li>\n<li>\n<p>XPath is now supported without STL (<code>PUGIXML_NO_STL</code>)</p>\n</li>\n<li>\n<p>Introduced variable support</p>\n</li>\n<li>\n<p>Introduced new <code>xpath_query::evaluate_string</code>, which works without STL</p>\n</li>\n<li>\n<p>Introduced new <code>xpath_node_set</code> constructor (from an iterator range)</p>\n</li>\n<li>\n<p>Evaluation function now accept attribute context nodes</p>\n</li>\n<li>\n<p>All internal allocations use custom allocation functions</p>\n</li>\n<li>\n<p>Improved error reporting; now a last parsed offset is returned together with the parsing error</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed memory leak for loading from streams with stream exceptions turned on</p>\n</li>\n<li>\n<p>Fixed custom deallocation function calling with null pointer in one case</p>\n</li>\n<li>\n<p>Fixed missing attributes for iterator category functions; all functions/classes can now be DLL-exported</p>\n</li>\n<li>\n<p>Worked around Digital Mars compiler bug, which lead to minor read overfetches in several functions</p>\n</li>\n<li>\n<p><code>load_file</code> now works with 2+ Gb files in MSVC/MinGW</p>\n</li>\n<li>\n<p>XPath: fixed memory leaks for incorrect queries</p>\n</li>\n<li>\n<p>XPath: fixed <code>xpath_node()</code> attribute constructor with empty attribute argument</p>\n</li>\n<li>\n<p>XPath: fixed <code>lang()</code> function for non-ASCII arguments</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>CDATA nodes containing <code>]]&gt;</code> are printed as several nodes; while this changes the internal structure, this is the only way to escape CDATA contents</p>\n</li>\n<li>\n<p>Memory allocation errors during parsing now preserve last parsed offset (to give an idea about parsing progress)</p>\n</li>\n<li>\n<p>If an element node has the only child, and it is of CDATA type, then the extra indentation is omitted (previously this behavior only held for PCDATA children)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Additional functionality:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added <code>xml_parse_result</code> default constructor</p>\n</li>\n<li>\n<p>Added <code>xml_document::load_file</code> and <code>xml_document::save_file</code> with wide character paths</p>\n</li>\n<li>\n<p>Added <code>as_utf8</code> and <code>as_wide</code> overloads for <code>std::wstring</code>/<code>std::string</code> arguments</p>\n</li>\n<li>\n<p>Added DOCTYPE node type (<code>node_doctype</code>) and a special parse flag, <code>parse_doctype</code>, to add such nodes to the document during parsing</p>\n</li>\n<li>\n<p>Added <code>parse_full</code> parse flag mask, which extends <code>parse_default</code> with all node type parsing flags except <code>parse_ws_pcdata</code></p>\n</li>\n<li>\n<p>Added <code>xml_node::hash_value()</code> and <code>xml_attribute::hash_value()</code> functions for use in hash-based containers</p>\n</li>\n<li>\n<p>Added <code>internal_object()</code> and additional constructor for both <code>xml_node</code> and <code>xml_attribute</code> for easier marshalling (useful for language bindings)</p>\n</li>\n<li>\n<p>Added <code>xml_document::document_element()</code> function</p>\n</li>\n<li>\n<p>Added <code>xml_node::prepend_attribute</code>, <code>xml_node::prepend_child</code> and <code>xml_node::prepend_copy</code> functions</p>\n</li>\n<li>\n<p>Added <code>xml_node::append_child</code>, <code>xml_node::prepend_child</code>, <code>xml_node::insert_child_before</code> and <code>xml_node::insert_child_after</code> overloads for element nodes (with name instead of type)</p>\n</li>\n<li>\n<p>Added <code>xml_document::reset()</code> function</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Performance improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xml_node::root()</code> and <code>xml_node::offset_debug()</code> are now O(1) instead of O(logN)</p>\n</li>\n<li>\n<p>Minor parsing optimizations</p>\n</li>\n<li>\n<p>Minor memory optimization for strings in DOM tree (<code>set_name</code>/<code>set_value</code>)</p>\n</li>\n<li>\n<p>Memory optimization for string memory reclaiming in DOM tree (<code>set_name</code>/<code>set_value</code> now reallocate the buffer if memory waste is too big)</p>\n</li>\n<li>\n<p>XPath: optimized document order sorting</p>\n</li>\n<li>\n<p>XPath: optimized child/attribute axis step</p>\n</li>\n<li>\n<p>XPath: optimized number-to-string conversions in MSVC</p>\n</li>\n<li>\n<p>XPath: optimized concat for many arguments</p>\n</li>\n<li>\n<p>XPath: optimized evaluation allocation mechanism: constant and document strings are not heap-allocated</p>\n</li>\n<li>\n<p>XPath: optimized evaluation allocation mechanism: all temporaries' allocations use fast stack-like allocator</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Removed wildcard functions (<code>xml_node::child_w</code>, <code>xml_node::attribute_w</code>, etc.)</p>\n</li>\n<li>\n<p>Removed <code>xml_node::all_elements_by_name</code></p>\n</li>\n<li>\n<p>Removed <code>xpath_type_t</code> enumeration; use <code>xpath_value_type</code> instead</p>\n</li>\n<li>\n<p>Removed <code>format_write_bom_utf8</code> enumeration; use <code>format_write_bom</code> instead</p>\n</li>\n<li>\n<p>Removed <code>xml_document::precompute_document_order</code>, <code>xml_attribute::document_order</code> and <code>xml_node::document_order</code> functions; document order sort optimization is now automatic</p>\n</li>\n<li>\n<p>Removed <code>xml_document::parse</code> functions and <code>transfer_ownership</code> struct; use <code>xml_document::load_buffer_inplace</code> and <code>xml_document::load_buffer_inplace_own</code> instead</p>\n</li>\n<li>\n<p>Removed <code>as_utf16</code> function; use <code>as_wide</code> instead</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.9\"><a class=\"anchor\" href=\"#v0.9\"></a><a class=\"link\" href=\"#v0.9\">v0.9 <sup>2010-07-01</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major release, featuring extended and improved Unicode support, miscellaneous performance improvements, bug fixes and more.</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Major Unicode improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Introduced encoding support (automatic/manual encoding detection on load, manual encoding selection on save, conversion from/to UTF8, UTF16 LE/BE, UTF32 LE/BE)</p>\n</li>\n<li>\n<p>Introduced <code>wchar_t</code> mode (you can set <code>PUGIXML_WCHAR_MODE</code> define to switch pugixml internal encoding from UTF8 to <code>wchar_t</code>; all functions are switched to their Unicode variants)</p>\n</li>\n<li>\n<p>Load/save functions now support wide streams</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed document corruption on failed parsing bug</p>\n</li>\n<li>\n<p>XPath string/number conversion improvements (increased precision, fixed crash for huge numbers)</p>\n</li>\n<li>\n<p>Improved DOCTYPE parsing: now parser recognizes all well-formed DOCTYPE declarations</p>\n</li>\n<li>\n<p>Fixed <code>xml_attribute::as_uint()</code> for large numbers (i.e. 2<sup>32</sup>-1)</p>\n</li>\n<li>\n<p>Fixed <code>xml_node::first_element_by_path</code> for path components that are prefixes of node names, but are not exactly equal to them.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>parse()</code> API changed to <code>load_buffer</code>/<code>load_buffer_inplace</code>/<code>load_buffer_inplace_own</code>; <code>load_buffer</code> APIs do not require zero-terminated strings.</p>\n</li>\n<li>\n<p>Renamed <code>as_utf16</code> to <code>as_wide</code></p>\n</li>\n<li>\n<p>Changed <code>xml_node::offset_debug</code> return type and <code>xml_parse_result::offset</code> type to <code>ptrdiff_t</code></p>\n</li>\n<li>\n<p>Nodes/attributes with empty names are now printed as <code>:anonymous</code></p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Performance improvements:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Optimized document parsing and saving</p>\n</li>\n<li>\n<p>Changed internal memory management: internal allocator is used for both metadata and name/value data; allocated pages are deleted if all allocations from them are deleted</p>\n</li>\n<li>\n<p>Optimized memory consumption: <code>sizeof(xml_node_struct)</code> reduced from 40 bytes to 32 bytes on x86</p>\n</li>\n<li>\n<p>Optimized debug mode parsing/saving by order of magnitude</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Miscellaneous:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>All STL includes except <code>&lt;exception&gt;</code> in <code>pugixml.hpp</code> are replaced with forward declarations</p>\n</li>\n<li>\n<p><code>xml_node::remove_child</code> and <code>xml_node::remove_attribute</code> now return the operation result</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Compatibility:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>parse()</code> and <code>as_utf16</code> are left for compatibility (these functions are deprecated and will be removed in version 1.0)</p>\n</li>\n<li>\n<p>Wildcard functions, <code>document_order</code>/<code>precompute_document_order</code> functions, <code>all_elements_by_name</code> function and <code>format_write_bom_utf8</code> flag are deprecated and will be removed in version 1.0</p>\n</li>\n<li>\n<p><code>xpath_type_t</code> enumeration was renamed to <code>xpath_value_type</code>; <code>xpath_type_t</code> is deprecated and will be removed in version 1.0</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.5\"><a class=\"anchor\" href=\"#v0.5\"></a><a class=\"link\" href=\"#v0.5\">v0.5 <sup>2009-11-08</sup></a></h3>\n<div class=\"paragraph\">\n<p>Major bugfix release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>XPath bugfixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed <code>translate()</code>, <code>lang()</code> and <code>concat()</code> functions (infinite loops/crashes)</p>\n</li>\n<li>\n<p>Fixed compilation of queries with empty literal strings (<code>\"\"</code>)</p>\n</li>\n<li>\n<p>Fixed axis tests: they never add empty nodes/attributes to the resulting node set now</p>\n</li>\n<li>\n<p>Fixed string-value evaluation for node-set (the result excluded some text descendants)</p>\n</li>\n<li>\n<p>Fixed <code>self::</code> axis (it behaved like <code>ancestor-or-self::</code>)</p>\n</li>\n<li>\n<p>Fixed <code>following::</code> and <code>preceding::</code> axes (they included descendent and ancestor nodes, respectively)</p>\n</li>\n<li>\n<p>Minor fix for <code>namespace-uri()</code> function (namespace declaration scope includes the parent element of namespace declaration attribute)</p>\n</li>\n<li>\n<p>Some incorrect queries are no longer parsed now (i.e. <code>foo: *</code>)</p>\n</li>\n<li>\n<p>Fixed <code>text()</code>/etc. node test parsing bug (i.e. <code>foo[text()]</code> failed to compile)</p>\n</li>\n<li>\n<p>Fixed root step (<code>/</code>) - it now selects empty node set if query is evaluated on empty node</p>\n</li>\n<li>\n<p>Fixed string to number conversion (<code>\"123 \"</code> converted to NaN, <code>\"123 .456\"</code> converted to 123.456 - now the results are 123 and NaN, respectively)</p>\n</li>\n<li>\n<p>Node set copying now preserves sorted type; leads to better performance on some queries</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Miscellaneous bugfixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed <code>xml_node::offset_debug</code> for PI nodes</p>\n</li>\n<li>\n<p>Added empty attribute checks to <code>xml_node::remove_attribute</code></p>\n</li>\n<li>\n<p>Fixed <code>node_pi</code> and <code>node_declaration</code> copying</p>\n</li>\n<li>\n<p>Const-correctness fixes</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Specification changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><code>xpath_node::select_nodes()</code> and related functions now throw exception if expression return type is not node set (instead of assertion)</p>\n</li>\n<li>\n<p><code>xml_node::traverse()</code> now sets depth to -1 for both <code>begin()</code> and <code>end()</code> callbacks (was 0 at <code>begin()</code> and -1 at <code>end()</code>)</p>\n</li>\n<li>\n<p>In case of non-raw node printing a newline is output after PCDATA inside nodes if the PCDATA has siblings</p>\n</li>\n<li>\n<p>UTF8 &#8594; <code>wchar_t</code> conversion now considers 5-byte UTF8-like sequences as invalid</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added <code>xpath_node_set::operator[]</code> for index-based iteration</p>\n</li>\n<li>\n<p>Added <code>xpath_query::return_type()</code></p>\n</li>\n<li>\n<p>Added getter accessors for memory-management functions</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.42\"><a class=\"anchor\" href=\"#v0.42\"></a><a class=\"link\" href=\"#v0.42\">v0.42 <sup>2009-09-17</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed deallocation in case of custom allocation functions or if <code>delete[]</code> / <code>free</code> are incompatible</p>\n</li>\n<li>\n<p>XPath parser fixed for incorrect queries (i.e. incorrect XPath queries should now always fail to compile)</p>\n</li>\n<li>\n<p>Const-correctness fixes for <code>find_child_by_attribute</code></p>\n</li>\n<li>\n<p>Improved compatibility (miscellaneous warning fixes, fixed <code>&lt;cstring&gt;</code> include dependency for GCC)</p>\n</li>\n<li>\n<p>Fixed iterator begin/end and print function to work correctly for empty nodes</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added <code>PUGIXML_API</code>/<code>PUGIXML_CLASS</code>/<code>PUGIXML_FUNCTION</code> configuration macros to control class/function attributes</p>\n</li>\n<li>\n<p>Added <code>xml_attribute::set_value</code> overloads for different types</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.41\"><a class=\"anchor\" href=\"#v0.41\"></a><a class=\"link\" href=\"#v0.41\">v0.41 <sup>2009-02-08</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed bug with node printing (occasionally some content was not written to output stream)</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.4\"><a class=\"anchor\" href=\"#v0.4\"></a><a class=\"link\" href=\"#v0.4\">v0.4 <sup>2009-01-18</sup></a></h3>\n<div class=\"paragraph\">\n<p>Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Documentation fix in samples for <code>parse()</code> with manual lifetime control</p>\n</li>\n<li>\n<p>Fixed document order sorting in XPath (it caused wrong order of nodes after <code>xpath_node_set::sort</code> and wrong results of some XPath queries)</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Node printing changes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Single quotes are no longer escaped when printing nodes</p>\n</li>\n<li>\n<p>Symbols in second half of ASCII table are no longer escaped when printing nodes; because of this, <code>format_utf8</code> flag is deleted as it&#8217;s no longer needed and <code>format_write_bom</code> is renamed to <code>format_write_bom_utf8</code>.</p>\n</li>\n<li>\n<p>Reworked node printing - now it works via <code>xml_writer</code> interface; implementations for <code>FILE*</code> and <code>std::ostream</code> are available. As a side-effect, <code>xml_document::save_file</code> now works without STL.</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added unsigned integer support for attributes (<code>xml_attribute::as_uint</code>, <code>xml_attribute::operator=</code>)</p>\n</li>\n<li>\n<p>Now document declaration (<code>&lt;?xml &#8230;&#8203;?&gt;</code>) is parsed as node with type <code>node_declaration</code> when <code>parse_declaration</code> flag is specified (access to encoding/version is performed as if they were attributes, i.e. <code>doc.child(\"xml\").attribute(\"version\").as_float()</code>); corresponding flags for node printing were also added</p>\n</li>\n<li>\n<p>Added support for custom memory management (see <code>set_memory_management_functions</code> for details)</p>\n</li>\n<li>\n<p>Implemented node/attribute copying (see <code>xml_node::insert_copy_*</code> and <code>xml_node::append_copy</code> for details)</p>\n</li>\n<li>\n<p>Added <code>find_child_by_attribute</code> and <code>find_child_by_attribute_w</code> to simplify parsing code in some cases (i.e. COLLADA files)</p>\n</li>\n<li>\n<p>Added file offset information querying for debugging purposes (now you&#8217;re able to determine exact location of any <code>xml_node</code> in parsed file, see <code>xml_node::offset_debug</code> for details)</p>\n</li>\n<li>\n<p>Improved error handling for parsing - now <code>load()</code>, <code>load_file()</code> and <code>parse()</code> return <code>xml_parse_result</code>, which contains error code and last parsed offset; this does not break old interface as <code>xml_parse_result</code> can be implicitly casted to <code>bool</code>.</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.34\"><a class=\"anchor\" href=\"#v0.34\"></a><a class=\"link\" href=\"#v0.34\">v0.34 <sup>2007-10-31</sup></a></h3>\n<div class=\"paragraph\">\n<p>Maintenance release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed bug with loading from text-mode iostreams</p>\n</li>\n<li>\n<p>Fixed leak when <code>transfer_ownership</code> is true and parsing is failing</p>\n</li>\n<li>\n<p>Fixed bug in saving (<code>\\r</code> and <code>\\n</code> are now escaped in attribute values)</p>\n</li>\n<li>\n<p>Renamed <code>free()</code> to <code>destroy()</code> - some macro conflicts were reported</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Improved compatibility (supported Digital Mars C&#43;&#43;, MSVC 6, CodeWarrior 8, PGI C&#43;&#43;, Comeau, supported PS3 and XBox360)</p>\n</li>\n<li>\n<p><code>PUGIXML_NO_EXCEPTION</code> flag for platforms without exception handling</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.3\"><a class=\"anchor\" href=\"#v0.3\"></a><a class=\"link\" href=\"#v0.3\">v0.3 <sup>2007-02-21</sup></a></h3>\n<div class=\"paragraph\">\n<p>Refactored, reworked and improved version. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Interface:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Added XPath</p>\n</li>\n<li>\n<p>Added tree modification functions</p>\n</li>\n<li>\n<p>Added no STL compilation mode</p>\n</li>\n<li>\n<p>Added saving document to file</p>\n</li>\n<li>\n<p>Refactored parsing flags</p>\n</li>\n<li>\n<p>Removed <code>xml_parser</code> class in favor of <code>xml_document</code></p>\n</li>\n<li>\n<p>Added transfer ownership parsing mode</p>\n</li>\n<li>\n<p>Modified the way <code>xml_tree_walker</code> works</p>\n</li>\n<li>\n<p>Iterators are now non-constant</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>Implementation:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Support of several compilers and platforms</p>\n</li>\n<li>\n<p>Refactored and sped up parsing core</p>\n</li>\n<li>\n<p>Improved standard compliancy</p>\n</li>\n<li>\n<p>Added XPath implementation</p>\n</li>\n<li>\n<p>Fixed several bugs</p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.2\"><a class=\"anchor\" href=\"#v0.2\"></a><a class=\"link\" href=\"#v0.2\">v0.2 <sup>2006-11-06</sup></a></h3>\n<div class=\"paragraph\">\n<p>First public release. Changes:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Bug fixes:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Fixed <code>child_value()</code> (for empty nodes)</p>\n</li>\n<li>\n<p>Fixed <code>xml_parser_impl</code> warning at W4</p>\n</li>\n</ol>\n</div>\n</li>\n<li>\n<p>New features:</p>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p>Introduced <code>child_value(name)</code> and <code>child_value_w(name)</code></p>\n</li>\n<li>\n<p><code>parse_eol_pcdata</code> and <code>parse_eol_attribute</code> flags + <code>parse_minimal</code> optimizations</p>\n</li>\n<li>\n<p>Optimizations of <code>strconv_t</code></p>\n</li>\n</ol>\n</div>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"v0.1\"><a class=\"anchor\" href=\"#v0.1\"></a><a class=\"link\" href=\"#v0.1\">v0.1 <sup>2006-07-15</sup></a></h3>\n<div class=\"paragraph\">\n<p>First private release for testing purposes</p>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"apiref\"><a class=\"anchor\" href=\"#apiref\"></a><a class=\"link\" href=\"#apiref\">10. API Reference</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>This is the reference for all macros, types, enumerations, classes and functions in pugixml. Each symbol is a link that leads to the relevant section of the manual.</p>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.macros\"><a class=\"anchor\" href=\"#apiref.macros\"></a><a class=\"link\" href=\"#apiref.macros\">10.1. Macros</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-cp\">#define <a href=\"#PUGIXML_WCHAR_MODE\">PUGIXML_WCHAR_MODE</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_COMPACT\">PUGIXML_COMPACT</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_NO_XPATH\">PUGIXML_NO_XPATH</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_NO_STL\">PUGIXML_NO_STL</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_NO_EXCEPTIONS\">PUGIXML_NO_EXCEPTIONS</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_API\">PUGIXML_API</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_CLASS\">PUGIXML_CLASS</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_FUNCTION\">PUGIXML_FUNCTION</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_MEMORY_PAGE_SIZE\">PUGIXML_MEMORY_PAGE_SIZE</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_MEMORY_OUTPUT_STACK\">PUGIXML_MEMORY_OUTPUT_STACK</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_MEMORY_XPATH_PAGE_SIZE\">PUGIXML_MEMORY_XPATH_PAGE_SIZE</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_HEADER_ONLY\">PUGIXML_HEADER_ONLY</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_HAS_LONG_LONG\">PUGIXML_HAS_LONG_LONG</a></span>\n<span class=\"tok-cp\">#define <a href=\"#PUGIXML_HAS_STRING_VIEW\">PUGIXML_HAS_STRING_VIEW</a></span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.types\"><a class=\"anchor\" href=\"#apiref.types\"></a><a class=\"link\" href=\"#apiref.types\">10.2. Types</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">configuration</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#char_t\">char_t</a><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">configuration</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#string_t\">string_t</a><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">configuration</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#string_view_t\">string_view_t</a><span class=\"tok-p\">;</span>\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">*</span><a href=\"#allocation_function\">allocation_function</a><span class=\"tok-p\">)(</span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-o\">*</span><a href=\"#deallocation_function\">deallocation_function</a><span class=\"tok-p\">)(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ptr</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.enums\"><a class=\"anchor\" href=\"#apiref.enums\"></a><a class=\"link\" href=\"#apiref.enums\">10.3. Enumerations</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><a href=\"#xml_node_type\">xml_node_type</a>\n<span class=\"tok-w\">    </span><a href=\"#node_null\">node_null</a>\n<span class=\"tok-w\">    </span><a href=\"#node_document\">node_document</a>\n<span class=\"tok-w\">    </span><a href=\"#node_element\">node_element</a>\n<span class=\"tok-w\">    </span><a href=\"#node_pcdata\">node_pcdata</a>\n<span class=\"tok-w\">    </span><a href=\"#node_cdata\">node_cdata</a>\n<span class=\"tok-w\">    </span><a href=\"#node_comment\">node_comment</a>\n<span class=\"tok-w\">    </span><a href=\"#node_pi\">node_pi</a>\n<span class=\"tok-w\">    </span><a href=\"#node_declaration\">node_declaration</a>\n<span class=\"tok-w\">    </span><a href=\"#node_doctype\">node_doctype</a>\n\n<span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_status\">xml_parse_status</a>\n<span class=\"tok-w\">    </span><a href=\"#status_ok\">status_ok</a>\n<span class=\"tok-w\">    </span><a href=\"#status_file_not_found\">status_file_not_found</a>\n<span class=\"tok-w\">    </span><a href=\"#status_io_error\">status_io_error</a>\n<span class=\"tok-w\">    </span><a href=\"#status_out_of_memory\">status_out_of_memory</a>\n<span class=\"tok-w\">    </span><a href=\"#status_internal_error\">status_internal_error</a>\n<span class=\"tok-w\">    </span><a href=\"#status_unrecognized_tag\">status_unrecognized_tag</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_pi\">status_bad_pi</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_comment\">status_bad_comment</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_cdata\">status_bad_cdata</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_doctype\">status_bad_doctype</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_pcdata\">status_bad_pcdata</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_start_element\">status_bad_start_element</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_attribute\">status_bad_attribute</a>\n<span class=\"tok-w\">    </span><a href=\"#status_bad_end_element\">status_bad_end_element</a>\n<span class=\"tok-w\">    </span><a href=\"#status_end_element_mismatch\">status_end_element_mismatch</a>\n<span class=\"tok-w\">    </span><a href=\"#status_append_invalid_root\">status_append_invalid_root</a>\n<span class=\"tok-w\">    </span><a href=\"#status_no_document_element\">status_no_document_element</a>\n\n<span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><a href=\"#xml_encoding\">xml_encoding</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_auto\">encoding_auto</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf8\">encoding_utf8</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf16_le\">encoding_utf16_le</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf16_be\">encoding_utf16_be</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf16\">encoding_utf16</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf32_le\">encoding_utf32_le</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf32_be\">encoding_utf32_be</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_utf32\">encoding_utf32</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_wchar\">encoding_wchar</a>\n<span class=\"tok-w\">    </span><a href=\"#encoding_latin1\">encoding_latin1</a>\n\n<span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><a href=\"#xpath_value_type\">xpath_value_type</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_type_none\">xpath_type_none</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_type_node_set\">xpath_type_node_set</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_type_number\">xpath_type_number</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_type_string\">xpath_type_string</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_type_boolean\">xpath_type_boolean</a></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.constants\"><a class=\"anchor\" href=\"#apiref.constants\"></a><a class=\"link\" href=\"#apiref.constants\">10.4. Constants</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// Formatting options bit flags:</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_attribute_single_quote\">format_attribute_single_quote</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_default\">format_default</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_indent\">format_indent</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_indent_attributes\">format_indent_attributes</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_no_declaration\">format_no_declaration</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_no_empty_element_tags\">format_no_empty_element_tags</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_no_escapes\">format_no_escapes</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_raw\">format_raw</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_save_file_text\">format_save_file_text</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_skip_control_chars\">format_skip_control_chars</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#format_write_bom\">format_write_bom</a>\n\n<span class=\"tok-c1\">// Parsing options bit flags:</span>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_cdata\">parse_cdata</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_comments\">parse_comments</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_declaration\">parse_declaration</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_default\">parse_default</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_doctype\">parse_doctype</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_eol\">parse_eol</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_escapes\">parse_escapes</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_fragment\">parse_fragment</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_full\">parse_full</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_minimal\">parse_minimal</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_pi\">parse_pi</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_trim_pcdata\">parse_trim_pcdata</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_ws_pcdata\">parse_ws_pcdata</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_ws_pcdata_single\">parse_ws_pcdata_single</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_embed_pcdata\">parse_embed_pcdata</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_merge_pcdata\">parse_merge_pcdata</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_wconv_attribute\">parse_wconv_attribute</a>\n<span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#parse_wnorm_attribute\">parse_wnorm_attribute</a></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.classes\"><a class=\"anchor\" href=\"#apiref.classes\"></a><a class=\"link\" href=\"#apiref.classes\">10.5. Classes</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">class</span> <a href=\"#xml_attribute\">xml_attribute</a>\n<span class=\"tok-w\">    </span><a href=\"#xml_attribute::ctor\">xml_attribute</a><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::empty\">empty</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::unspecified_bool_type\">unspecified_bool_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator==</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator!=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator&lt;</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator&gt;</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator&lt;=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::comparison\">operator&gt;=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::hash_value\">hash_value</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::next_attribute\">next_attribute</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::previous_attribute\">previous_attribute</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::name\">name</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::value\">value</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_string\">as_string</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_int\">as_int</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_uint\">as_uint</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_double\">as_double</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_float\">as_float</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_bool\">as_bool</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_llong\">as_llong</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::as_ullong\">as_ullong</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-n\">unsnigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_node\">xml_node</a>\n<span class=\"tok-w\">    </span><a href=\"#xml_node::ctor\">xml_node</a><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::empty\">empty</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xml_node::unspecified_bool_type\">unspecified_bool_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator==</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator!=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator&lt;</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator&gt;</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator&lt;=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::comparison\">operator&gt;=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">r</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><a href=\"#xml_node::hash_value\">hash_value</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><a href=\"#xml_node::type\">type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_node::name\">name</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_node::value\">value</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::parent\">parent</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::first_child\">first_child</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::last_child\">last_child</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::next_sibling\">next_sibling</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::previous_sibling\">previous_sibling</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::first_attribute\">first_attribute</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::last_attribute\">last_attribute</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">implementation</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#xml_node::children\">children</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">implementation</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#xml_node::children\">children</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">implementation</span><span class=\"tok-o\">-</span><span class=\"tok-n\">defined</span><span class=\"tok-o\">-</span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attributes\">attributes</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::child\">child</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::child\">child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attribute\">attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attribute\">attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::next_sibling_name\">next_sibling</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::next_sibling_name\">next_sibling</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::previous_sibling_name\">previous_sibling</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::previous_sibling_name\">previous_sibling</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attribute_hinted\">attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attribute_hinted\">attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">hint</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::find_child_by_attribute\">find_child_by_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_value</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::find_child_by_attribute\">find_child_by_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr_value</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_node::child_value\">child_value</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_node::child_value\">child_value</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-w\"> </span><a href=\"#xml_node::text\">text</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node_iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_node_iterator\">iterator</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_node::begin\">begin</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_node::end\">end</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute_iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_attribute_iterator\">attribute_iterator</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">attribute_iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attributes_begin\">attributes_begin</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">attribute_iterator</span><span class=\"tok-w\"> </span><a href=\"#xml_node::attributes_end\">attributes_end</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::traverse\">traverse</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_tree_walker</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">walker</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::find_attribute\">find_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::find_child\">find_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">template</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">typename</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">Predicate</span><span class=\"tok-o\">&gt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::find_node\">find_node</a><span class=\"tok-p\">(</span><span class=\"tok-n\">Predicate</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pred</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">string_t</span><span class=\"tok-w\"> </span><a href=\"#xml_node::path\">path</a><span class=\"tok-p\">(</span><span class=\"tok-n\">char_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">delimiter</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-sc\">&#39;/&#39;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::first_element_by_path\">xml_node::first_element_by_path</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">delimiter</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-sc\">&#39;/&#39;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::root\">root</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><a href=\"#xml_node::offset_debug\">offset_debug</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_name\">set_name</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::set_value\">set_value</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_attribute\">append_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_attribute\">append_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_attribute\">prepend_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_attribute\">prepend_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_attribute_after\">insert_attribute_after</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_attribute_after\">insert_attribute_after</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_attribute_before\">insert_attribute_before</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_attribute_before\">insert_attribute_before</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_child\">append_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_element</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_child\">prepend_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_element</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_after\">insert_child_after</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_before\">insert_child_before</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_child\">append_child</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_child\">append_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_child\">prepend_child</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_child\">prepend_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_after\">insert_child_after</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_after\">insert_child_after</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_before\">insert_child_before</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_child_before\">insert_child_before</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_copy\">append_copy</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_copy\">prepend_copy</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_copy_after\">insert_copy_after</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_copy_before\">insert_copy_before</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_copy\">append_copy</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_copy\">prepend_copy</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_copy_after\">insert_copy_after</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_copy_before\">insert_copy_before</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_move\">append_move</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::prepend_move\">prepend_move</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_move_after\">insert_move_after</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::insert_move_before\">insert_move_before</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">moved</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_attribute\">remove_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">a</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_attribute\">remove_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_attribute\">remove_attribute</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_attributes\">remove_attributes</a><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_child\">remove_child</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_child\">remove_child</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_child\">remove_child</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_node::remove_children\">remove_children</a><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_node::append_buffer\">append_buffer</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_node::print\">print</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_writer</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">writer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_node::print_stream\">print</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">os</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_node::print_stream\">print</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">os</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::select_node\">select_node</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><a href=\"#xml_node::select_node_precomp\">select_node</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><a href=\"#xml_node::select_nodes\">select_nodes</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><a href=\"#xml_node::select_nodes_precomp\">select_nodes</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_query</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_document\">xml_document</a>\n<span class=\"tok-w\">    </span><a href=\"#xml_document::ctor\">xml_document</a><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-o\">~</span><a href=\"#xml_document::dtor\">xml_document</a><span class=\"tok-p\">();</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_document::reset\">reset</a><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_document::reset\">reset</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_document</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">proto</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_stream\">load</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">istream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_stream\">load</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wistream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_string\">load_string</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_file\">load_file</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_file_wide\">load_file</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_buffer\">load_buffer</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_buffer_inplace\">load_buffer_inplace</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><a href=\"#xml_document::load_buffer_inplace_own\">load_buffer_inplace_own</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">contents</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">options</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parse_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_document::save_file\">save_file</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_document::save_file_wide\">save_file</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">path</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_document::save_stream\">save</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_document::save_stream\">save</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_document::save\">save</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_writer</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">writer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">indent</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\t</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">flags</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">format_default</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">encoding_auto</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_document::document_element\">document_element</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">struct</span> <a href=\"#xml_parse_result\">xml_parse_result</a>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_parse_status</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_result::status\">status</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_result::offset\">offset</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_encoding</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_result::encoding\">encoding</a><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_result::bool\">bool</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_parse_result::description\">description</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_node_iterator\">xml_node_iterator</a>\n<span class=\"tok-k\">class</span> <a href=\"#xml_attribute_iterator\">xml_attribute_iterator</a>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_tree_walker\">xml_tree_walker</a>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_tree_walker::begin\">begin</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_tree_walker::for_each\">for_each</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_tree_walker::end\">end</a><span class=\"tok-p\">(</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#xml_tree_walker::depth\">depth</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_text\">xml_text</a>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::empty\">empty</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xml_text::unspecified_bool_type\">xml_text::unspecified_bool_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_text::get\">xml_text::get</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_string\">as_string</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_int\">as_int</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_uint\">as_uint</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_double\">as_double</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_float\">as_float</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_bool\">as_bool</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_llong\">as_llong</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><a href=\"#xml_text::as_ullong\">as_ullong</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">def</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xml_text::set_value\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-n\">string_view_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">float</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_text</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xml_text::assign\">operator=</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">unsigned</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">long</span><span class=\"tok-w\"> </span><span class=\"tok-n\">rhs</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xml_text::data\">data</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_writer\">xml_writer</a>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xml_writer::write\">write</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">data</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_writer_file\">xml_writer_file</a><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-k\">public</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_writer</span>\n<span class=\"tok-w\">    </span><a href=\"#xml_writer_file\">xml_writer_file</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">file</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xml_writer_stream\">xml_writer_stream</a><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-k\">public</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_writer</span>\n<span class=\"tok-w\">    </span><a href=\"#xml_writer_stream\">xml_writer_stream</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><a href=\"#xml_writer_stream\">xml_writer_stream</a><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wostream</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">struct</span> <a href=\"#xpath_parse_result\">xpath_parse_result</a>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_parse_result::error\">error</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">ptrdiff_t</span><span class=\"tok-w\"> </span><a href=\"#xpath_parse_result::offset\">offset</a><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xpath_parse_result::bool\">bool</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_parse_result::description\">description</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_query\">xpath_query</a>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">explicit</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::ctor\">xpath_query</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">query</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable_set</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">variables</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_boolean\">evaluate_boolean</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_number\">evaluate_number</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">string_t</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_string\">evaluate_string</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_string_buffer\">evaluate_string</a><span class=\"tok-p\">(</span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">capacity</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_node_set\">evaluate_node_set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::evaluate_node\">evaluate_node</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::return_type\">return_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_parse_result</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::result\">result</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xpath_query::unspecified_bool_type\">unspecified_bool_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_exception\">xpath_exception</a><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-k\">public</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">exception</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_exception::what\">what</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-k\">noexcept</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_parse_result</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xpath_exception::result\">result</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_node\">xpath_node</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_node::ctor\">xpath_node</a><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><a href=\"#xpath_node::ctor\">xpath_node</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><a href=\"#xpath_node::ctor\">xpath_node</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">parent</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::node\">node</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::attribute\">attribute</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::parent\">parent</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">operator</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::unspecified_bool_type\">unspecified_bool_type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::comparison\">operator==</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_node::comparison\">operator!=</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">n</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_node_set\">xpath_node_set</a>\n<span class=\"tok-w\">    </span><a href=\"#xpath_node_set::ctor\">xpath_node_set</a><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><a href=\"#xpath_node_set::ctor\">xpath_node_set</a><span class=\"tok-p\">(</span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">begin</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">end</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type_unsorted</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">typedef</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::const_iterator\">const_iterator</a><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::begin\">begin</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::end\">end</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::index\">operator[</a><span class=\"tok-p\">](</span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">index</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::size\">size</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::empty\">empty</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::first\">first</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">enum</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">type_t</span><span class=\"tok-w\"> </span><span class=\"tok-p\">{</span><a href=\"#xpath_node_set::type_unsorted\">type_unsorted</a><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::type_sorted\">type_sorted</a><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::type_sorted_reverse\">type_sorted_reverse</a><span class=\"tok-p\">};</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">type_t</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::type\">type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#xpath_node_set::sort\">sort</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">reverse</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">false</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_variable\">xpath_variable</a>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::name\">name</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::type\">type</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::get_boolean\">get_boolean</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::get_number\">get_number</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::get_string\">get_string</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::get_node_set\">get_node_set</a><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">class</span> <a href=\"#xpath_variable_set\">xpath_variable_set</a>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::add\">add</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_value_type</span><span class=\"tok-w\"> </span><span class=\"tok-n\">type</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">double</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::set\">set</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">value</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::get\">get</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">xpath_variable</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><a href=\"#xpath_variable_set::get\">get</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">char_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">name</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-k\">const</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"apiref.functions\"><a class=\"anchor\" href=\"#apiref.functions\"></a><a class=\"link\" href=\"#apiref.functions\">10.6. Functions</a></h3>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><a href=\"#as_utf8\">as_utf8</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">wchar_t</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><a href=\"#as_utf8\">as_utf8</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-w\"> </span><a href=\"#as_wide\">as_wide</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">wstring</span><span class=\"tok-w\"> </span><a href=\"#as_wide\">as_wide</a><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">str</span><span class=\"tok-p\">);</span>\n<span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><a href=\"#set_memory_management_functions\">set_memory_management_functions</a><span class=\"tok-p\">(</span><span class=\"tok-n\">allocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-n\">allocate</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">deallocation_function</span><span class=\"tok-w\"> </span><span class=\"tok-n\">deallocate</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">allocation_function</span><span class=\"tok-w\"> </span><a href=\"#get_memory_allocation_function\">get_memory_allocation_function</a><span class=\"tok-p\">();</span>\n<span class=\"tok-n\">deallocation_function</span><span class=\"tok-w\"> </span><a href=\"#get_memory_deallocation_function\">get_memory_deallocation_function</a><span class=\"tok-p\">();</span></code></pre>\n</div>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div id=\"footnotes\">\n<hr>\n<div class=\"footnote\" id=\"_footnotedef_1\">\n<a href=\"#_footnoteref_1\">1</a>. All trademarks used are properties of their respective owners.\n</div>\n</div>\n<div id=\"footer\">\n<div id=\"footer-text\">\nLast updated 2025-01-10 08:48:45 -0800\n</div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "external/pugixml/docs/quickstart.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta name=\"generator\" content=\"Asciidoctor 2.0.20\">\n<meta name=\"author\" content=\"website, repository\">\n<title>pugixml 1.14 quick start guide</title>\n<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700\">\n<style>\n/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */\n/* Uncomment the following line when using as a custom stylesheet */\n/* @import \"https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700\"; */\nhtml{font-family:sans-serif;-webkit-text-size-adjust:100%}\na{background:none}\na:focus{outline:thin dotted}\na:active,a:hover{outline:0}\nh1{font-size:2em;margin:.67em 0}\nb,strong{font-weight:bold}\nabbr{font-size:.9em}\nabbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}\ndfn{font-style:italic}\nhr{height:0}\nmark{background:#ff0;color:#000}\ncode,kbd,pre,samp{font-family:monospace;font-size:1em}\npre{white-space:pre-wrap}\nq{quotes:\"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\"}\nsmall{font-size:80%}\nsub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}\nsup{top:-.5em}\nsub{bottom:-.25em}\nimg{border:0}\nsvg:not(:root){overflow:hidden}\nfigure{margin:0}\naudio,video{display:inline-block}\naudio:not([controls]){display:none;height:0}\nfieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}\nlegend{border:0;padding:0}\nbutton,input,select,textarea{font-family:inherit;font-size:100%;margin:0}\nbutton,input{line-height:normal}\nbutton,select{text-transform:none}\nbutton,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}\nbutton[disabled],html input[disabled]{cursor:default}\ninput[type=checkbox],input[type=radio]{padding:0}\nbutton::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}\ntextarea{overflow:auto;vertical-align:top}\ntable{border-collapse:collapse;border-spacing:0}\n*,::before,::after{box-sizing:border-box}\nhtml,body{font-size:100%}\nbody{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:\"Noto Serif\",\"DejaVu Serif\",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}\na:hover{cursor:pointer}\nimg,object,embed{max-width:100%;height:auto}\nobject,embed{height:100%}\nimg{-ms-interpolation-mode:bicubic}\n.left{float:left!important}\n.right{float:right!important}\n.text-left{text-align:left!important}\n.text-right{text-align:right!important}\n.text-center{text-align:center!important}\n.text-justify{text-align:justify!important}\n.hide{display:none}\nimg,object,svg{display:inline-block;vertical-align:middle}\ntextarea{height:auto;min-height:50px}\nselect{width:100%}\n.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}\ndiv,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}\na{color:#2156a5;text-decoration:underline;line-height:inherit}\na:hover,a:focus{color:#1d4b8f}\na img{border:0}\np{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}\np aside{font-size:.875em;line-height:1.35;font-style:italic}\nh1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}\nh1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}\nh1{font-size:2.125em}\nh2{font-size:1.6875em}\nh3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}\nh4,h5{font-size:1.125em}\nh6{font-size:1em}\nhr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}\nem,i{font-style:italic;line-height:inherit}\nstrong,b{font-weight:bold;line-height:inherit}\nsmall{font-size:60%;line-height:inherit}\ncode{font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;font-weight:400;color:rgba(0,0,0,.9)}\nul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}\nul,ol{margin-left:1.5em}\nul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}\nul.circle{list-style-type:circle}\nul.disc{list-style-type:disc}\nul.square{list-style-type:square}\nul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit}\nol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}\ndl dt{margin-bottom:.3125em;font-weight:bold}\ndl dd{margin-bottom:1.25em}\nblockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}\nblockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}\n@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}\nh1{font-size:2.75em}\nh2{font-size:2.3125em}\nh3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}\nh4{font-size:1.4375em}}\ntable{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}\ntable thead,table tfoot{background:#f7f8f7}\ntable thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}\ntable tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}\ntable tr.even,table tr.alt{background:#f8f8f7}\ntable thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}\nh1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}\nh1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}\n.center{margin-left:auto;margin-right:auto}\n.stretch{width:100%}\n.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:\" \";display:table}\n.clearfix::after,.float-group::after{clear:both}\n:not(pre).nobreak{word-wrap:normal}\n:not(pre).nowrap{white-space:nowrap}\n:not(pre).pre-wrap{white-space:pre-wrap}\n:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}\npre{color:rgba(0,0,0,.9);font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;line-height:1.45;text-rendering:optimizeSpeed}\npre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}\npre>code{display:block}\npre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}\nem em{font-style:normal}\nstrong strong{font-weight:400}\n.keyseq{color:rgba(51,51,51,.8)}\nkbd{font-family:\"Droid Sans Mono\",\"DejaVu Sans Mono\",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}\n.keyseq kbd:first-child{margin-left:0}\n.keyseq kbd:last-child{margin-right:0}\n.menuseq,.menuref{color:#000}\n.menuseq b:not(.caret),.menuref{font-weight:inherit}\n.menuseq{word-spacing:-.02em}\n.menuseq b.caret{font-size:1.25em;line-height:.8}\n.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}\nb.button::before,b.button::after{position:relative;top:-1px;font-weight:400}\nb.button::before{content:\"[\";padding:0 3px 0 2px}\nb.button::after{content:\"]\";padding:0 2px 0 3px}\np a>code:hover{color:rgba(0,0,0,.9)}\n#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}\n#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:\" \";display:table}\n#header::after,#content::after,#footnotes::after,#footer::after{clear:both}\n#content{margin-top:1.25em}\n#content::before{content:none}\n#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}\n#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}\n#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}\n#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}\n#header .details span:first-child{margin-left:-.125em}\n#header .details span.email a{color:rgba(0,0,0,.85)}\n#header .details br{display:none}\n#header .details br+span::before{content:\"\\00a0\\2013\\00a0\"}\n#header .details br+span.author::before{content:\"\\00a0\\22c5\\00a0\";color:rgba(0,0,0,.85)}\n#header .details br+span#revremark::before{content:\"\\00a0|\\00a0\"}\n#header #revnumber{text-transform:capitalize}\n#header #revnumber::after{content:\"\\00a0\"}\n#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}\n#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}\n#toc>ul{margin-left:.125em}\n#toc ul.sectlevel0>li>a{font-style:italic}\n#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}\n#toc ul{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;list-style-type:none}\n#toc li{line-height:1.3334;margin-top:.3334em}\n#toc a{text-decoration:none}\n#toc a:active{text-decoration:underline}\n#toctitle{color:#7a2518;font-size:1.2em}\n@media screen and (min-width:768px){#toctitle{font-size:1.375em}\nbody.toc2{padding-left:15em;padding-right:0}\n#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}\n#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}\n#toc.toc2>ul{font-size:.9em;margin-bottom:0}\n#toc.toc2 ul ul{margin-left:0;padding-left:1em}\n#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}\nbody.toc2.toc-right{padding-left:0;padding-right:15em}\nbody.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}\n@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}\n#toc.toc2{width:20em}\n#toc.toc2 #toctitle{font-size:1.375em}\n#toc.toc2>ul{font-size:.95em}\n#toc.toc2 ul ul{padding-left:1.25em}\nbody.toc2.toc-right{padding-left:0;padding-right:20em}}\n#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}\n#content #toc>:first-child{margin-top:0}\n#content #toc>:last-child{margin-bottom:0}\n#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}\n#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}\n#content{margin-bottom:.625em}\n.sect1{padding-bottom:.625em}\n@media screen and (min-width:768px){#content{margin-bottom:1.25em}\n.sect1{padding-bottom:1.25em}}\n.sect1:last-child{padding-bottom:0}\n.sect1+.sect1{border-top:1px solid #e7e7e9}\n#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}\n#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:\"\\00A7\";font-size:.85em;display:block;padding-top:.1em}\n#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}\n#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}\n#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}\ndetails,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}\ndetails{margin-left:1.25rem}\ndetails>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}\ndetails>summary::-webkit-details-marker{display:none}\ndetails>summary::before{content:\"\";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}\ndetails[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}\ndetails>summary::after{content:\"\";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}\n.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:\"Noto Serif\",\"DejaVu Serif\",serif;font-size:1rem;font-style:italic}\ntable.tableblock.fit-content>caption.title{white-space:nowrap;width:0}\n.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}\n.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}\n.admonitionblock>table td.icon{text-align:center;width:80px}\n.admonitionblock>table td.icon img{max-width:none}\n.admonitionblock>table td.icon .title{font-weight:bold;font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;text-transform:uppercase}\n.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}\n.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}\n.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}\n.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}\n.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}\n.exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0}\n.exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}\n.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}\n@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}\n@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}\n.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^=\"highlight \"]{background:#f7f7f8}\n.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}\n.listingblock>.content{position:relative}\n.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}\n.listingblock:hover code[data-lang]::before{display:block}\n.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}\n.listingblock.terminal pre .command:not([data-prompt])::before{content:\"$\"}\n.listingblock pre.highlightjs{padding:0}\n.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}\n.listingblock pre.prettyprint{border-width:0}\n.prettyprint{background:#f7f7f8}\npre.prettyprint .linenums{line-height:1.45;margin-left:2em}\npre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}\npre.prettyprint li code[data-lang]::before{opacity:1}\npre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}\ntable.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}\ntable.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}\ntable.linenotable td.code{padding-left:.75em}\ntable.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}\npre.pygments span.linenos{display:inline-block;margin-right:.75em}\n.quoteblock{margin:0 1em 1.25em 1.5em;display:table}\n.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}\n.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}\n.quoteblock blockquote{margin:0;padding:0;border:0}\n.quoteblock blockquote::before{content:\"\\201c\";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}\n.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}\n.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}\n.verseblock{margin:0 1em 1.25em}\n.verseblock pre{font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}\n.verseblock pre strong{font-weight:400}\n.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}\n.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}\n.quoteblock .attribution br,.verseblock .attribution br{display:none}\n.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}\n.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}\n.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}\n.quoteblock.abstract{margin:0 1em 1.25em;display:block}\n.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}\n.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}\n.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}\n.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}\n.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}\np.tableblock:last-child{margin-bottom:0}\ntd.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}\ntd.tableblock>.content>:last-child{margin-bottom:-1.25em}\ntable.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}\ntable.grid-all>*>tr>*{border-width:1px}\ntable.grid-cols>*>tr>*{border-width:0 1px}\ntable.grid-rows>*>tr>*{border-width:1px 0}\ntable.frame-all{border-width:1px}\ntable.frame-ends{border-width:1px 0}\ntable.frame-sides{border-width:0 1px}\ntable.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}\ntable.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}\ntable.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}\ntable.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}\ntable.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}\nth.halign-left,td.halign-left{text-align:left}\nth.halign-right,td.halign-right{text-align:right}\nth.halign-center,td.halign-center{text-align:center}\nth.valign-top,td.valign-top{vertical-align:top}\nth.valign-bottom,td.valign-bottom{vertical-align:bottom}\nth.valign-middle,td.valign-middle{vertical-align:middle}\ntable thead th,table tfoot th{font-weight:bold}\ntbody tr th{background:#f7f8f7}\ntbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}\np.tableblock>code:only-child{background:none;padding:0}\np.tableblock{font-size:1em}\nol{margin-left:1.75em}\nul li ol{margin-left:1.5em}\ndl dd{margin-left:1.125em}\ndl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}\nli p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}\nul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}\nul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}\nul.unstyled,ol.unstyled{margin-left:0}\nli>p:empty:only-child::before{content:\"\";display:inline-block}\nul.checklist>li>p:first-child{margin-left:-1em}\nul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}\nul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}\nul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}\nul.inline>li{margin-left:1.25em}\n.unstyled dl dt{font-weight:400;font-style:normal}\nol.arabic{list-style-type:decimal}\nol.decimal{list-style-type:decimal-leading-zero}\nol.loweralpha{list-style-type:lower-alpha}\nol.upperalpha{list-style-type:upper-alpha}\nol.lowerroman{list-style-type:lower-roman}\nol.upperroman{list-style-type:upper-roman}\nol.lowergreek{list-style-type:lower-greek}\n.hdlist>table,.colist>table{border:0;background:none}\n.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}\ntd.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}\ntd.hdlist1{font-weight:bold;padding-bottom:1.25em}\ntd.hdlist2{word-wrap:anywhere}\n.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}\n.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}\n.colist td:not([class]):first-child img{max-width:none}\n.colist td:not([class]):last-child{padding:.25em 0}\n.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}\n.imageblock.left{margin:.25em .625em 1.25em 0}\n.imageblock.right{margin:.25em 0 1.25em .625em}\n.imageblock>.title{margin-bottom:0}\n.imageblock.thumb,.imageblock.th{border-width:6px}\n.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}\n.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}\n.image.left{margin-right:.625em}\n.image.right{margin-left:.625em}\na.image{text-decoration:none;display:inline-block}\na.image object{pointer-events:none}\nsup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}\nsup.footnote a,sup.footnoteref a{text-decoration:none}\nsup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}\n#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}\n#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}\n#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}\n#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}\n#footnotes .footnote:last-of-type{margin-bottom:0}\n#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}\ndiv.unbreakable{page-break-inside:avoid}\n.big{font-size:larger}\n.small{font-size:smaller}\n.underline{text-decoration:underline}\n.overline{text-decoration:overline}\n.line-through{text-decoration:line-through}\n.aqua{color:#00bfbf}\n.aqua-background{background:#00fafa}\n.black{color:#000}\n.black-background{background:#000}\n.blue{color:#0000bf}\n.blue-background{background:#0000fa}\n.fuchsia{color:#bf00bf}\n.fuchsia-background{background:#fa00fa}\n.gray{color:#606060}\n.gray-background{background:#7d7d7d}\n.green{color:#006000}\n.green-background{background:#007d00}\n.lime{color:#00bf00}\n.lime-background{background:#00fa00}\n.maroon{color:#600000}\n.maroon-background{background:#7d0000}\n.navy{color:#000060}\n.navy-background{background:#00007d}\n.olive{color:#606000}\n.olive-background{background:#7d7d00}\n.purple{color:#600060}\n.purple-background{background:#7d007d}\n.red{color:#bf0000}\n.red-background{background:#fa0000}\n.silver{color:#909090}\n.silver-background{background:#bcbcbc}\n.teal{color:#006060}\n.teal-background{background:#007d7d}\n.white{color:#bfbfbf}\n.white-background{background:#fafafa}\n.yellow{color:#bfbf00}\n.yellow-background{background:#fafa00}\nspan.icon>.fa{cursor:default}\na span.icon>.fa{cursor:inherit}\n.admonitionblock td.icon [class^=\"fa icon-\"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}\n.admonitionblock td.icon .icon-note::before{content:\"\\f05a\";color:#19407c}\n.admonitionblock td.icon .icon-tip::before{content:\"\\f0eb\";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}\n.admonitionblock td.icon .icon-warning::before{content:\"\\f071\";color:#bf6900}\n.admonitionblock td.icon .icon-caution::before{content:\"\\f06d\";color:#bf3400}\n.admonitionblock td.icon .icon-important::before{content:\"\\f06a\";color:#bf0000}\n.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:\"Open Sans\",\"DejaVu Sans\",sans-serif;font-style:normal;font-weight:bold}\n.conum[data-value] *{color:#fff!important}\n.conum[data-value]+b{display:none}\n.conum[data-value]::after{content:attr(data-value)}\npre .conum[data-value]{position:relative;top:-.125em}\nb.conum *{color:inherit!important}\n.conum:not([data-value]):empty{display:none}\ndt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}\nh1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}\np strong,td.content strong,div.footnote strong{letter-spacing:-.005em}\np,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem}\np{margin-bottom:1.25rem}\n.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}\n.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}\n.print-only{display:none!important}\n@page{margin:1.25cm .75cm}\n@media print{*{box-shadow:none!important;text-shadow:none!important}\nhtml{font-size:80%}\na{color:inherit!important;text-decoration:underline!important}\na.bare,a[href^=\"#\"],a[href^=\"mailto:\"]{text-decoration:none!important}\na[href^=\"http:\"]:not(.bare)::after,a[href^=\"https:\"]:not(.bare)::after{content:\"(\" attr(href) \")\";display:inline-block;font-size:.875em;padding-left:.25em}\nabbr[title]{border-bottom:1px dotted}\nabbr[title]::after{content:\" (\" attr(title) \")\"}\npre,blockquote,tr,img,object,svg{page-break-inside:avoid}\nthead{display:table-header-group}\nsvg{max-width:100%}\np,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}\nh2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}\n#header,#content,#footnotes,#footer{max-width:none}\n#toc,.sidebarblock,.exampleblock>.content{background:none!important}\n#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}\nbody.book #header{text-align:center}\nbody.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}\nbody.book #header .details{border:0!important;display:block;padding:0!important}\nbody.book #header .details span:first-child{margin-left:0!important}\nbody.book #header .details br{display:block}\nbody.book #header .details br+span::before{content:none!important}\nbody.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}\nbody.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}\n.listingblock code[data-lang]::before{display:block}\n#footer{padding:0 .9375em}\n.hide-on-print{display:none!important}\n.print-only{display:block!important}\n.hide-for-print{display:none!important}\n.show-for-print{display:inherit!important}}\n@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}\n.sect1{padding:0!important}\n.sect1+.sect1{border:0}\n#footer{background:none}\n#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}\n@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}\n</style>\n<style>\npre.pygments .hll { background-color: #ffffcc }\npre.pygments { background: #f8f8f8; }\npre.pygments .tok-c { color: #3D7B7B; font-style: italic } /* Comment */\npre.pygments .tok-err { border: 1px solid #FF0000 } /* Error */\npre.pygments .tok-k { color: #008000; font-weight: bold } /* Keyword */\npre.pygments .tok-o { color: #666666 } /* Operator */\npre.pygments .tok-ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\npre.pygments .tok-cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\npre.pygments .tok-cp { color: #9C6500 } /* Comment.Preproc */\npre.pygments .tok-cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\npre.pygments .tok-c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\npre.pygments .tok-cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\npre.pygments .tok-gd { color: #A00000 } /* Generic.Deleted */\npre.pygments .tok-ge { font-style: italic } /* Generic.Emph */\npre.pygments .tok-ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\npre.pygments .tok-gr { color: #E40000 } /* Generic.Error */\npre.pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */\npre.pygments .tok-gi { color: #008400 } /* Generic.Inserted */\npre.pygments .tok-go { color: #717171 } /* Generic.Output */\npre.pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */\npre.pygments .tok-gs { font-weight: bold } /* Generic.Strong */\npre.pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */\npre.pygments .tok-gt { color: #0044DD } /* Generic.Traceback */\npre.pygments .tok-kc { color: #008000; font-weight: bold } /* Keyword.Constant */\npre.pygments .tok-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\npre.pygments .tok-kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\npre.pygments .tok-kp { color: #008000 } /* Keyword.Pseudo */\npre.pygments .tok-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\npre.pygments .tok-kt { color: #B00040 } /* Keyword.Type */\npre.pygments .tok-m { color: #666666 } /* Literal.Number */\npre.pygments .tok-s { color: #BA2121 } /* Literal.String */\npre.pygments .tok-na { color: #687822 } /* Name.Attribute */\npre.pygments .tok-nb { color: #008000 } /* Name.Builtin */\npre.pygments .tok-nc { color: #0000FF; font-weight: bold } /* Name.Class */\npre.pygments .tok-no { color: #880000 } /* Name.Constant */\npre.pygments .tok-nd { color: #AA22FF } /* Name.Decorator */\npre.pygments .tok-ni { color: #717171; font-weight: bold } /* Name.Entity */\npre.pygments .tok-ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\npre.pygments .tok-nf { color: #0000FF } /* Name.Function */\npre.pygments .tok-nl { color: #767600 } /* Name.Label */\npre.pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\npre.pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */\npre.pygments .tok-nv { color: #19177C } /* Name.Variable */\npre.pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\npre.pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */\npre.pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */\npre.pygments .tok-mf { color: #666666 } /* Literal.Number.Float */\npre.pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */\npre.pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */\npre.pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */\npre.pygments .tok-sa { color: #BA2121 } /* Literal.String.Affix */\npre.pygments .tok-sb { color: #BA2121 } /* Literal.String.Backtick */\npre.pygments .tok-sc { color: #BA2121 } /* Literal.String.Char */\npre.pygments .tok-dl { color: #BA2121 } /* Literal.String.Delimiter */\npre.pygments .tok-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\npre.pygments .tok-s2 { color: #BA2121 } /* Literal.String.Double */\npre.pygments .tok-se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\npre.pygments .tok-sh { color: #BA2121 } /* Literal.String.Heredoc */\npre.pygments .tok-si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\npre.pygments .tok-sx { color: #008000 } /* Literal.String.Other */\npre.pygments .tok-sr { color: #A45A77 } /* Literal.String.Regex */\npre.pygments .tok-s1 { color: #BA2121 } /* Literal.String.Single */\npre.pygments .tok-ss { color: #19177C } /* Literal.String.Symbol */\npre.pygments .tok-bp { color: #008000 } /* Name.Builtin.Pseudo */\npre.pygments .tok-fm { color: #0000FF } /* Name.Function.Magic */\npre.pygments .tok-vc { color: #19177C } /* Name.Variable.Class */\npre.pygments .tok-vg { color: #19177C } /* Name.Variable.Global */\npre.pygments .tok-vi { color: #19177C } /* Name.Variable.Instance */\npre.pygments .tok-vm { color: #19177C } /* Name.Variable.Magic */\npre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */\n</style>\n</head>\n<body class=\"article toc2 toc-right\">\n<div id=\"header\">\n<h1>pugixml 1.14 quick start guide</h1>\n<div class=\"details\">\n<span id=\"author\" class=\"author\">website</span><br>\n<span id=\"email\" class=\"email\"><a href=\"https://pugixml.org\" class=\"bare\">https://pugixml.org</a></span><br>\n<span id=\"author2\" class=\"author\">repository</span><br>\n<span id=\"email2\" class=\"email\"><a href=\"https://github.com/zeux/pugixml\" class=\"bare\">https://github.com/zeux/pugixml</a></span><br>\n</div>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents</div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#introduction\">Introduction</a></li>\n<li><a href=\"#install\">Installation</a></li>\n<li><a href=\"#dom\">Document object model</a></li>\n<li><a href=\"#loading\">Loading document</a></li>\n<li><a href=\"#access\">Accessing document data</a></li>\n<li><a href=\"#modify\">Modifying document data</a></li>\n<li><a href=\"#saving\">Saving document</a></li>\n<li><a href=\"#feedback\">Feedback</a></li>\n<li><a href=\"#license\">License</a></li>\n</ul>\n</div>\n</div>\n<div id=\"content\">\n<div class=\"sect1\">\n<h2 id=\"introduction\"><a class=\"anchor\" href=\"#introduction\"></a><a class=\"link\" href=\"#introduction\">Introduction</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p><a href=\"https://pugixml.org/\">pugixml</a> is a light-weight C&#43;&#43; XML processing library. It consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with two Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving). The library is extremely portable and easy to integrate and use. pugixml is developed and maintained since 2006 and has many users. All code is distributed under the <a href=\"#license\">MIT license</a>, making it completely free to use in both open-source and proprietary applications.</p>\n</div>\n<div class=\"paragraph\">\n<p>pugixml enables very fast, convenient and memory-efficient XML document processing. However, since pugixml has a DOM parser, it can&#8217;t process XML documents that do not fit in memory; also the parser is a non-validating one, so if you need DTD/Schema validation, the library is not for you.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is the quick start guide for pugixml, which purpose is to enable you to start using the library quickly. Many important library features are either not described at all or only mentioned briefly; for more complete information you <a href=\"manual.html\">should read the complete manual</a>.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nNo documentation is perfect; neither is this one. If you find errors or omissions, please don’t hesitate to <a href=\"https://github.com/zeux/pugixml/issues/new\">submit an issue or open a pull request</a> with a fix.\n</td>\n</tr>\n</table>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"install\"><a class=\"anchor\" href=\"#install\"></a><a class=\"link\" href=\"#install\">Installation</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>You can download the latest source distribution as an archive:</p>\n</div>\n<div class=\"paragraph\">\n<p><a href=\"https://github.com/zeux/pugixml/releases/download/v1.14/pugixml-1.14.zip\">pugixml-1.14.zip</a> (Windows line endings)\n/\n<a href=\"https://github.com/zeux/pugixml/releases/download/v1.14/pugixml-1.14.tar.gz\">pugixml-1.14.tar.gz</a> (Unix line endings)</p>\n</div>\n<div class=\"paragraph\">\n<p>The distribution contains library source, documentation (the guide you&#8217;re reading now and the manual) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive.</p>\n</div>\n<div class=\"paragraph\">\n<p>The complete pugixml source consists of three files - one source file, <code>pugixml.cpp</code>, and two header files, <code>pugixml.hpp</code> and <code>pugiconfig.hpp</code>. <code>pugixml.hpp</code> is the primary header which you need to include in order to use pugixml classes/functions. The rest of this guide assumes that <code>pugixml.hpp</code> is either in the current directory or in one of include directories of your projects, so that <code>#include \"pugixml.hpp\"</code> can find the header; however you can also use relative path (i.e. <code>#include \"../libs/pugixml/src/pugixml.hpp\"</code>) or include directory-relative path (i.e. <code>#include &lt;xml/thirdparty/pugixml/src/pugixml.hpp&gt;</code>).</p>\n</div>\n<div class=\"paragraph\">\n<p>The easiest way to build pugixml is to compile the source file, <code>pugixml.cpp</code>, along with the existing library/executable. This process depends on the method of building your application; for example, if you&#8217;re using Microsoft Visual Studio <sup class=\"footnote\">[<a id=\"_footnoteref_1\" class=\"footnote\" href=\"#_footnotedef_1\" title=\"View footnote.\">1</a>]</sup>, Apple Xcode, Code::Blocks or any other IDE, just <strong>add <code>pugixml.cpp</code> to one of your projects</strong>. There are other building methods available, including building pugixml as a standalone static/shared library; <a href=\"manual.html#install.building\">read the manual</a> for further information.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"dom\"><a class=\"anchor\" href=\"#dom\"></a><a class=\"link\" href=\"#dom\">Document object model</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml stores XML data in DOM-like way: the entire XML document (both document structure and element data) is stored in memory as a tree. The tree can be loaded from character stream (file, string, C&#43;&#43; I/O stream), then traversed via special API or XPath expressions. The whole tree is mutable: both node structure and node/attribute data can be changed at any time. Finally, the result of document transformations can be saved to a character stream (file, C&#43;&#43; I/O stream or custom transport).</p>\n</div>\n<div class=\"paragraph\">\n<p>The root of the tree is the document itself, which corresponds to C&#43;&#43; type <code>xml_document</code>. Document has one or more child nodes, which correspond to C&#43;&#43; type <code>xml_node</code>. Nodes have different types; depending on a type, a node can have a collection of child nodes, a collection of attributes, which correspond to C&#43;&#43; type <code>xml_attribute</code>, and some additional data (i.e. name).</p>\n</div>\n<div class=\"paragraph\">\n<p>The most common node types are:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Document node (<code>node_document</code>) - this is the root of the tree, which consists of several child nodes. This node corresponds to <code>xml_document</code> class; note that <code>xml_document</code> is a sub-class of <code>xml_node</code>, so the entire node interface is also available.</p>\n</li>\n<li>\n<p>Element/tag node (<code>node_element</code>) - this is the most common type of node, which represents XML elements. Element nodes have a name, a collection of attributes and a collection of child nodes (both of which may be empty). The attribute is a simple name/value pair.</p>\n</li>\n<li>\n<p>Plain character data nodes (<code>node_pcdata</code>) represent plain text in XML. PCDATA nodes have a value, but do not have name or children/attributes. Note that <strong>plain character data is not a part of the element node but instead has its own node</strong>; for example, an element node can have several child PCDATA nodes.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>Despite the fact that there are several node types, there are only three C&#43;&#43; types representing the tree (<code>xml_document</code>, <code>xml_node</code>, <code>xml_attribute</code>); some operations on <code>xml_node</code> are only valid for certain node types. They are described below.</p>\n</div>\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nAll pugixml classes and functions are located in <code>pugi</code> namespace; you have to either use explicit name qualification (i.e. <code>pugi::xml_node</code>), or to gain access to relevant symbols via <code>using</code> directive (i.e. <code>using pugi::xml_node;</code> or <code>using namespace pugi;</code>).\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p><code>xml_document</code> is the owner of the entire document structure; destroying the document destroys the whole tree. The interface of <code>xml_document</code> consists of loading functions, saving functions and the entire interface of <code>xml_node</code>, which allows for document inspection and/or modification. Note that while <code>xml_document</code> is a sub-class of <code>xml_node</code>, <code>xml_node</code> is not a polymorphic type; the inheritance is present only to simplify usage.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>xml_node</code> is the handle to document node; it can point to any node in the document, including document itself. There is a common interface for nodes of all types. Note that <code>xml_node</code> is only a handle to the actual node, not the node itself - you can have several <code>xml_node</code> handles pointing to the same underlying object. Destroying <code>xml_node</code> handle does not destroy the node and does not remove it from the tree.</p>\n</div>\n<div class=\"paragraph\">\n<p>There is a special value of <code>xml_node</code> type, known as null node or empty node. It does not correspond to any node in any document, and thus resembles null pointer. However, all operations are defined on empty nodes; generally the operations don&#8217;t do anything and return empty nodes/attributes or empty strings as their result. This is useful for chaining calls; i.e. you can get the grandparent of a node like so: <code>node.parent().parent()</code>; if a node is a null node or it does not have a parent, the first <code>parent()</code> call returns null node; the second <code>parent()</code> call then also returns null node, so you don&#8217;t have to check for errors twice. You can test if a handle is null via implicit boolean cast: <code>if (node) { &#8230;&#8203; }</code> or <code>if (!node) { &#8230;&#8203; }</code>.</p>\n</div>\n<div class=\"paragraph\">\n<p><code>xml_attribute</code> is the handle to an XML attribute; it has the same semantics as <code>xml_node</code>, i.e. there can be several <code>xml_attribute</code> handles pointing to the same underlying object and there is a special null attribute value, which propagates to function results.</p>\n</div>\n<div class=\"paragraph\">\n<p>There are two choices of interface and internal representation when configuring pugixml: you can either choose the UTF-8 (also called char) interface or UTF-16/32 (also called wchar_t) one. The choice is controlled via <code>PUGIXML_WCHAR_MODE</code> define; you can set it via <code>pugiconfig.hpp</code> or via preprocessor options. All tree functions that work with strings work with either C-style null terminated strings or STL strings of the selected character type. <a href=\"manual.html#dom.unicode\">Read the manual</a> for additional information on Unicode interface.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"loading\"><a class=\"anchor\" href=\"#loading\"></a><a class=\"link\" href=\"#loading\">Loading document</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml provides several functions for loading XML data from various places - files, C&#43;&#43; iostreams, memory buffers. All functions use an extremely fast non-validating parser. This parser is not fully W3C conformant - it can load any valid XML document, but does not perform some well-formedness checks. While considerable effort is made to reject invalid XML documents, some validation is not performed because of performance reasons. XML data is always converted to internal character format before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it&#8217;s a strict subset of UTF-16) and handles all encoding conversions automatically.</p>\n</div>\n<div class=\"paragraph\">\n<p>The most common source of XML data is files; pugixml provides a separate function for loading XML document from file. This function accepts file path as its first argument, and also two optional arguments, which specify parsing options and input data encoding, which are described in the manual.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of loading XML document from file (<a href=\"samples/load_file.cpp\" class=\"bare\">samples/load_file.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_file</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;tree.xml&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Load result: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, mesh name: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;mesh&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p><code>load_file</code>, as well as other loading functions, destroys the existing document tree and then tries to load the new tree from the specified file. The result of the operation is returned in an <code>xml_parse_result</code> object; this object contains the operation status, and the related information (i.e. last successfully parsed position in the input file, if parsing fails).</p>\n</div>\n<div class=\"paragraph\">\n<p>Parsing result object can be implicitly converted to <code>bool</code>; if you do not want to handle parsing errors thoroughly, you can just check the return value of load functions as if it was a <code>bool</code>: <code>if (doc.load_file(\"file.xml\")) { &#8230;&#8203; } else { &#8230;&#8203; }</code>. Otherwise you can use the <code>status</code> member to get parsing status, or the <code>description()</code> member function to get the status in a string form.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of handling loading errors (<a href=\"samples/load_error_handling.cpp\" class=\"bare\">samples/load_error_handling.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_document</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_string</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">result</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;XML [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;] parsed without errors, attr value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;attr&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n<span class=\"tok-k\">else</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;XML [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;] parsed with errors, attr value: [&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;attr&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Error description: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">description</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Error offset: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">offset</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; (error at [...&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-w\"> </span><span class=\"tok-o\">+</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">offset</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;]</span><span class=\"tok-se\">\\n\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Sometimes XML data should be loaded from some other source than file, i.e. HTTP URL; also you may want to load XML data from file using non-standard functions, i.e. to use your virtual file system facilities or to load XML from gzip-compressed files. These scenarios either require loading document from memory, in which case you should prepare a contiguous memory block with all XML data and to pass it to one of buffer loading functions, or loading document from C&#43;&#43; IOstream, in which case you should provide an object which implements <code>std::istream</code> or <code>std::wistream</code> interface.</p>\n</div>\n<div class=\"paragraph\">\n<p>There are different functions for loading document from memory; they treat the passed buffer as either an immutable one (<code>load_buffer</code>), a mutable buffer which is owned by the caller (<code>load_buffer_inplace</code>), or a mutable buffer which ownership belongs to pugixml (<code>load_buffer_inplace_own</code>). There is also a simple helper function, <code>xml_document::load</code>, for cases when you want to load the XML document from null-terminated character string.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of loading XML document from memory using one of these functions (<a href=\"samples/load_memory.cpp\" class=\"bare\">samples/load_memory.cpp</a>); read the sample code for more examples:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-p\">[]</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&lt;mesh name=&#39;sphere&#39;&gt;&lt;bounds&gt;0 0 1 1&lt;/bounds&gt;&lt;/mesh&gt;&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-k\">sizeof</span><span class=\"tok-p\">(</span><span class=\"tok-n\">source</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// You can use load_buffer_inplace to load document from mutable memory block; the block&#39;s lifetime must exceed that of document</span>\n<span class=\"tok-kt\">char</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-k\">new</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-p\">[</span><span class=\"tok-n\">size</span><span class=\"tok-p\">];</span>\n<span class=\"tok-n\">memcpy</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">source</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// The block can be allocated by any method; the block is modified during parsing</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load_buffer_inplace</span><span class=\"tok-p\">(</span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// You have to destroy the block yourself after the document is no longer used</span>\n<span class=\"tok-k\">delete</span><span class=\"tok-p\">[]</span><span class=\"tok-w\"> </span><span class=\"tok-n\">buffer</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of loading XML document from file using streams (<a href=\"samples/load_stream.cpp\" class=\"bare\">samples/load_stream.cpp</a>); read the sample code for more complex examples involving wide streams and locales:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">ifstream</span><span class=\"tok-w\"> </span><span class=\"tok-n\">stream</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;weekly-utf-8.xml&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_parse_result</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">load</span><span class=\"tok-p\">(</span><span class=\"tok-n\">stream</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"access\"><a class=\"anchor\" href=\"#access\"></a><a class=\"link\" href=\"#access\">Accessing document data</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>pugixml features an extensive interface for getting various types of data from the document and for traversing the document. You can use various accessors to get node/attribute data, you can traverse the child node/attribute lists via accessors or iterators, you can do depth-first traversals with <code>xml_tree_walker</code> objects, and you can use XPath for complex data-driven queries.</p>\n</div>\n<div class=\"paragraph\">\n<p>You can get node or attribute name via <code>name()</code> accessor, and value via <code>value()</code> accessor. Note that both functions never return null pointers - they either return a string with the relevant content, or an empty string if name/value is absent or if the handle is null. Also there are two notable things for reading values:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>It is common to store data as text contents of some node - i.e. <code>&lt;node&gt;&lt;description&gt;This is a node&lt;/description&gt;&lt;/node&gt;</code>. In this case, <code>&lt;description&gt;</code> node does not have a value, but instead has a child of type <code>node_pcdata</code> with value <code>\"This is a node\"</code>. pugixml provides <code>child_value()</code> and <code>text()</code> helper functions to parse such data.</p>\n</li>\n<li>\n<p>In many cases attribute values have types that are not strings - i.e. an attribute may always contain values that should be treated as integers, despite the fact that they are represented as strings in XML. pugixml provides several accessors that convert attribute value to some other type.</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of using these functions (<a href=\"samples/traverse_base.cpp\" class=\"bare\">samples/traverse_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;: AllowRemote &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;AllowRemote&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_bool</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, Timeout &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Timeout&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">as_int</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, Description &#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Description&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Since a lot of document traversal consists of finding the node/attribute with the correct name, there are special functions for that purpose. For example, <code>child(\"Tool\")</code> returns the first node which has the name <code>\"Tool\"</code>, or null handle if there is no such node. This is an example of using such functions (<a href=\"samples/traverse_base.cpp\" class=\"bare\">samples/traverse_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool for *.dae generation: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">find_child_by_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;OutputFileMasks&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;*.dae&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">);</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">next_sibling</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Child node lists and attribute lists are simply double-linked lists; while you can use <code>previous_sibling</code>/<code>next_sibling</code> and other such functions for iteration, pugixml additionally provides node and attribute iterators, so that you can treat nodes as containers of other nodes or attributes. All iterators are bidirectional and support all usual iterator operations. The iterators are invalidated if the node/attribute objects they&#8217;re pointing to are removed from the tree; adding nodes/attributes does not invalidate any iterators.</p>\n</div>\n<div class=\"paragraph\">\n<p>Here is an example of using iterators for document traversal (<a href=\"samples/traverse_iter.cpp\" class=\"bare\">samples/traverse_iter.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">it</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool:&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">attributes_begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">attributes_end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">ait</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">ait</span><span class=\"tok-o\">-&gt;</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If your C&#43;&#43; compiler supports range-based for-loop (this is a C&#43;&#43;11 feature, at the time of writing it&#8217;s supported by Microsoft Visual Studio 11 Beta, GCC 4.6 and Clang 3.0), you can use it to enumerate nodes/attributes. Additional helpers are provided to support this; note that they are also compatible with <a href=\"http://www.boost.org/libs/foreach/\">Boost Foreach</a>, and possibly other pre-C&#43;&#43;11 foreach facilities.</p>\n</div>\n<div class=\"paragraph\">\n<p>Here is an example of using C&#43;&#43;11 range-based for loop for document traversal (<a href=\"samples/traverse_rangefor.cpp\" class=\"bare\">samples/traverse_rangefor.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">children</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Tool&quot;</span><span class=\"tok-p\">))</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tool:&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attributes</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot; &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">children</span><span class=\"tok-p\">())</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, child &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">child</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">();</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>The methods described above allow traversal of immediate children of some node; if you want to do a deep tree traversal, you&#8217;ll have to do it via a recursive function or some equivalent method. However, pugixml provides a helper for depth-first traversal of a subtree. In order to use it, you have to implement <code>xml_tree_walker</code> interface and to call <code>traverse</code> function.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of traversing tree hierarchy with xml_tree_walker (<a href=\"samples/traverse_walker.cpp\" class=\"bare\">samples/traverse_walker.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">simple_walker</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_tree_walker</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">bool</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">for_each</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-o\">&amp;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-kt\">int</span><span class=\"tok-w\"> </span><span class=\"tok-n\">i</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mi\">0</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">i</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">depth</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">i</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;  &quot;</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// indentation</span>\n\n<span class=\"tok-w\">        </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node_types</span><span class=\"tok-p\">[</span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">type</span><span class=\"tok-p\">()]</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;: name=&#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;, value=&#39;&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;&#39;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">        </span><span class=\"tok-k\">return</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">;</span><span class=\"tok-w\"> </span><span class=\"tok-c1\">// continue traversal</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">simple_walker</span><span class=\"tok-w\"> </span><span class=\"tok-n\">walker</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">traverse</span><span class=\"tok-p\">(</span><span class=\"tok-n\">walker</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Finally, for complex queries often a higher-level DSL is needed. pugixml provides an implementation of XPath 1.0 language for such queries. The complete description of XPath usage can be found in the manual, but here are some examples:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_nodes</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;/Profile/Tools/Tool[@AllowRemote=&#39;true&#39; and @DeriveCaptionFrom=&#39;lastparam&#39;]&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Tools:</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-k\">for</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node_set</span><span class=\"tok-o\">::</span><span class=\"tok-n\">const_iterator</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">begin</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-n\">it</span><span class=\"tok-w\"> </span><span class=\"tok-o\">!=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">tools</span><span class=\"tok-p\">.</span><span class=\"tok-n\">end</span><span class=\"tok-p\">();</span><span class=\"tok-w\"> </span><span class=\"tok-o\">++</span><span class=\"tok-n\">it</span><span class=\"tok-p\">)</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-o\">*</span><span class=\"tok-n\">it</span><span class=\"tok-p\">;</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-p\">}</span>\n\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xpath_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">build_tool</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">select_node</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;//Tool[contains(Description, &#39;build system&#39;)]&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-k\">if</span><span class=\"tok-w\"> </span><span class=\"tok-p\">(</span><span class=\"tok-n\">build_tool</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Build tool: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">build_tool</span><span class=\"tok-p\">.</span><span class=\"tok-n\">node</span><span class=\"tok-p\">().</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Filename&quot;</span><span class=\"tok-p\">).</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\nXPath functions throw <code>xpath_exception</code> objects on error; the sample above does not catch these exceptions.\n</td>\n</tr>\n</table>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"modify\"><a class=\"anchor\" href=\"#modify\"></a><a class=\"link\" href=\"#modify\">Modifying document data</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The document in pugixml is fully mutable: you can completely change the document structure and modify the data of nodes/attributes. All functions take care of memory management and structural integrity themselves, so they always result in structurally valid tree - however, it is possible to create an invalid XML tree (for example, by adding two attributes with the same name or by setting attribute/node name to empty/invalid string). Tree modification is optimized for performance and for memory consumption, so if you have enough memory you can create documents from scratch with pugixml and later save them to file/stream instead of relying on error-prone manual text writing and without too much overhead.</p>\n</div>\n<div class=\"paragraph\">\n<p>All member functions that change node/attribute data or structure are non-constant and thus can not be called on constant handles. However, you can easily convert constant handle to non-constant one by simple assignment: <code>void foo(const pugi::xml_node&amp; n) { pugi::xml_node nc = n; }</code>, so const-correctness here mainly provides additional documentation.</p>\n</div>\n<div class=\"paragraph\">\n<p>As discussed before, nodes can have name and value, both of which are strings. Depending on node type, name or value may be absent. You can use <code>set_name</code> and <code>set_value</code> member functions to set them. Similar functions are available for attributes; however, the <code>set_value</code> function is overloaded for some other types except strings, like floating-point numbers. Also, attribute value can be set using an assignment operator. This is an example of setting node/attribute name and value (<a href=\"samples/modify_base.cpp\" class=\"bare\">samples/modify_base.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// change node name</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;notnode&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new node name: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// change comment text</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;useless comment&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new comment text: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can&#39;t change value of the element or name of the comment</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;1&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">last_child</span><span class=\"tok-p\">().</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;2&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;id&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// change attribute name/value</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_name</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;key&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;345&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;, new attribute: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">name</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;=&quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can use numbers or booleans</span>\n<span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-mf\">1.234</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;new attribute value: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-c1\">// we can also use assignment operators for more concise code</span>\n<span class=\"tok-n\">attr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-nb\">true</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;final attribute value: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">attr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">value</span><span class=\"tok-p\">()</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>Nodes and attributes do not exist without a document tree, so you can&#8217;t create them without adding them to some document. A node or attribute can be created at the end of node/attribute list or before/after some other node. All insertion functions return the handle to newly created object on success, and null handle on failure. Even if the operation fails (for example, if you&#8217;re trying to add a child node to PCDATA node), the document remains in consistent state, but the requested node/attribute is not added.</p>\n</div>\n<div class=\"admonitionblock caution\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Caution</div>\n</td>\n<td class=\"content\">\n<code>attribute()</code> and <code>child()</code> functions do not add attributes or nodes to the tree, so code like <code>node.attribute(\"id\") = 123;</code> will not do anything if <code>node</code> does not have an attribute with name <code>\"id\"</code>. Make sure you&#8217;re operating with existing attributes/nodes by adding them if necessary.\n</td>\n</tr>\n</table>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of adding new attributes/nodes to the document (<a href=\"samples/modify_add.cpp\" class=\"bare\">samples/modify_add.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// add node with some name</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add description node with text child</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">descr</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">descr</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_child</span><span class=\"tok-p\">(</span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">node_pcdata</span><span class=\"tok-p\">).</span><span class=\"tok-n\">set_value</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;Simple node&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add param node before the description</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_child_before</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;param&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">descr</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// add attributes to param node</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;version&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;value&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-mf\">1.1</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">insert_attribute_after</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;type&quot;</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">))</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;float&quot;</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>If you do not want your document to contain some node or attribute, you can remove it with <code>remove_attribute</code> and <code>remove_child</code> functions. Removing the attribute or node invalidates all handles to the same underlying object, and also invalidates all iterators pointing to the same object. Removing node also invalidates all past-the-end iterators to its attribute or child node list. Be careful to ensure that all such handles and iterators either do not exist or are not used after the attribute/node is removed.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is an example of removing attributes/nodes from the document (<a href=\"samples/modify_remove.cpp\" class=\"bare\">samples/modify_remove.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// remove description node with the whole subtree</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;node&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;description&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// remove id attribute</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_node</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">node</span><span class=\"tok-p\">.</span><span class=\"tok-n\">child</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;param&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;value&quot;</span><span class=\"tok-p\">);</span>\n\n<span class=\"tok-c1\">// we can also remove nodes/attributes by handles</span>\n<span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_attribute</span><span class=\"tok-w\"> </span><span class=\"tok-n\">id</span><span class=\"tok-w\"> </span><span class=\"tok-o\">=</span><span class=\"tok-w\"> </span><span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">attribute</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;name&quot;</span><span class=\"tok-p\">);</span>\n<span class=\"tok-n\">param</span><span class=\"tok-p\">.</span><span class=\"tok-n\">remove_attribute</span><span class=\"tok-p\">(</span><span class=\"tok-n\">id</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"saving\"><a class=\"anchor\" href=\"#saving\"></a><a class=\"link\" href=\"#saving\">Saving document</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Often after creating a new document or loading the existing one and processing it, it is necessary to save the result back to file. Also it is occasionally useful to output the whole document or a subtree to some stream; use cases include debug printing, serialization via network or other text-oriented medium, etc. pugixml provides several functions to output any subtree of the document to a file, stream or another generic transport interface; these functions allow to customize the output format, and also perform necessary encoding conversions.</p>\n</div>\n<div class=\"paragraph\">\n<p>Before writing to the destination the node/attribute data is properly formatted according to the node type; all special XML symbols, such as &lt; and &amp;, are properly escaped. In order to guard against forgotten node/attribute names, empty node/attribute names are printed as <code>\":anonymous\"</code>. For well-formed output, make sure all node and attribute names are set to meaningful values.</p>\n</div>\n<div class=\"paragraph\">\n<p>If you want to save the whole document to a file, you can use the <code>save_file</code> function, which returns <code>true</code> on success. This is a simple example of saving XML document to file (<a href=\"samples/save_file.cpp\" class=\"bare\">samples/save_file.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// save document to file</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Saving result: &quot;</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save_file</span><span class=\"tok-p\">(</span><span class=\"tok-s\">&quot;save_file_output.xml&quot;</span><span class=\"tok-p\">)</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">endl</span><span class=\"tok-p\">;</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>To enhance interoperability pugixml provides functions for saving document to any object which implements C&#43;&#43; <code>std::ostream</code> interface. This allows you to save documents to any standard C&#43;&#43; stream (i.e. file stream) or any third-party compliant implementation (i.e. Boost Iostreams). Most notably, this allows for easy debug output, since you can use <code>std::cout</code> stream as saving target. There are two functions, one works with narrow character streams, another handles wide character ones.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of saving XML document to standard output (<a href=\"samples/save_stream.cpp\" class=\"bare\">samples/save_stream.cpp</a>):</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-c1\">// save document to standard output</span>\n<span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-w\"> </span><span class=\"tok-o\">&lt;&lt;</span><span class=\"tok-w\"> </span><span class=\"tok-s\">&quot;Document:</span><span class=\"tok-se\">\\n</span><span class=\"tok-s\">&quot;</span><span class=\"tok-p\">;</span>\n<span class=\"tok-n\">doc</span><span class=\"tok-p\">.</span><span class=\"tok-n\">save</span><span class=\"tok-p\">(</span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">cout</span><span class=\"tok-p\">);</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>All of the above saving functions are implemented in terms of writer interface. This is a simple interface with a single function, which is called several times during output process with chunks of document data as input. In order to output the document via some custom transport, for example sockets, you should create an object which implements <code>xml_writer_file</code> interface and pass it to <code>xml_document::save</code> function.</p>\n</div>\n<div class=\"paragraph\">\n<p>This is a simple example of custom writer for saving document data to STL string (<a href=\"samples/save_custom_writer.cpp\" class=\"bare\">samples/save_custom_writer.cpp</a>); read the sample code for more complex examples:</p>\n</div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"pygments highlight\"><code data-lang=\"c++\"><span></span><span class=\"tok-k\">struct</span><span class=\"tok-w\"> </span><span class=\"tok-nc\">xml_string_writer</span><span class=\"tok-o\">:</span><span class=\"tok-w\"> </span><span class=\"tok-n\">pugi</span><span class=\"tok-o\">::</span><span class=\"tok-n\">xml_writer</span>\n<span class=\"tok-p\">{</span>\n<span class=\"tok-w\">    </span><span class=\"tok-n\">std</span><span class=\"tok-o\">::</span><span class=\"tok-n\">string</span><span class=\"tok-w\"> </span><span class=\"tok-n\">result</span><span class=\"tok-p\">;</span>\n\n<span class=\"tok-w\">    </span><span class=\"tok-k\">virtual</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-w\"> </span><span class=\"tok-nf\">write</span><span class=\"tok-p\">(</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">void</span><span class=\"tok-o\">*</span><span class=\"tok-w\"> </span><span class=\"tok-n\">data</span><span class=\"tok-p\">,</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">size_t</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">)</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">{</span>\n<span class=\"tok-w\">        </span><span class=\"tok-n\">result</span><span class=\"tok-p\">.</span><span class=\"tok-n\">append</span><span class=\"tok-p\">(</span><span class=\"tok-k\">static_cast</span><span class=\"tok-o\">&lt;</span><span class=\"tok-k\">const</span><span class=\"tok-w\"> </span><span class=\"tok-kt\">char</span><span class=\"tok-o\">*&gt;</span><span class=\"tok-p\">(</span><span class=\"tok-n\">data</span><span class=\"tok-p\">),</span><span class=\"tok-w\"> </span><span class=\"tok-n\">size</span><span class=\"tok-p\">);</span>\n<span class=\"tok-w\">    </span><span class=\"tok-p\">}</span>\n<span class=\"tok-p\">};</span></code></pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>While the previously described functions save the whole document to the destination, it is easy to save a single subtree. Instead of calling <code>xml_document::save</code>, just call <code>xml_node::print</code> function on the target node. You can save node contents to C&#43;&#43; IOstream object or custom writer in this way. Saving a subtree slightly differs from saving the whole document; <a href=\"manual.html#saving.subtree\">read the manual</a> for more information.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"feedback\"><a class=\"anchor\" href=\"#feedback\"></a><a class=\"link\" href=\"#feedback\">Feedback</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If you believe you&#8217;ve found a bug in pugixml, please file an issue via <a href=\"https://github.com/zeux/pugixml/issues/new\">issue submission form</a>. Be sure to include the relevant information so that the bug can be reproduced: the version of pugixml, compiler version and target architecture, the code that uses pugixml and exhibits the bug, etc. Feature requests and contributions can be filed as issues, too.</p>\n</div>\n<div class=\"paragraph\">\n<p>If filing an issue is not possible due to privacy or other concerns, you can contact pugixml author by e-mail directly: <a href=\"mailto:arseny.kapoulkine@gmail.com\">arseny.kapoulkine@gmail.com</a>.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"license\"><a class=\"anchor\" href=\"#license\"></a><a class=\"link\" href=\"#license\">License</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The pugixml library is distributed under the MIT license:</p>\n</div>\n<div class=\"literalblock\">\n<div class=\"content\">\n<pre>Copyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.</pre>\n</div>\n</div>\n<div class=\"paragraph\">\n<p>This means that you can freely use pugixml in your applications, both open-source and proprietary. If you use pugixml in a product, it is sufficient to add an acknowledgment like this to the product distribution:</p>\n</div>\n<div class=\"literalblock\">\n<div class=\"content\">\n<pre>This software is based on pugixml library (https://pugixml.org).\npugixml is Copyright (C) 2006-2025 Arseny Kapoulkine.</pre>\n</div>\n</div>\n</div>\n</div>\n</div>\n<div id=\"footnotes\">\n<hr>\n<div class=\"footnote\" id=\"_footnotedef_1\">\n<a href=\"#_footnoteref_1\">1</a>. All trademarks used are properties of their respective owners.\n</div>\n</div>\n<div id=\"footer\">\n<div id=\"footer-text\">\nLast updated 2025-01-10 07:29:46 -0800\n</div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "external/pugixml/docs/samples/character.xml",
    "content": "<?xml version=\"1.0\"?>\n<network>\n\t<animation clip=\"idle\" flags=\"loop\" />\n\t<animation clip=\"run\" flags=\"loop\" />\n\t<animation clip=\"attack\" />\n\n\t<?include transitions.xml?>\n</network>\n"
  },
  {
    "path": "external/pugixml/docs/samples/custom_memory_management.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <new>\n\n// tag::decl[]\nvoid* custom_allocate(size_t size)\n{\n    return new (std::nothrow) char[size];\n}\n\nvoid custom_deallocate(void* ptr)\n{\n    delete[] static_cast<char*>(ptr);\n}\n// end::decl[]\n\nint main()\n{\n// tag::call[]\n    pugi::set_memory_management_functions(custom_allocate, custom_deallocate);\n// end::call[]\n\n    pugi::xml_document doc;\n    doc.load_string(\"<node/>\");\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/include.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <string.h>\n#include <iostream>\n\n// tag::code[]\nbool load_preprocess(pugi::xml_document& doc, const char* path);\n\nbool preprocess(pugi::xml_node node)\n{\n    for (pugi::xml_node child = node.first_child(); child; )\n    {\n        if (child.type() == pugi::node_pi && strcmp(child.name(), \"include\") == 0)\n        {\n            pugi::xml_node include = child;\n\n            // load new preprocessed document (note: ideally this should handle relative paths)\n            const char* path = include.value();\n\n            pugi::xml_document doc;\n            if (!load_preprocess(doc, path)) return false;\n\n            // insert the comment marker above include directive\n            node.insert_child_before(pugi::node_comment, include).set_value(path);\n\n            // copy the document above the include directive (this retains the original order!)\n            for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling())\n            {\n                node.insert_copy_before(ic, include);\n            }\n\n            // remove the include node and move to the next child\n            child = child.next_sibling();\n\n            node.remove_child(include);\n        }\n        else\n        {\n            if (!preprocess(child)) return false;\n\n            child = child.next_sibling();\n        }\n    }\n\n    return true;\n}\n\nbool load_preprocess(pugi::xml_document& doc, const char* path)\n{\n    pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for <?include?>\n\n    return result ? preprocess(doc) : false;\n}\n// end::code[]\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!load_preprocess(doc, \"character.xml\")) return -1;\n\n    doc.print(std::cout);\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/load_error_handling.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nvoid check_xml(const char* source)\n{\n// tag::code[]\n    pugi::xml_document doc;\n    pugi::xml_parse_result result = doc.load_string(source);\n\n    if (result)\n    {\n        std::cout << \"XML [\" << source << \"] parsed without errors, attr value: [\" << doc.child(\"node\").attribute(\"attr\").value() << \"]\\n\\n\";\n    }\n    else\n    {\n        std::cout << \"XML [\" << source << \"] parsed with errors, attr value: [\" << doc.child(\"node\").attribute(\"attr\").value() << \"]\\n\";\n        std::cout << \"Error description: \" << result.description() << \"\\n\";\n        std::cout << \"Error offset: \" << result.offset << \" (error at [...\" << (source + result.offset) << \"]\\n\\n\";\n    }\n// end::code[]\n}\n\nint main()\n{\n    check_xml(\"<node attr='value'><child>text</child></node>\");\n    check_xml(\"<node attr='value'><child>text</chil></node>\");\n    check_xml(\"<node attr='value'><child>text</child>\");\n    check_xml(\"<node attr='value\\\"><child>text</child></node>\");\n    check_xml(\"<node attr='value'><#tag /></node>\");\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/load_file.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n// tag::code[]\n    pugi::xml_document doc;\n\n    pugi::xml_parse_result result = doc.load_file(\"tree.xml\");\n\n    std::cout << \"Load result: \" << result.description() << \", mesh name: \" << doc.child(\"mesh\").attribute(\"name\").value() << std::endl;\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/load_memory.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n#include <cstring>\n\nint main()\n{\n// tag::decl[]\n    const char source[] = \"<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>\";\n    size_t size = sizeof(source);\n// end::decl[]\n\n    pugi::xml_document doc;\n\n    {\n    // tag::load_buffer[]\n        // You can use load_buffer to load document from immutable memory block:\n        pugi::xml_parse_result result = doc.load_buffer(source, size);\n    // end::load_buffer[]\n\n        std::cout << \"Load result: \" << result.description() << \", mesh name: \" << doc.child(\"mesh\").attribute(\"name\").value() << std::endl;\n    }\n\n    {\n    // tag::load_buffer_inplace_begin[]\n        // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document\n        char* buffer = new char[size];\n        memcpy(buffer, source, size);\n\n        // The block can be allocated by any method; the block is modified during parsing\n        pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);\n    // end::load_buffer_inplace_begin[]\n\n        std::cout << \"Load result: \" << result.description() << \", mesh name: \" << doc.child(\"mesh\").attribute(\"name\").value() << std::endl;\n\n    // tag::load_buffer_inplace_end[]\n        // You have to destroy the block yourself after the document is no longer used\n        delete[] buffer;\n    // end::load_buffer_inplace_end[]\n    }\n\n    {\n    // tag::load_buffer_inplace_own[]\n        // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block\n        // The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect\n        char* buffer = static_cast<char*>(pugi::get_memory_allocation_function()(size));\n        memcpy(buffer, source, size);\n\n        // The block will be deleted by the document\n        pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size);\n    // end::load_buffer_inplace_own[]\n\n        std::cout << \"Load result: \" << result.description() << \", mesh name: \" << doc.child(\"mesh\").attribute(\"name\").value() << std::endl;\n    }\n\n    {\n    // tag::load_string[]\n        // You can use load to load document from null-terminated strings, for example literals:\n        pugi::xml_parse_result result = doc.load_string(\"<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>\");\n    // end::load_string[]\n\n        std::cout << \"Load result: \" << result.description() << \", mesh name: \" << doc.child(\"mesh\").attribute(\"name\").value() << std::endl;\n    }\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/load_options.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n\n// tag::code[]\n    const char* source = \"<!--comment--><node>&lt;</node>\";\n\n    // Parsing with default options; note that comment node is not added to the tree, and entity reference &lt; is expanded\n    doc.load_string(source);\n    std::cout << \"First node value: [\" << doc.first_child().value() << \"], node child value: [\" << doc.child_value(\"node\") << \"]\\n\";\n\n    // Parsing with additional parse_comments option; comment node is now added to the tree\n    doc.load_string(source, pugi::parse_default | pugi::parse_comments);\n    std::cout << \"First node value: [\" << doc.first_child().value() << \"], node child value: [\" << doc.child_value(\"node\") << \"]\\n\";\n\n    // Parsing with additional parse_comments option and without the (default) parse_escapes option; &lt; is not expanded\n    doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes);\n    std::cout << \"First node value: [\" << doc.first_child().value() << \"], node child value: [\" << doc.child_value(\"node\") << \"]\\n\";\n\n    // Parsing with minimal option mask; comment node is not added to the tree, and &lt; is not expanded\n    doc.load_string(source, pugi::parse_minimal);\n    std::cout << \"First node value: [\" << doc.first_child().value() << \"], node child value: [\" << doc.child_value(\"node\") << \"]\\n\";\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/load_stream.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n\nvoid print_doc(const char* message, const pugi::xml_document& doc, const pugi::xml_parse_result& result)\n{\n    std::cout\n        << message\n        << \"\\t: load result '\" << result.description() << \"'\"\n        << \", first character of root name: U+\" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << pugi::as_wide(doc.first_child().name())[0]\n        << \", year: \" << doc.first_child().first_child().first_child().child_value()\n        << std::endl;\n}\n\nbool try_imbue(std::wistream& stream, const char* name)\n{\n    try\n    {\n        stream.imbue(std::locale(name));\n\n        return true;\n    }\n    catch (const std::exception&)\n    {\n        return false;\n    }\n}\n\nint main()\n{\n    pugi::xml_document doc;\n\n    {\n    // tag::code[]\n        std::ifstream stream(\"weekly-utf-8.xml\");\n        pugi::xml_parse_result result = doc.load(stream);\n    // end::code[]\n\n        // first character of root name: U+9031, year: 1997\n        print_doc(\"UTF8 file from narrow stream\", doc, result);\n    }\n\n    {\n        std::ifstream stream(\"weekly-utf-16.xml\");\n        pugi::xml_parse_result result = doc.load(stream);\n\n        // first character of root name: U+9031, year: 1997\n        print_doc(\"UTF16 file from narrow stream\", doc, result);\n    }\n\n    {\n        // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-8 file from a wide stream\n        // directly if you have localized characters; you'll have to provide a UTF8 locale (there is no\n        // standard one; you can use utf8_codecvt_facet from Boost or codecvt_utf8 from C++0x)\n        std::wifstream stream(\"weekly-utf-8.xml\");\n\n        if (try_imbue(stream, \"en_US.UTF-8\")) // try Linux encoding\n        {\n            pugi::xml_parse_result result = doc.load(stream);\n\n            // first character of root name: U+00E9, year: 1997\n            print_doc(\"UTF8 file from wide stream\", doc, result);\n        }\n        else\n        {\n            std::cout << \"UTF-8 locale is not available\\n\";\n        }\n    }\n\n    {\n        // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-16 file from a wide stream without\n        // using custom codecvt; you can use codecvt_utf16 from C++0x\n    }\n\n    {\n        // Since encoding names are non-standard, you can't load the Shift-JIS (or any other non-ASCII) file\n        // from a wide stream portably\n        std::wifstream stream(\"weekly-shift_jis.xml\");\n\n        if (try_imbue(stream, \".932\") || // try Microsoft encoding\n            try_imbue(stream, \"ja_JP.SJIS\")) // try Linux encoding; run \"localedef -i ja_JP -c -f SHIFT_JIS /usr/lib/locale/ja_JP.SJIS\" to get it\n        {\n            pugi::xml_parse_result result = doc.load(stream);\n\n            // first character of root name: U+9031, year: 1997\n            print_doc(\"Shift-JIS file from wide stream\", doc, result);\n        }\n        else\n        {\n            std::cout << \"Shift-JIS locale is not available\\n\";\n        }\n    }\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/modify_add.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n\n    // tag::code[]\n    // add node with some name\n    pugi::xml_node node = doc.append_child(\"node\");\n\n    // add description node with text child\n    pugi::xml_node descr = node.append_child(\"description\");\n    descr.append_child(pugi::node_pcdata).set_value(\"Simple node\");\n\n    // add param node before the description\n    pugi::xml_node param = node.insert_child_before(\"param\", descr);\n\n    // add attributes to param node\n    param.append_attribute(\"name\") = \"version\";\n    param.append_attribute(\"value\") = 1.1;\n    param.insert_attribute_after(\"type\", param.attribute(\"name\")) = \"float\";\n    // end::code[]\n\n    doc.print(std::cout);\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/modify_base.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <string.h>\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_string(\"<node id='123'>text</node><!-- comment -->\", pugi::parse_default | pugi::parse_comments)) return -1;\n\n    // tag::node[]\n    pugi::xml_node node = doc.child(\"node\");\n\n    // change node name\n    std::cout << node.set_name(\"notnode\");\n    std::cout << \", new node name: \" << node.name() << std::endl;\n\n    // change comment text\n    std::cout << doc.last_child().set_value(\"useless comment\");\n    std::cout << \", new comment text: \" << doc.last_child().value() << std::endl;\n\n    // we can't change value of the element or name of the comment\n    std::cout << node.set_value(\"1\") << \", \" << doc.last_child().set_name(\"2\") << std::endl;\n    // end::node[]\n\n    // tag::attr[]\n    pugi::xml_attribute attr = node.attribute(\"id\");\n\n    // change attribute name/value\n    std::cout << attr.set_name(\"key\") << \", \" << attr.set_value(\"345\");\n    std::cout << \", new attribute: \" << attr.name() << \"=\" << attr.value() << std::endl;\n\n    // we can use numbers or booleans\n    attr.set_value(1.234);\n    std::cout << \"new attribute value: \" << attr.value() << std::endl;\n\n    // we can also use assignment operators for more concise code\n    attr = true;\n    std::cout << \"final attribute value: \" << attr.value() << std::endl;\n    // end::attr[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/modify_remove.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_string(\"<node><description>Simple node</description><param name='id' value='123'/></node>\")) return -1;\n\n    // tag::code[]\n    // remove description node with the whole subtree\n    pugi::xml_node node = doc.child(\"node\");\n    node.remove_child(\"description\");\n\n    // remove id attribute\n    pugi::xml_node param = node.child(\"param\");\n    param.remove_attribute(\"value\");\n\n    // we can also remove nodes/attributes by handles\n    pugi::xml_attribute id = param.attribute(\"name\");\n    param.remove_attribute(id);\n    // end::code[]\n\n    doc.print(std::cout);\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_custom_writer.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <string>\n#include <iostream>\n#include <cstring>\n\n// tag::code[]\nstruct xml_string_writer: pugi::xml_writer\n{\n    std::string result;\n\n    virtual void write(const void* data, size_t size)\n    {\n        result.append(static_cast<const char*>(data), size);\n    }\n};\n// end::code[]\n\nstruct xml_memory_writer: pugi::xml_writer\n{\n    char* buffer;\n    size_t capacity;\n\n    size_t result;\n\n    xml_memory_writer(): buffer(0), capacity(0), result(0)\n    {\n    }\n\n    xml_memory_writer(char* buffer, size_t capacity): buffer(buffer), capacity(capacity), result(0)\n    {\n    }\n\n    size_t written_size() const\n    {\n        return result < capacity ? result : capacity;\n    }\n\n    virtual void write(const void* data, size_t size)\n    {\n        if (result < capacity)\n        {\n            size_t chunk = (capacity - result < size) ? capacity - result : size;\n\n            memcpy(buffer + result, data, chunk);\n        }\n\n        result += size;\n    }\n};\n\nstd::string node_to_string(pugi::xml_node node)\n{\n    xml_string_writer writer;\n    node.print(writer);\n\n    return writer.result;\n}\n\nchar* node_to_buffer(pugi::xml_node node, char* buffer, size_t size)\n{\n    if (size == 0) return buffer;\n\n    // leave one character for null terminator\n    xml_memory_writer writer(buffer, size - 1);\n    node.print(writer);\n\n    // null terminate\n    buffer[writer.written_size()] = 0;\n\n    return buffer;\n}\n\nchar* node_to_buffer_heap(pugi::xml_node node)\n{\n    // first pass: get required memory size\n    xml_memory_writer counter;\n    node.print(counter);\n\n    // allocate necessary size (+1 for null termination)\n    char* buffer = new char[counter.result + 1];\n\n    // second pass: actual printing\n    xml_memory_writer writer(buffer, counter.result);\n    node.print(writer);\n\n    // null terminate\n    buffer[writer.written_size()] = 0;\n\n    return buffer;\n}\n\nint main()\n{\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'>hey</foo>\");\n\n    // get contents as std::string (single pass)\n    std::cout << \"contents: [\" << node_to_string(doc) << \"]\\n\";\n\n    // get contents into fixed-size buffer (single pass)\n    char large_buf[128];\n    std::cout << \"contents: [\" << node_to_buffer(doc, large_buf, sizeof(large_buf)) << \"]\\n\";\n\n    // get contents into fixed-size buffer (single pass, shows truncating behavior)\n    char small_buf[22];\n    std::cout << \"contents: [\" << node_to_buffer(doc, small_buf, sizeof(small_buf)) << \"]\\n\";\n\n    // get contents into heap-allocated buffer (two passes)\n    char* heap_buf = node_to_buffer_heap(doc);\n    std::cout << \"contents: [\" << heap_buf << \"]\\n\";\n    delete[] heap_buf;\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_declaration.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    // tag::code[]\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'><call>hey</call></foo>\");\n\n    // add a custom declaration node\n    pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);\n    decl.append_attribute(\"version\") = \"1.0\";\n    decl.append_attribute(\"encoding\") = \"UTF-8\";\n    decl.append_attribute(\"standalone\") = \"no\";\n\n    // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n    // <foo bar=\"baz\">\n    //         <call>hey</call>\n    // </foo>\n    doc.save(std::cout);\n    std::cout << std::endl;\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_file.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'>hey</foo>\");\n\n    // tag::code[]\n    // save document to file\n    std::cout << \"Saving result: \" << doc.save_file(\"save_file_output.xml\") << std::endl;\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_options.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    // tag::code[]\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'><call>hey</call></foo>\");\n\n    // default options; prints\n    // <?xml version=\"1.0\"?>\n    // <foo bar=\"baz\">\n    //         <call>hey</call>\n    // </foo>\n    doc.save(std::cout);\n    std::cout << std::endl;\n\n    // default options with custom indentation string; prints\n    // <?xml version=\"1.0\"?>\n    // <foo bar=\"baz\">\n    // --<call>hey</call>\n    // </foo>\n    doc.save(std::cout, \"--\");\n    std::cout << std::endl;\n\n    // default options without indentation; prints\n    // <?xml version=\"1.0\"?>\n    // <foo bar=\"baz\">\n    // <call>hey</call>\n    // </foo>\n    doc.save(std::cout, \"\\t\", pugi::format_default & ~pugi::format_indent); // can also pass \"\" instead of indentation string for the same effect\n    std::cout << std::endl;\n\n    // raw output; prints\n    // <?xml version=\"1.0\"?><foo bar=\"baz\"><call>hey</call></foo>\n    doc.save(std::cout, \"\\t\", pugi::format_raw);\n    std::cout << std::endl << std::endl;\n\n    // raw output without declaration; prints\n    // <foo bar=\"baz\"><call>hey</call></foo>\n    doc.save(std::cout, \"\\t\", pugi::format_raw | pugi::format_no_declaration);\n    std::cout << std::endl;\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_stream.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'><call>hey</call></foo>\");\n\n    // tag::code[]\n    // save document to standard output\n    std::cout << \"Document:\\n\";\n    doc.save(std::cout);\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/save_subtree.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    // tag::code[]\n    // get a test document\n    pugi::xml_document doc;\n    doc.load_string(\"<foo bar='baz'><call>hey</call></foo>\");\n\n    // print document to standard output (prints <?xml version=\"1.0\"?><foo bar=\"baz\"><call>hey</call></foo>)\n    doc.save(std::cout, \"\", pugi::format_raw);\n    std::cout << std::endl;\n\n    // print document to standard output as a regular node (prints <foo bar=\"baz\"><call>hey</call></foo>)\n    doc.print(std::cout, \"\", pugi::format_raw);\n    std::cout << std::endl;\n\n    // print a subtree to standard output (prints <call>hey</call>)\n    doc.child(\"foo\").child(\"call\").print(std::cout, \"\", pugi::format_raw);\n    std::cout << std::endl;\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/text.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n\n    // get a test document\n    doc.load_string(\"<project><name>test</name><version>1.1</version><public>yes</public></project>\");\n\n    pugi::xml_node project = doc.child(\"project\");\n\n    // tag::access[]\n    std::cout << \"Project name: \" << project.child(\"name\").text().get() << std::endl;\n    std::cout << \"Project version: \" << project.child(\"version\").text().as_double() << std::endl;\n    std::cout << \"Project visibility: \" << (project.child(\"public\").text().as_bool(/* def= */ true) ? \"public\" : \"private\") << std::endl;\n    std::cout << \"Project description: \" << project.child(\"description\").text().get() << std::endl;\n    // end::access[]\n\n    std::cout << std::endl;\n\n    // tag::modify[]\n    // change project version\n    project.child(\"version\").text() = 1.2;\n\n    // add description element and set the contents\n    // note that we do not have to explicitly add the node_pcdata child\n    project.append_child(\"description\").text().set(\"a test project\");\n    // end::modify[]\n\n    doc.save(std::cout);\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/transitions.xml",
    "content": "<transition source=\"idle\" target=\"run\">\n\t<event name=\"key_up|key_shift\" />\n</transition>\n<transition source=\"run\" target=\"attack\">\n\t<event name=\"key_ctrl\" />\n\t<condition expr=\"weapon != null\" />\n</transition>\n"
  },
  {
    "path": "external/pugixml/docs/samples/traverse_base.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <string.h>\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n    pugi::xml_node tools = doc.child(\"Profile\").child(\"Tools\");\n\n    // tag::basic[]\n    for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling())\n    {\n        std::cout << \"Tool:\";\n\n        for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute())\n        {\n            std::cout << \" \" << attr.name() << \"=\" << attr.value();\n        }\n\n        std::cout << std::endl;\n    }\n    // end::basic[]\n\n    std::cout << std::endl;\n\n    // tag::data[]\n    for (pugi::xml_node tool = tools.child(\"Tool\"); tool; tool = tool.next_sibling(\"Tool\"))\n    {\n        std::cout << \"Tool \" << tool.attribute(\"Filename\").value();\n        std::cout << \": AllowRemote \" << tool.attribute(\"AllowRemote\").as_bool();\n        std::cout << \", Timeout \" << tool.attribute(\"Timeout\").as_int();\n        std::cout << \", Description '\" << tool.child_value(\"Description\") << \"'\\n\";\n    }\n    // end::data[]\n\n    std::cout << std::endl;\n\n    // tag::contents[]\n    std::cout << \"Tool for *.dae generation: \" << tools.find_child_by_attribute(\"Tool\", \"OutputFileMasks\", \"*.dae\").attribute(\"Filename\").value() << \"\\n\";\n\n    for (pugi::xml_node tool = tools.child(\"Tool\"); tool; tool = tool.next_sibling(\"Tool\"))\n    {\n        std::cout << \"Tool \" << tool.attribute(\"Filename\").value() << \"\\n\";\n    }\n    // end::contents[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/traverse_iter.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n    pugi::xml_node tools = doc.child(\"Profile\").child(\"Tools\");\n\n    // tag::code[]\n    for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)\n    {\n        std::cout << \"Tool:\";\n\n        for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait)\n        {\n            std::cout << \" \" << ait->name() << \"=\" << ait->value();\n        }\n\n        std::cout << std::endl;\n    }\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/traverse_predicate.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <string.h>\n#include <iostream>\n\n// tag::decl[]\nbool small_timeout(pugi::xml_node node)\n{\n    return node.attribute(\"Timeout\").as_int() < 20;\n}\n\nstruct allow_remote_predicate\n{\n    bool operator()(pugi::xml_attribute attr) const\n    {\n        return strcmp(attr.name(), \"AllowRemote\") == 0;\n    }\n\n    bool operator()(pugi::xml_node node) const\n    {\n        return node.attribute(\"AllowRemote\").as_bool();\n    }\n};\n// end::decl[]\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n    pugi::xml_node tools = doc.child(\"Profile\").child(\"Tools\");\n\n    // tag::find[]\n    // Find child via predicate (looks for direct children only)\n    std::cout << tools.find_child(allow_remote_predicate()).attribute(\"Filename\").value() << std::endl;\n\n    // Find node via predicate (looks for all descendants in depth-first order)\n    std::cout << doc.find_node(allow_remote_predicate()).attribute(\"Filename\").value() << std::endl;\n\n    // Find attribute via predicate\n    std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl;\n\n    // We can use simple functions instead of function objects\n    std::cout << tools.find_child(small_timeout).attribute(\"Filename\").value() << std::endl;\n    // end::find[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/traverse_rangefor.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n    pugi::xml_node tools = doc.child(\"Profile\").child(\"Tools\");\n\n    // tag::code[]\n    for (pugi::xml_node tool: tools.children(\"Tool\"))\n    {\n        std::cout << \"Tool:\";\n\n        for (pugi::xml_attribute attr: tool.attributes())\n        {\n            std::cout << \" \" << attr.name() << \"=\" << attr.value();\n        }\n\n        for (pugi::xml_node child: tool.children())\n        {\n            std::cout << \", child \" << child.name();\n        }\n\n        std::cout << std::endl;\n    }\n    // end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/traverse_walker.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nconst char* node_types[] =\n{\n    \"null\", \"document\", \"element\", \"pcdata\", \"cdata\", \"comment\", \"pi\", \"declaration\"\n};\n\n// tag::impl[]\nstruct simple_walker: pugi::xml_tree_walker\n{\n    virtual bool for_each(pugi::xml_node& node)\n    {\n        for (int i = 0; i < depth(); ++i) std::cout << \"  \"; // indentation\n\n        std::cout << node_types[node.type()] << \": name='\" << node.name() << \"', value='\" << node.value() << \"'\\n\";\n\n        return true; // continue traversal\n    }\n};\n// end::impl[]\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"tree.xml\")) return -1;\n\n    // tag::traverse[]\n    simple_walker walker;\n    doc.traverse(walker);\n    // end::traverse[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/tree.xml",
    "content": "<?xml version=\"1.0\"?>\n<mesh name=\"mesh_root\">\n\t<!-- here is a mesh node -->\n\tsome text\n\t<![CDATA[someothertext]]>\n\tsome more text\n\t<node attr1=\"value1\" attr2=\"value2\" />\n\t<node attr1=\"value2\">\n\t\t<innernode/>\n\t</node>\n</mesh>\n<?include somedata?>\n"
  },
  {
    "path": "external/pugixml/docs/samples/weekly-shift_jis.xml",
    "content": "<?xml version=\"1.0\" encoding=\"Shift_JIS\"?>\n<!DOCTYPE T SYSTEM \"weekly-shift_jis.dtd\">\n<!-- TTv -->\n<T>\n  <NT>\n    <Nx>1997</Nx>\n    <x>1</x>\n    <T>1</T>\n  </NT>\n\n  <>\n    <>Rc</>\n    <>Y</>\n  </>\n\n  <Ɩ񍐃Xg>\n    <Ɩ>\n      <Ɩ>XMLGfB^[̍쐬</Ɩ>\n      <ƖR[h>X3355-23</ƖR[h>\n      <HǗ>\n        <ςH>1600</ςH>\n        <эH>320</эH>\n        <ςH>160</ςH>\n        <эH>24</эH>\n      </HǗ>\n      <\\荀ڃXg>\n        <\\荀>\n          <P>XMLGfB^[̊{dl̍쐬</P>\n        </\\荀>\n      </\\荀ڃXg>\n      <{Xg>\n        <{>\n          <P>XMLGfB^[̊{dl̍쐬</P>\n        </{>\n        <{>\n          <P>Аi̋@\\</P>\n        </{>\n      </{Xg>\n      <㒷ւ̗vXg>\n        <㒷ւ̗v>\n          <P>ɂȂ</P>\n        </㒷ւ̗v>\n      </㒷ւ̗vXg>\n      <_΍>\n        <P>XMLƂ͉킩ȂB</P>\n      </_΍>\n    </Ɩ>\n\n    <Ɩ>\n      <Ɩ>GW̊J</Ɩ>\n      <ƖR[h>S8821-76</ƖR[h>\n      <HǗ>\n        <ςH>120</ςH>\n        <эH>6</эH>\n        <ςH>32</ςH>\n        <эH>2</эH>\n      </HǗ>\n      <\\荀ڃXg>\n        <\\荀>\n          <P><A href=\"http://www.goo.ne.jp\">goo</A>̋@\\𒲂ׂĂ݂</P>\n        </\\荀>\n      </\\荀ڃXg>\n      <{Xg>\n        <{>\n          <P>XɁAǂGW邩</P>\n        </{>\n      </{Xg>\n      <㒷ւ̗vXg>\n        <㒷ւ̗v>\n          <P>Ĵ͂߂ǂȂ̂ŁAYahoo!𔃎ĉB</P>\n        </㒷ւ̗v>\n      </㒷ւ̗vXg>\n      <_΍>\n        <P>GWŎԂ𑖂点邱ƂłȂBivj</P>\n      </_΍>\n    </Ɩ>\n  </Ɩ񍐃Xg>\n</T>\n"
  },
  {
    "path": "external/pugixml/docs/samples/weekly-utf-8.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE 週報 SYSTEM \"weekly-utf-8.dtd\">\n<!-- 週報サンプル -->\n<週報>\n  <年月週>\n    <年度>1997</年度>\n    <月度>1</月度>\n    <週>1</週>\n  </年月週>\n\n  <氏名>\n    <氏>山田</氏>\n    <名>太郎</名>\n  </氏名>\n\n  <業務報告リスト>\n    <業務報告>\n      <業務名>XMLエディターの作成</業務名>\n      <業務コード>X3355-23</業務コード>\n      <工数管理>\n        <見積もり工数>1600</見積もり工数>\n        <実績工数>320</実績工数>\n        <当月見積もり工数>160</当月見積もり工数>\n        <当月実績工数>24</当月実績工数>\n      </工数管理>\n      <予定項目リスト>\n        <予定項目>\n          <P>XMLエディターの基本仕様の作成</P>\n        </予定項目>\n      </予定項目リスト>\n      <実施事項リスト>\n        <実施事項>\n          <P>XMLエディターの基本仕様の作成</P>\n        </実施事項>\n        <実施事項>\n          <P>競合他社製品の機能調査</P>\n        </実施事項>\n      </実施事項リスト>\n      <上長への要請事項リスト>\n        <上長への要請事項>\n          <P>特になし</P>\n        </上長への要請事項>\n      </上長への要請事項リスト>\n      <問題点対策>\n        <P>XMLとは何かわからない。</P>\n      </問題点対策>\n    </業務報告>\n\n    <業務報告>\n      <業務名>検索エンジンの開発</業務名>\n      <業務コード>S8821-76</業務コード>\n      <工数管理>\n        <見積もり工数>120</見積もり工数>\n        <実績工数>6</実績工数>\n        <当月見積もり工数>32</当月見積もり工数>\n        <当月実績工数>2</当月実績工数>\n      </工数管理>\n      <予定項目リスト>\n        <予定項目>\n          <P><A href=\"http://www.goo.ne.jp\">goo</A>の機能を調べてみる</P>\n        </予定項目>\n      </予定項目リスト>\n      <実施事項リスト>\n        <実施事項>\n          <P>更に、どういう検索エンジンがあるか調査する</P>\n        </実施事項>\n      </実施事項リスト>\n      <上長への要請事項リスト>\n        <上長への要請事項>\n          <P>開発をするのはめんどうなので、Yahoo!を買収して下さい。</P>\n        </上長への要請事項>\n      </上長への要請事項リスト>\n      <問題点対策>\n        <P>検索エンジンで車を走らせることができない。（要調査）</P>\n      </問題点対策>\n    </業務報告>\n  </業務報告リスト>\n</週報>\n"
  },
  {
    "path": "external/pugixml/docs/samples/xgconsole.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n<Profile FormatVersion=\"1\">\n    <Tools>\n        <Tool Filename=\"jam\" AllowIntercept=\"true\">\n        \t<Description>Jamplus build system</Description>\n        </Tool>\n        <Tool Filename=\"mayabatch.exe\" AllowRemote=\"true\" OutputFileMasks=\"*.dae\" DeriveCaptionFrom=\"lastparam\" Timeout=\"40\" />\n        <Tool Filename=\"meshbuilder_*.exe\" AllowRemote=\"false\" OutputFileMasks=\"*.mesh\" DeriveCaptionFrom=\"lastparam\" Timeout=\"10\" />\n        <Tool Filename=\"texbuilder_*.exe\" AllowRemote=\"true\" OutputFileMasks=\"*.tex\" DeriveCaptionFrom=\"lastparam\" />\n        <Tool Filename=\"shaderbuilder_*.exe\" AllowRemote=\"true\" DeriveCaptionFrom=\"lastparam\" />\n    </Tools>\n</Profile>\n"
  },
  {
    "path": "external/pugixml/docs/samples/xpath_error.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n// tag::code[]\n    // Exception is thrown for incorrect query syntax\n    try\n    {\n        doc.select_nodes(\"//nodes[#true()]\");\n    }\n    catch (const pugi::xpath_exception& e)\n    {\n        std::cout << \"Select failed: \" << e.what() << std::endl;\n    }\n\n    // Exception is thrown for incorrect query semantics\n    try\n    {\n        doc.select_nodes(\"(123)/next\");\n    }\n    catch (const pugi::xpath_exception& e)\n    {\n        std::cout << \"Select failed: \" << e.what() << std::endl;\n    }\n\n    // Exception is thrown for query with incorrect return type\n    try\n    {\n        doc.select_nodes(\"123\");\n    }\n    catch (const pugi::xpath_exception& e)\n    {\n        std::cout << \"Select failed: \" << e.what() << std::endl;\n    }\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/xpath_query.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n#include <string>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n// tag::code[]\n    // Select nodes via compiled query\n    pugi::xpath_query query_remote_tools(\"/Profile/Tools/Tool[@AllowRemote='true']\");\n\n    pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc);\n    std::cout << \"Remote tool: \";\n    tools[2].node().print(std::cout);\n\n    // Evaluate numbers via compiled query\n    pugi::xpath_query query_timeouts(\"sum(//Tool/@Timeout)\");\n    std::cout << query_timeouts.evaluate_number(doc) << std::endl;\n\n    // Evaluate strings via compiled query for different context nodes\n    pugi::xpath_query query_name_valid(\"string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks\");\n    pugi::xpath_query query_name(\"concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)\");\n\n    for (pugi::xml_node tool = doc.first_element_by_path(\"Profile/Tools/Tool\"); tool; tool = tool.next_sibling())\n    {\n        std::string s = query_name.evaluate_string(tool);\n\n        if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl;\n    }\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/xpath_select.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n// tag::code[]\n    pugi::xpath_node_set tools = doc.select_nodes(\"/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']\");\n\n    std::cout << \"Tools:\\n\";\n\n    for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)\n    {\n        pugi::xpath_node node = *it;\n        std::cout << node.node().attribute(\"Filename\").value() << \"\\n\";\n    }\n\n    pugi::xpath_node build_tool = doc.select_node(\"//Tool[contains(Description, 'build system')]\");\n\n    if (build_tool)\n        std::cout << \"Build tool: \" << build_tool.node().attribute(\"Filename\").value() << \"\\n\";\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/docs/samples/xpath_variables.cpp",
    "content": "#include \"pugixml.hpp\"\n\n#include <iostream>\n#include <string>\n\nint main()\n{\n    pugi::xml_document doc;\n    if (!doc.load_file(\"xgconsole.xml\")) return -1;\n\n// tag::code[]\n    // Select nodes via compiled query\n    pugi::xpath_variable_set vars;\n    vars.add(\"remote\", pugi::xpath_type_boolean);\n\n    pugi::xpath_query query_remote_tools(\"/Profile/Tools/Tool[@AllowRemote = string($remote)]\", &vars);\n\n    vars.set(\"remote\", true);\n    pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc);\n\n    vars.set(\"remote\", false);\n    pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc);\n\n    std::cout << \"Remote tool: \";\n    tools_remote[2].node().print(std::cout);\n\n    std::cout << \"Local tool: \";\n    tools_local[0].node().print(std::cout);\n\n    // You can pass the context directly to select_nodes/select_node\n    pugi::xpath_node_set tools_local_imm = doc.select_nodes(\"/Profile/Tools/Tool[@AllowRemote = string($remote)]\", &vars);\n\n    std::cout << \"Local tool imm: \";\n    tools_local_imm[0].node().print(std::cout);\n// end::code[]\n}\n\n// vim:et\n"
  },
  {
    "path": "external/pugixml/readme.txt",
    "content": "pugixml 1.15 - an XML processing library\n\nCopyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)\nReport bugs and download new versions at https://pugixml.org/\n\nThis is the distribution of pugixml, which is a C++ XML processing library,\nwhich consists of a DOM-like interface with rich traversal/modification\ncapabilities, an extremely fast XML parser which constructs the DOM tree from\nan XML file/buffer, and an XPath 1.0 implementation for complex data-driven\ntree queries. Full Unicode support is also available, with Unicode interface\nvariants and conversions between different Unicode encodings (which happen\nautomatically during parsing/saving).\n\nThe distribution contains the following folders:\n\n\tdocs/ - documentation\n\t\tdocs/samples - pugixml usage examples\n\t\tdocs/quickstart.html - quick start guide\n\t\tdocs/manual.html - complete manual\n\n\tscripts/ - project files for IDE/build systems\n\n\tsrc/ - header and source files\n\n\treadme.txt - this file.\n\nThis library is distributed under the MIT License:\n\nCopyright (c) 2006-2025 Arseny Kapoulkine\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "external/pugixml/scripts/cocoapods_push.sh",
    "content": "#!/bin/bash\n\n#Push to igagis repo for now\npod repo push igagis pugixml.podspec --use-libraries --verbose\n"
  },
  {
    "path": "external/pugixml/scripts/natvis/pugixml.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"pugi::xml_node\">\n    <DisplayString Condition=\"_root\">{_root}</DisplayString>\n    <DisplayString Condition=\"!_root\">none</DisplayString>\n    <Expand>\n      <ExpandedItem Condition=\"_root\">_root</ExpandedItem>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_node_struct\">\n    <DisplayString Condition=\"name &amp;&amp; value\">{(pugi::xml_node_type)(header &amp; 0xf),en} name={name,na} value={value,na}</DisplayString>\n    <DisplayString Condition=\"name\">{(pugi::xml_node_type)(header &amp; 0xf),en} name={name,na}</DisplayString>\n    <DisplayString Condition=\"value\">{(pugi::xml_node_type)(header &amp; 0xf),en} value={value,na}</DisplayString>\n    <DisplayString>{(pugi::xml_node_type)(header &amp; 0xf),en}</DisplayString>\n    <Expand>\n      <Item Name=\"value\" Condition=\"value\">value,na</Item>\n      <Synthetic Name=\"attributes\" Condition=\"first_attribute\">\n        <Expand>\n          <CustomListItems>\n            <Variable Name=\"curr\" InitialValue=\"first_attribute\" />\n\n            <Loop Condition=\"curr\">\n              <Item Name=\"{curr->name,na}\">curr,view(child)na</Item>\n              <Exec>curr = curr->next_attribute</Exec>\n            </Loop>\n          </CustomListItems>\n        </Expand>\n      </Synthetic>\n      <LinkedListItems>\n        <HeadPointer>first_child</HeadPointer>\n        <NextPointer>next_sibling</NextPointer>\n        <ValueNode>this,na</ValueNode>\n      </LinkedListItems>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_attribute\">\n    <DisplayString Condition=\"_attr\">{_attr}</DisplayString>\n    <DisplayString Condition=\"!_attr\">none</DisplayString>\n    <Expand>\n      <ExpandedItem Condition=\"_attr\">_attr</ExpandedItem>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_attribute_struct\">\n    <DisplayString ExcludeView=\"child\">{name,na} = {value,na}</DisplayString>\n    <DisplayString>{value,na}</DisplayString>\n    <Expand>\n      <Item Name=\"name\">name,na</Item>\n      <Item Name=\"value\">value,na</Item>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xpath_node\">\n    <DisplayString Condition=\"_node._root &amp;&amp; _attribute._attr\">{_node,na} \"{_attribute._attr->name,na}\"=\"{_attribute._attr->value,na}\"</DisplayString>\n    <DisplayString Condition=\"_node._root\">{_node,na}</DisplayString>\n    <DisplayString Condition=\"_attribute._attr\">{_attribute}</DisplayString>\n    <DisplayString>empty</DisplayString>\n    <Expand HideRawView=\"1\">\n      <ExpandedItem Condition=\"_node._root &amp;&amp; !_attribute._attr\">_node</ExpandedItem>\n      <ExpandedItem Condition=\"!_node._root &amp;&amp; _attribute._attr\">_attribute</ExpandedItem>\n      <Item Name=\"node\" Condition=\"_node._root &amp;&amp; _attribute._attr\">_node,na</Item>\n      <Item Name=\"attribute\" Condition=\"_node._root &amp;&amp; _attribute._attr\">_attribute,na</Item>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xpath_node_set\">\n    <Expand>\n      <Item Name=\"type\">_type</Item>\n      <ArrayItems>\n        <Size>_end - _begin</Size>\n        <ValuePointer>_begin</ValuePointer>\n      </ArrayItems>\n    </Expand>\n  </Type>\n</AutoVisualizer>"
  },
  {
    "path": "external/pugixml/scripts/natvis/pugixml_compact.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"pugi::xml_node\">\n    <DisplayString Condition=\"_root\">{_root}</DisplayString>\n    <DisplayString Condition=\"!_root\">none</DisplayString>\n    <Expand>\n      <ExpandedItem Condition=\"_root\">_root</ExpandedItem>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_attribute\">\n    <DisplayString Condition=\"_attr\">{_attr}</DisplayString>\n    <DisplayString Condition=\"!_attr\">none</DisplayString>\n    <Expand>\n      <ExpandedItem Condition=\"_attr\">_attr</ExpandedItem>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_node_struct\">\n    <Expand>\n      <Item Name=\"type\">(pugi::xml_node_type)(header._flags &amp; 15)</Item>\n      <Item Name=\"name\" Condition=\"name._data\">name,na</Item>\n      <Item Name=\"value\" Condition=\"value._data\">value,na</Item>\n      \n      <Synthetic Name=\"attributes\" Condition=\"first_attribute._data\">\n        <DisplayString>...</DisplayString>\n        <Expand>\n          <CustomListItems>\n            <Variable Name=\"attribute_this\" InitialValue=\"(size_t)&amp;first_attribute\" />\n            <Variable Name=\"attribute_data\" InitialValue=\"first_attribute._data\" />\n            <Variable Name=\"attribute_data_copy\" InitialValue=\"attribute_data\" />\n            \n            <!-- first_attribute struct template arguments -->\n            <Variable Name=\"attribute_T1\" InitialValue=\"11\" />\n            <Variable Name=\"attribute_T2\" InitialValue=\"0\" />\n\n            <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n            <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n            \n            <!-- compact_get_page() -->\n            <Variable Name=\"_page\" InitialValue=\"*(char*)(attribute_this - attribute_T1)\" />\n            <Variable Name=\"page\" InitialValue=\"((attribute_this - attribute_T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(attribute_this - attribute_T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n            <!-- page->allocator->_hash -->\n            <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n            <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n            <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n            <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n            <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n            <!-- find() prolog -->\n            <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n            <Variable Name=\"h\" InitialValue=\"(unsigned)attribute_this\" />\n            <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n            <Variable Name=\"probe\" InitialValue=\"0\" />\n            <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n            <Variable Name=\"attribute_real\" InitialValue=\"(pugi::xml_attribute_struct*)0\" />\n\n            <!-- if _data < 255 -->\n            <Variable Name=\"attribute_short\" InitialValue=\"(pugi::xml_attribute_struct*)(((size_t)attribute_this &amp; ~(compact_alignment - 1)) + (attribute_data - 1 + attribute_T2) * compact_alignment)\" />\n\n            <Variable Name=\"number\" InitialValue=\"0\" />\n\n            <!-- Loop over all attributes -->\n            <Loop Condition=\"attribute_this &amp;&amp; attribute_data\">\n              <!-- find() hash -->\n              <Exec>h = h ^ (h >> 16)</Exec>\n              <Exec>h = h * (0x85ebca6bu)</Exec>\n              <Exec>h = h ^ (h >> 13)</Exec>\n              <Exec>h = h * (0xc2b2ae35u)</Exec>\n              <Exec>h = h ^ (h >> 16)</Exec>\n\n              <Exec>bucket = h &amp; hashmod</Exec>\n\n              <!-- find() loop -->\n              <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n                <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n                <If Condition=\"*probe_item == attribute_this || *probe_item == 0\">\n                  <Exec>attribute_real = *(pugi::xml_attribute_struct**)(probe_item + 1)</Exec><!--1 pointer offsetof(item_t, value)-->\n                  <Break/>\n                </If>\n\n                <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n                <Exec>probe++</Exec>\n              </Loop>\n\n              <Exec>attribute_data_copy = attribute_data</Exec>\n\n              <If Condition=\"attribute_data_copy &gt;= 255 &amp;&amp; attribute_real\">\n                <Item Name=\"[{number}]\">*attribute_real,view(child)</Item>\n                <Exec>attribute_this = (size_t)&amp;(*attribute_real).next_attribute</Exec>\n                <Exec>attribute_data = (*attribute_real).next_attribute._data</Exec>\n              </If>\n              <If Condition=\"attribute_data_copy &lt; 255 &amp;&amp; attribute_short\">\n                <Item Name=\"[{number}]\">*attribute_short,view(child)</Item>\n                <Exec>attribute_this = (size_t)&amp;(*attribute_short).next_attribute</Exec>\n                <Exec>attribute_data = (*attribute_short).next_attribute._data</Exec>\n              </If>\n\n              <!-- next_attribute struct template arguments -->\n              <Exec>attribute_T1 = 7</Exec>\n              <Exec>attribute_T2 = 0</Exec>\n\n              <!-- find() prolog again -->\n              <Exec>h = (unsigned)attribute_this</Exec>\n              <Exec>bucket = 0</Exec>\n\n              <Exec>probe = 0</Exec>\n              <Exec>probe_item = (size_t*)0</Exec>\n\n              <Exec>attribute_real = (pugi::xml_attribute_struct*)0</Exec>\n              <Exec>attribute_short = (pugi::xml_attribute_struct*)(((size_t)attribute_this &amp; ~(compact_alignment - 1)) + (attribute_data - 1 + attribute_T2) * compact_alignment)</Exec>\n\n              <Exec>number++</Exec>\n            </Loop>\n          </CustomListItems>\n        </Expand>\n      </Synthetic>\n      \n      <CustomListItems>\n        <Variable Name=\"child_this\" InitialValue=\"&amp;first_child\" />\n        <Variable Name=\"child_data\" InitialValue=\"first_child._data\" />\n        <Variable Name=\"child_data_copy\" InitialValue=\"child_data\" />\n\n        <!-- first_child struct template arguments -->\n        <Variable Name=\"child_T1\" InitialValue=\"8\" />\n        <Variable Name=\"child_T2\" InitialValue=\"0\" />\n\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n\n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(child_this - child_T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((child_this - child_T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(child_this - child_T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <!-- page->allocator->_hash -->\n        <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n        <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n        <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n        <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n        <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n        <!-- find() prolog -->\n        <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n        <Variable Name=\"h\" InitialValue=\"(unsigned)child_this\" />\n        <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n        <Variable Name=\"probe\" InitialValue=\"0\" />\n        <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n        <Variable Name=\"child_real\" InitialValue=\"(pugi::xml_node_struct*)0\" />\n\n        <!-- if _data < 255 -->\n        <Variable Name=\"child_short\" InitialValue=\"(pugi::xml_node_struct*)(((size_t)child_this &amp; ~(compact_alignment - 1)) + (child_data - 1 + child_T2) * compact_alignment)\" />\n\n        <Variable Name=\"number\" InitialValue=\"0\" />\n\n        <Loop Condition=\"child_this &amp;&amp; child_data\">\n          <!-- find() hash -->\n          <Exec>h = h ^ (h >> 16)</Exec>\n          <Exec>h = h * (0x85ebca6bu)</Exec>\n          <Exec>h = h ^ (h >> 13)</Exec>\n          <Exec>h = h * (0xc2b2ae35u)</Exec>\n          <Exec>h = h ^ (h >> 16)</Exec>\n\n          <Exec>bucket = h &amp; hashmod</Exec>\n\n          <!-- find() loop -->\n          <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n            <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n            <If Condition=\"*probe_item == child_this || *probe_item == 0\">\n              <Exec>child_real = *(pugi::xml_node_struct**)(probe_item + 1)</Exec><!--1 pointer offsetof(item_t, value)-->\n              <Break/>\n            </If>\n\n            <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n            <Exec>probe++</Exec>\n          </Loop>\n\n          <Exec>child_data_copy = child_data</Exec>\n\n          <If Condition=\"child_data_copy &gt;= 255 &amp;&amp; child_real\">\n            <Item Name=\"[{number}]\">*child_real,view(child)</Item>\n            <Exec>child_this = (size_t)&amp;(*child_real).next_sibling</Exec>\n            <Exec>child_data = (*child_real).next_sibling._data</Exec>\n          </If>\n          <If Condition=\"child_data_copy &lt; 255 &amp;&amp; child_short\">\n            <Item Name=\"[{number}]\">*child_short,view(child)</Item>\n            <Exec>child_this = (size_t)&amp;(*child_short).next_sibling</Exec>\n            <Exec>child_data = (*child_short).next_sibling._data</Exec>\n          </If>\n\n          <!-- next_sibling struct template arguments -->\n          <Exec>child_T1 = 10</Exec>\n          <Exec>child_T2 = 0</Exec>\n\n          <!-- find() prolog again -->\n          <Exec>h = (unsigned)child_this</Exec>\n          <Exec>bucket = 0</Exec>\n\n          <Exec>probe = 0</Exec>\n          <Exec>probe_item = (size_t*)0</Exec>\n\n          <Exec>child_real = (pugi::xml_node_struct*)0</Exec>\n          <Exec>child_short = (pugi::xml_node_struct*)(((size_t)child_this &amp; ~(compact_alignment - 1)) + (child_data - 1 + child_T2) * compact_alignment)</Exec>\n\n          <Exec>number++</Exec>\n        </Loop>\n      </CustomListItems>\n      \n      <Item Name=\"next_sibling\" ExcludeView=\"child\">next_sibling</Item>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xml_attribute_struct\">\n    <Expand>\n      <Item Name=\"name\">name,na</Item>\n      <Item Name=\"value\">value,na</Item>\n      \n      <CustomListItems ExcludeView=\"child\">\n        <Variable Name=\"attribute_this\" InitialValue=\"&amp;next_attribute\" />\n        <Variable Name=\"attribute_data\" InitialValue=\"next_attribute._data\" />\n\n        <!-- next_attribute struct template arguments -->\n        <Variable Name=\"attribute_T1\" InitialValue=\"7\" />\n        <Variable Name=\"attribute_T2\" InitialValue=\"0\" />\n\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n\n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(attribute_this - attribute_T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((attribute_this - attribute_T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(attribute_this - attribute_T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <!-- page->allocator->_hash -->\n        <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n        <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n        <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n        <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n        <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n        <!-- find() prolog -->\n        <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n        <Variable Name=\"h\" InitialValue=\"(unsigned)attribute_this\" />\n        <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n        <Variable Name=\"probe\" InitialValue=\"0\" />\n        <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n        <Variable Name=\"attribute_real\" InitialValue=\"(pugi::xml_attribute_struct*)0\" />\n\n        <!-- if _data < 255 -->\n        <Variable Name=\"attribute_short\" InitialValue=\"(pugi::xml_attribute_struct*)(((size_t)attribute_this &amp; ~(compact_alignment - 1)) + (attribute_data - 1 + attribute_T2) * compact_alignment)\" />\n\n        <!-- find() hash -->\n        <Exec>h = h ^ (h >> 16)</Exec>\n        <Exec>h = h * (0x85ebca6bu)</Exec>\n        <Exec>h = h ^ (h >> 13)</Exec>\n        <Exec>h = h * (0xc2b2ae35u)</Exec>\n        <Exec>h = h ^ (h >> 16)</Exec>\n\n        <Exec>bucket = h &amp; hashmod</Exec>\n\n        <!-- find() loop -->\n        <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n          <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n          <If Condition=\"*probe_item == attribute_this || *probe_item == 0\">\n            <Exec>attribute_real = *(pugi::xml_attribute_struct**)(probe_item + 1)</Exec><!--1 pointer offsetof(item_t, value)-->\n            <Break/>\n          </If>\n\n          <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n          <Exec>probe++</Exec>\n        </Loop>\n\n        <If Condition=\"attribute_data &gt;= 255 &amp;&amp; attribute_real\">\n          <Item Name=\"next_attribute\">*attribute_real</Item>\n        </If>\n        <If Condition=\"attribute_data != 0 &amp;&amp; attribute_data &lt; 255 &amp;&amp; attribute_short\">\n          <Item Name=\"next_attribute\">*attribute_short</Item>\n        </If>\n      </CustomListItems>\n    </Expand>\n  </Type>\n\n  <Type Name=\"pugi::impl::`anonymous-namespace'::compact_string&lt;*,*&gt;\">\n    <Expand HideRawView=\"1\">\n      <CustomListItems Condition=\"_data &amp;&amp; _data &lt; 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(this - $T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((this - $T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(this - $T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <Variable Name=\"compact_string_base\" InitialValue=\"*(size_t*)(page + 5 * sizeof(void*))\" /><!-- 5 pointer offsetof(page, compact_string_base)-->\n        <Variable Name=\"base\" InitialValue=\"this - $T2\" />\n        <Variable Name=\"offset\" InitialValue=\"((*(short*)base - 1) &lt;&lt; 7) + (_data - 1)\" />\n        \n        <Item Name=\"value\">(pugi::char_t*)(compact_string_base + offset * sizeof(pugi::char_t)),na</Item>\n      </CustomListItems>\n      \n      <CustomListItems Condition=\"_data &amp;&amp; _data &gt;= 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(this - $T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((this - $T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(this - $T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <!-- page->allocator->_hash -->\n        <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n        <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n        <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n        <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n        <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n        <!-- find() prolog -->\n        <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n        <Variable Name=\"h\" InitialValue=\"(unsigned)this\" />\n        <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n        <Variable Name=\"probe\" InitialValue=\"0\" />\n        <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n        <!-- find() hash -->\n        <Exec>h = h ^ (h >> 16)</Exec>\n        <Exec>h = h * (0x85ebca6bu)</Exec>\n        <Exec>h = h ^ (h >> 13)</Exec>\n        <Exec>h = h * (0xc2b2ae35u)</Exec>\n        <Exec>h = h ^ (h >> 16)</Exec>\n\n        <Exec>bucket = h &amp; hashmod</Exec>\n\n        <!-- find() loop -->\n        <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n          <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n          <If Condition=\"*probe_item == this || *probe_item == 0\">\n            <Item Name=\"value\">*(pugi::char_t**)(probe_item + 1)</Item><!--1 pointer offsetof(item_t, value)-->\n            <Break/>\n          </If>\n\n          <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n          <Exec>probe++</Exec>\n        </Loop>\n      </CustomListItems>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::impl::`anonymous-namespace'::compact_pointer&lt;pugi::xml_node_struct,*,*&gt;\">\n    <DisplayString Condition=\"!_data\">nullptr</DisplayString>\n    <DisplayString Condition=\"_data\">...</DisplayString>\n    \n    <Expand HideRawView=\"1\">\n      <CustomListItems Condition=\"_data &amp;&amp; _data &lt; 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <Item Name=\"value\">*(pugi::xml_node_struct*)(((size_t)this &amp; ~(compact_alignment - 1)) + (_data - 1 + $T2) * compact_alignment)</Item>\n      </CustomListItems>\n      \n      <CustomListItems Condition=\"_data &amp;&amp; _data &gt;= 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(this - $T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((this - $T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(this - $T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <!-- page->allocator->_hash -->\n        <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n        <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n        <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n        <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n        <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n        <!-- find() prolog -->\n        <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n        <Variable Name=\"h\" InitialValue=\"(unsigned)this\" />\n        <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n        <Variable Name=\"probe\" InitialValue=\"0\" />\n        <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n        <!-- find() hash -->\n        <Exec>h = h ^ (h >> 16)</Exec>\n        <Exec>h = h * (0x85ebca6bu)</Exec>\n        <Exec>h = h ^ (h >> 13)</Exec>\n        <Exec>h = h * (0xc2b2ae35u)</Exec>\n        <Exec>h = h ^ (h >> 16)</Exec>\n\n        <Exec>bucket = h &amp; hashmod</Exec>\n\n        <!-- find() loop -->\n        <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n          <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n          <If Condition=\"*probe_item == this || *probe_item == 0\">\n            <Item Name=\"value\">**(pugi::xml_node_struct**)(probe_item + 1)</Item><!--1 pointer offsetof(item_t, value)-->\n            <Break/>\n          </If>\n\n          <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n          <Exec>probe++</Exec>\n        </Loop>\n      </CustomListItems>\n    </Expand>\n  </Type>\n\n  <Type Name=\"pugi::impl::`anonymous-namespace'::compact_pointer&lt;pugi::xml_attribute_struct,*,*&gt;\">\n    <DisplayString Condition=\"!_data\">nullptr</DisplayString>\n    <DisplayString Condition=\"_data\">...</DisplayString>\n    \n    <Expand HideRawView=\"1\">\n      <CustomListItems Condition=\"_data &amp;&amp; _data &lt; 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <Item Name=\"value\">*(pugi::xml_attribute_struct*)(((size_t)this &amp; ~(compact_alignment - 1)) + (_data - 1 + $T2) * compact_alignment)</Item>\n      </CustomListItems>\n      \n      <CustomListItems Condition=\"_data &amp;&amp; _data &gt;= 255\">\n        <Variable Name=\"compact_alignment_log2\" InitialValue=\"2\" />\n        <Variable Name=\"compact_alignment\" InitialValue=\"1 &lt;&lt; compact_alignment_log2\" />\n        \n        <!-- compact_get_page() -->\n        <Variable Name=\"_page\" InitialValue=\"*(char*)(this - $T1)\" />\n        <Variable Name=\"page\" InitialValue=\"((this - $T1 - (_page &lt;&lt; compact_alignment_log2)) - *(unsigned*)(this - $T1 - (_page &lt;&lt; compact_alignment_log2)))\" />\n\n        <!-- page->allocator->_hash -->\n        <Variable Name=\"allocator\" InitialValue=\"*(size_t*)page\" />\n        <Variable Name=\"_hash\" InitialValue=\"*(size_t*)(allocator + 2 * sizeof(size_t))\" /><!--2 pointer offsetof(allocator, _hash)-->\n        <Variable Name=\"_items\" InitialValue=\"*(size_t*)_hash\" />\n        <Variable Name=\"_capacity\" InitialValue=\"*((size_t*)_hash + 1)\" /><!--1 pointer offsetof(_hash, _capacity)-->\n        <Variable Name=\"_count\" InitialValue=\"*((size_t*)_hash + 2)\" /><!--2 pointer offsetof(_hash, _count)-->\n\n        <!-- find() prolog -->\n        <Variable Name=\"hashmod\" InitialValue=\"_capacity - 1\" />\n\n        <Variable Name=\"h\" InitialValue=\"(unsigned)this\" />\n        <Variable Name=\"bucket\" InitialValue=\"0\" />\n\n        <Variable Name=\"probe\" InitialValue=\"0\" />\n        <Variable Name=\"probe_item\" InitialValue=\"(size_t*)0\" />\n\n        <!-- find() hash -->\n        <Exec>h = h ^ (h >> 16)</Exec>\n        <Exec>h = h * (0x85ebca6bu)</Exec>\n        <Exec>h = h ^ (h >> 13)</Exec>\n        <Exec>h = h * (0xc2b2ae35u)</Exec>\n        <Exec>h = h ^ (h >> 16)</Exec>\n\n        <Exec>bucket = h &amp; hashmod</Exec>\n\n        <!-- find() loop -->\n        <Loop Condition=\"probe &lt;= hashmod &amp;&amp;_capacity\">\n          <Exec>probe_item = (size_t*)_items + bucket * 2</Exec><!--2 pointer sizeof(item_t)-->\n\n          <If Condition=\"*probe_item == this || *probe_item == 0\">\n            <Item Name=\"value\">**(pugi::xml_attribute_struct**)(probe_item + 1)</Item><!--1 pointer offsetof(item_t, value)-->\n            <Break/>\n          </If>\n\n          <Exec>bucket = (bucket + probe + 1) &amp; hashmod</Exec>\n          <Exec>probe++</Exec>\n        </Loop>\n      </CustomListItems>\n    </Expand>\n  </Type>\n\n  <Type Name=\"pugi::xpath_node\">\n    <DisplayString Condition=\"_node._root &amp;&amp; _attribute._attr\">{_node,na} {_attribute,na}</DisplayString>\n    <DisplayString Condition=\"_node._root\">{_node,na}</DisplayString>\n    <DisplayString Condition=\"_attribute._attr\">{_attribute}</DisplayString>\n    <DisplayString>empty</DisplayString>\n    \n    <Expand HideRawView=\"1\">\n      <ExpandedItem Condition=\"_node._root &amp;&amp; !_attribute._attr\">_node</ExpandedItem>\n      <ExpandedItem Condition=\"!_node._root &amp;&amp; _attribute._attr\">_attribute</ExpandedItem>\n      \n      <Item Name=\"node\" Condition=\"_node._root &amp;&amp; _attribute._attr\">_node,na</Item>\n      <Item Name=\"attribute\" Condition=\"_node._root &amp;&amp; _attribute._attr\">_attribute,na</Item>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"pugi::xpath_node_set\">\n    <Expand>\n      <Item Name=\"type\">_type</Item>\n      <ArrayItems>\n        <Size>_end - _begin</Size>\n        <ValuePointer>_begin</ValuePointer>\n      </ArrayItems>\n    </Expand>\n  </Type>\n</AutoVisualizer>"
  },
  {
    "path": "external/pugixml/scripts/nuget/pugixml.nuspec",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd\">\n  <metadata>\n    <id>pugixml</id>\n    <version>1.15.0</version>\n    <title>pugixml</title>\n    <authors>Arseny Kapoulkine</authors>\n    <owners>Arseny Kapoulkine</owners>\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <license type=\"expression\">MIT</license>\n    <projectUrl>https://pugixml.org/</projectUrl>\n    <description>pugixml is a C++ XML processing library, which consists of a DOM-like interface with rich traversal/modification capabilities, an extremely fast XML parser which constructs the DOM tree from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven tree queries. Full Unicode support is also available, with Unicode interface variants and conversions between different Unicode encodings (which happen automatically during parsing/saving).\npugixml is used by a lot of projects, both open-source and proprietary, for performance and easy-to-use interface.\nThis package contains builds for VS2013, VS2015, VS2017, VS2019 and VS2022, for both statically linked and DLL CRT; you can switch the CRT linkage in Project -> Properties -> Referenced Packages -> pugixml.</description>\n    <summary>Light-weight, simple and fast XML parser for C++ with XPath support</summary>\n    <releaseNotes>https://pugixml.org/docs/manual.html#changes</releaseNotes>\n    <copyright>Copyright (c) 2006-2025 Arseny Kapoulkine</copyright>\n    <tags>native nativepackage</tags>\n  </metadata>\n</package>\n"
  },
  {
    "path": "external/pugixml/scripts/nuget_build.ps1",
    "content": "function Run-Command([string]$cmd)\n{\n\tInvoke-Expression $cmd\n\tif ($LastExitCode) { exit $LastExitCode }\n}\n\nfunction Force-Copy([string]$from, [string]$to)\n{\n\tWrite-Host $from \"->\" $to\n\tNew-Item -Force $to | Out-Null\n\tCopy-Item -Force $from $to\n\tif (! $?) { exit 1 }\n}\n\nfunction Build-Version([string]$vs, [string]$toolset, [string]$linkage)\n{\n\t$prjsuffix = if ($linkage -eq \"static\") { \"_static\" } else { \"\" }\n\t$cfgsuffix = if ($linkage -eq \"static\") { \"Static\" } else { \"\" }\n\n\tforeach ($configuration in \"Debug\",\"Release\")\n\t{\n\t\tRun-Command \"msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x86 /v:minimal /nologo\"\n\t\tRun-Command \"msbuild pugixml_$vs$prjsuffix.vcxproj /t:Rebuild /p:Configuration=$configuration /p:Platform=x64 /v:minimal /nologo\"\n\n\t\tForce-Copy \"$vs/Win32_$configuration$cfgsuffix/pugixml.lib\" \"nuget/build/native/lib/Win32/$toolset/$linkage/$configuration/pugixml.lib\"\n\t\tForce-Copy \"$vs/x64_$configuration$cfgsuffix/pugixml.lib\" \"nuget/build/native/lib/x64/$toolset/$linkage/$configuration/pugixml.lib\"\n\t}\n}\n\nPush-Location\n$scriptdir = Split-Path $MyInvocation.MyCommand.Path\ncd $scriptdir\n\nForce-Copy \"../src/pugiconfig.hpp\" \"nuget/build/native/include/pugiconfig.hpp\"\nForce-Copy \"../src/pugixml.hpp\" \"nuget/build/native/include/pugixml.hpp\"\nForce-Copy \"../src/pugixml.cpp\" \"nuget/build/native/include/pugixml.cpp\"\n\nif ($args[0] -eq 2022){\n\tBuild-Version \"vs2022\" \"v143\" \"dynamic\"\n\tBuild-Version \"vs2022\" \"v143\" \"static\"\n\n} elseif ($args[0] -eq 2019){\n\tBuild-Version \"vs2019\" \"v142\" \"dynamic\"\n\tBuild-Version \"vs2019\" \"v142\" \"static\"\n\n} elseif ($args[0] -eq 2017){\n\tBuild-Version \"vs2017\" \"v141\" \"dynamic\"\n\tBuild-Version \"vs2017\" \"v141\" \"static\"\n\n\tBuild-Version \"vs2015\" \"v140\" \"dynamic\"\n\tBuild-Version \"vs2015\" \"v140\" \"static\"\n\n\tBuild-Version \"vs2013\" \"v120\" \"dynamic\"\n\tBuild-Version \"vs2013\" \"v120\" \"static\"\n\n} elseif($args[0] -eq 2015){\n\tBuild-Version \"vs2015\" \"v140\" \"dynamic\"\n\tBuild-Version \"vs2015\" \"v140\" \"static\"\n\n\tBuild-Version \"vs2013\" \"v120\" \"dynamic\"\n\tBuild-Version \"vs2013\" \"v120\" \"static\"\n\n} elseif($args[0] -eq 2013){\n\tBuild-Version \"vs2013\" \"v120\" \"dynamic\"\n\tBuild-Version \"vs2013\" \"v120\" \"static\"\n}\n\nRun-Command \"nuget pack nuget\"\n\nPop-Location\n"
  },
  {
    "path": "external/pugixml/scripts/premake4.lua",
    "content": "-- Reset RNG seed to get consistent results across runs (i.e. XCode)\nmath.randomseed(12345)\n\nlocal static = _ARGS[1] == 'static'\nlocal action = premake.action.current()\n\nif string.startswith(_ACTION, \"vs\") then\n\tif action then\n\t\t-- Disable solution generation\n\t\tfunction action.onsolution(sln)\n\t\t\tsln.vstudio_configs = premake.vstudio_buildconfigs(sln)\n\t\tend\n\n\t\t-- Rename output file\n\t\tfunction action.onproject(prj)\n            local name = \"%%_\" .. _ACTION .. (static and \"_static\" or \"\")\n\n            if static then\n                for k, v in pairs(prj.project.__configs) do\n                    v.objectsdir = v.objectsdir .. \"Static\"\n                end\n            end\n\n            if _ACTION == \"vs2010\" then\n                premake.generate(prj, name .. \".vcxproj\", premake.vs2010_vcxproj)\n            else\n                premake.generate(prj, name .. \".vcproj\", premake.vs200x_vcproj)\n            end\n\t\tend\n\tend\nelseif _ACTION == \"codeblocks\" then\n\taction.onsolution = nil\n\n\tfunction action.onproject(prj)\n\t\tpremake.generate(prj, \"%%_\" .. _ACTION .. \".cbp\", premake.codeblocks_cbp)\n\tend\nelseif _ACTION == \"codelite\" then\n\taction.onsolution = nil\n\n\tfunction action.onproject(prj)\n\t\tpremake.generate(prj, \"%%_\" .. _ACTION .. \".project\", premake.codelite_project)\n\tend\nend\n\nsolution \"pugixml\"\n\tobjdir(_ACTION)\n\ttargetdir(_ACTION)\n\nif string.startswith(_ACTION, \"vs\") then\n\tif _ACTION ~= \"vs2002\" and _ACTION ~= \"vs2003\" then\n\t\tplatforms { \"x32\", \"x64\" }\n\n\t\tconfiguration \"x32\" targetdir(_ACTION .. \"/x32\")\n\t\tconfiguration \"x64\" targetdir(_ACTION .. \"/x64\")\n\tend\n\n\tconfigurations { \"Debug\", \"Release\" }\n\n    if static then\n        configuration \"Debug\" targetsuffix \"sd\"\n        configuration \"Release\" targetsuffix \"s\"\n    else\n        configuration \"Debug\" targetsuffix \"d\"\n    end\nelse\n\tif _ACTION == \"xcode3\" then\n\t\tplatforms \"universal\"\n\tend\n\n\tconfigurations { \"Debug\", \"Release\" }\n\n\tconfiguration \"Debug\" targetsuffix \"d\"\nend\n\nproject \"pugixml\"\n\tkind \"StaticLib\"\n\tlanguage \"C++\"\n\tfiles { \"../src/pugixml.hpp\", \"../src/pugiconfig.hpp\", \"../src/pugixml.cpp\" }\n\tflags { \"NoPCH\", \"NoMinimalRebuild\", \"NoEditAndContinue\", \"Symbols\" }\n\tuuid \"89A1E353-E2DC-495C-B403-742BE206ACED\"\n\nconfiguration \"Debug\"\n\tdefines { \"_DEBUG\" }\n\nconfiguration \"Release\"\n\tdefines { \"NDEBUG\" }\n\tflags { \"Optimize\" }\n\nif static then\n    configuration \"*\"\n        flags { \"StaticRuntime\" }\nend\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml-config.cmake.in",
    "content": "@PACKAGE_INIT@\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/pugixml-targets.cmake\")\n\n# If the user is not requiring 1.11 (either by explicitly requesting an older\n# version or not requesting one at all), provide the old imported target name\n# for compatibility.\nif (NOT TARGET pugixml AND (NOT DEFINED PACKAGE_FIND_VERSION OR PACKAGE_FIND_VERSION VERSION_LESS \"1.11\"))\n  add_library(pugixml INTERFACE IMPORTED)\n  # Equivalent to target_link_libraries INTERFACE, but compatible with CMake 3.10\n  set_target_properties(pugixml PROPERTIES INTERFACE_LINK_LIBRARIES pugixml::pugixml)\nendif ()\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml.pc.in",
    "content": "prefix=@CMAKE_INSTALL_PREFIX@\nexec_prefix=${prefix}\nincludedir=@PUGIXML_PC_INCLUDEDIR@\nlibdir=@PUGIXML_PC_LIBDIR@\n\nName: pugixml\nDescription: Light-weight, simple and fast XML parser for C++ with XPath support.\nURL: https://pugixml.org/\nVersion: @pugixml_VERSION@\nCflags: -I${includedir}\nLibs: -L${libdir} -lpugixml@LIB_POSTFIX@\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name         = \"pugixml\"\n  s.version      = \"1.15\"\n  s.summary      = \"C++ XML parser library.\"\n  s.homepage     = \"https://pugixml.org\"\n  s.license      = \"MIT\"\n  s.author       = { \"Arseny Kapoulkine\" => \"arseny.kapoulkine@gmail.com\" }\n  s.platform     = :ios, \"7.0\"\n  \n  s.source = { :git => \"https://github.com/zeux/pugixml.git\", :tag => \"v\" + s.version.to_s }\n\n  s.source_files  = \"src/**/*.{hpp,cpp}\"\n  s.header_mappings_dir = \"src\"\nend\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 45;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0424128F67AB5C730232235E /* pugixml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 47481C4F0E03673E0E780637 /* pugixml.cpp */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0B66463C5F896E6449051D38 /* pugiconfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = \"pugiconfig.hpp\"; path = \"pugiconfig.hpp\"; sourceTree = \"<group>\"; };\n\t\t47481C4F0E03673E0E780637 /* pugixml.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = \"pugixml.cpp\"; path = \"pugixml.cpp\"; sourceTree = \"<group>\"; };\n\t\t6C911F0460FC44CD3B1B5624 /* pugixml.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = \"pugixml.hpp\"; path = \"pugixml.hpp\"; sourceTree = \"<group>\"; };\n\t\t1DA04ADC64C3566D16C45B6D /* libpugixmld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = \"libpugixmld.a\"; path = \"libpugixmld.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t2BA00212518037166623673F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t19E0517F3CF26ED63AE23641 /* pugixml */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t578963B4309E714F05E01D71 /* src */,\n\t\t\t\t219F66186DDF392149043810 /* Products */,\n\t\t\t);\n\t\t\tname = \"pugixml\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t578963B4309E714F05E01D71 /* src */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0B66463C5F896E6449051D38 /* pugiconfig.hpp */,\n\t\t\t\t47481C4F0E03673E0E780637 /* pugixml.cpp */,\n\t\t\t\t6C911F0460FC44CD3B1B5624 /* pugixml.hpp */,\n\t\t\t);\n\t\t\tname = \"src\";\n\t\t\tpath = ../src;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t219F66186DDF392149043810 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1DA04ADC64C3566D16C45B6D /* libpugixmld.a */,\n\t\t\t);\n\t\t\tname = \"Products\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t6B55152571905B6C3A6F39D0 /* pugixml */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget \"pugixml\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t6CA66B9B6252229A36E8733C /* Resources */,\n\t\t\t\t287808486FBF545206A47CC1 /* Sources */,\n\t\t\t\t2BA00212518037166623673F /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"pugixml\";\n\t\t\tproductName = \"pugixml\";\n\t\t\tproductReference = 1DA04ADC64C3566D16C45B6D /* libpugixmld.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t08FB7793FE84155DC02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tbuildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject \"pugixml\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.1\";\n\t\t\thasScannedForEncodings = 1;\n\t\t\tmainGroup = 19E0517F3CF26ED63AE23641 /* pugixml */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t6B55152571905B6C3A6F39D0 /* libpugixmld.a */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t6CA66B9B6252229A36E8733C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t287808486FBF545206A47CC1 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0424128F67AB5C730232235E /* pugixml.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4FDB54E4253E36FC55CE27E8 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCONFIGURATION_BUILD_DIR = xcode3;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_MODEL_TUNING = G5;\n\t\t\t\tINSTALL_PATH = /usr/local/lib;\n\t\t\t\tPRODUCT_NAME = \"pugixmld\";\n\t\t\t};\n\t\t\tname = \"Debug\";\n\t\t};\n\t\t0A4C28F553990E0405306C15 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCONFIGURATION_BUILD_DIR = xcode3;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_MODEL_TUNING = G5;\n\t\t\t\tINSTALL_PATH = /usr/local/lib;\n\t\t\t\tPRODUCT_NAME = \"pugixml\";\n\t\t\t};\n\t\t\tname = \"Release\";\n\t\t};\n\t\t65DB0F6D27EA20852B6E3BB4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_32_64_BIT)\";\n\t\t\t\tCONFIGURATION_BUILD_DIR = \"$(SYMROOT)\";\n\t\t\t\tCONFIGURATION_TEMP_DIR = \"$(OBJROOT)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"_DEBUG\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tOBJROOT = \"xcode3/Universal/Debug\";\n\t\t\t\tONLY_ACTIVE_ARCH = NO;\n\t\t\t\tPREBINDING = NO;\n\t\t\t\tSYMROOT = \"xcode3\";\n\t\t\t};\n\t\t\tname = \"Debug\";\n\t\t};\n\t\t5314084032B57C1A11945858 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_32_64_BIT)\";\n\t\t\t\tCONFIGURATION_BUILD_DIR = \"$(SYMROOT)\";\n\t\t\t\tCONFIGURATION_TEMP_DIR = \"$(OBJROOT)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = s;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"NDEBUG\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tOBJROOT = \"xcode3/Universal/Release\";\n\t\t\t\tONLY_ACTIVE_ARCH = NO;\n\t\t\t\tPREBINDING = NO;\n\t\t\t\tSYMROOT = \"xcode3\";\n\t\t\t};\n\t\t\tname = \"Release\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t73BF376C14AA1ECC0AC517ED /* Build configuration list for PBXNativeTarget \"libpugixmld.a\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4FDB54E4253E36FC55CE27E8 /* Debug */,\n\t\t\t\t0A4C28F553990E0405306C15 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = \"Debug\";\n\t\t};\n\t\t1DEB928908733DD80010E9CD /* Build configuration list for PBXProject \"pugixml\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65DB0F6D27EA20852B6E3BB4 /* Debug */,\n\t\t\t\t5314084032B57C1A11945858 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = \"Debug\";\n\t\t};\n/* End XCConfigurationList section */\n\n\t};\n\trootObject = 08FB7793FE84155DC02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_airplay.mkf",
    "content": "includepaths\n{\n\"../src\"\n}\n\nfiles\n{\n(\"../src\")\npugiconfig.hpp\npugixml.cpp\npugixml.hpp\n}\n\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_codeblocks.cbp",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<CodeBlocks_project_file>\n\t<FileVersion major=\"1\" minor=\"6\" />\n\t<Project>\n\t\t<Option title=\"pugixml\" />\n\t\t<Option pch_mode=\"2\" />\n\t\t<Option compiler=\"gcc\" />\n\t\t<Build>\n\t\t\t<Target title=\"Debug\">\n\t\t\t\t<Option output=\"codeblocks/libpugixmld.a\" prefix_auto=\"0\" extension_auto=\"0\" />\n\t\t\t\t<Option object_output=\"codeblocks/Debug\" />\n\t\t\t\t<Option type=\"2\" />\n\t\t\t\t<Option compiler=\"gcc\" />\n\t\t\t\t<Compiler>\n\t\t\t\t\t<Add option=\"-g\" />\n\t\t\t\t\t<Add option=\"-D_DEBUG\" />\n\t\t\t\t</Compiler>\n\t\t\t\t<Linker>\n\t\t\t\t</Linker>\n\t\t\t</Target>\n\t\t\t<Target title=\"Release\">\n\t\t\t\t<Option output=\"codeblocks/libpugixml.a\" prefix_auto=\"0\" extension_auto=\"0\" />\n\t\t\t\t<Option object_output=\"codeblocks/Release\" />\n\t\t\t\t<Option type=\"2\" />\n\t\t\t\t<Option compiler=\"gcc\" />\n\t\t\t\t<Compiler>\n\t\t\t\t\t<Add option=\"-g\" />\n\t\t\t\t\t<Add option=\"-O2\" />\n\t\t\t\t\t<Add option=\"-DNDEBUG\" />\n\t\t\t\t</Compiler>\n\t\t\t\t<Linker>\n\t\t\t\t</Linker>\n\t\t\t</Target>\n\t\t</Build>\n\t\t<Unit filename=\"../src/pugixml.hpp\">\n\t\t</Unit>\n\t\t<Unit filename=\"../src/pugiconfig.hpp\">\n\t\t</Unit>\n\t\t<Unit filename=\"../src/pugixml.cpp\">\n\t\t</Unit>\n\t\t<Extensions />\n\t</Project>\n</CodeBlocks_project_file>\n\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_codelite.project",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<CodeLite_Project Name=\"pugixml\">\n  <VirtualDirectory Name=\"src\">\n    <File Name=\"../src/pugixml.hpp\"/>\n    <File Name=\"../src/pugiconfig.hpp\"/>\n    <File Name=\"../src/pugixml.cpp\"/>\n  </VirtualDirectory>\n  <Settings Type=\"Static Library\">\n    <Configuration Name=\"Debug\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Static Library\">\n      <General OutputFile=\"codelite/libpugixmld.a\" IntermediateDirectory=\"codelite/Debug\" Command=\"./libpugixmld.a\" CommandArguments=\"\" WorkingDirectory=\"codelite\" PauseExecWhenProcTerminates=\"yes\"/>\n      <Compiler Required=\"yes\" Options=\"-g\">\n        <Preprocessor Value=\"_DEBUG\"/>\n      </Compiler>\n      <Linker Required=\"yes\" Options=\"\">\n      </Linker>\n      <ResourceCompiler Required=\"no\" Options=\"\"/>\n      <CustomBuild Enabled=\"no\">\n        <CleanCommand></CleanCommand>\n        <BuildCommand></BuildCommand>\n        <SingleFileCommand></SingleFileCommand>\n        <MakefileGenerationCommand></MakefileGenerationCommand>\n        <ThirdPartyToolName>None</ThirdPartyToolName>\n        <WorkingDirectory></WorkingDirectory>\n      </CustomBuild>\n      <AdditionalRules>\n        <CustomPostBuild></CustomPostBuild>\n        <CustomPreBuild></CustomPreBuild>\n      </AdditionalRules>\n    </Configuration>\n    <Configuration Name=\"Release\" CompilerType=\"gnu g++\" DebuggerType=\"GNU gdb debugger\" Type=\"Static Library\">\n      <General OutputFile=\"codelite/libpugixml.a\" IntermediateDirectory=\"codelite/Release\" Command=\"./libpugixml.a\" CommandArguments=\"\" WorkingDirectory=\"codelite\" PauseExecWhenProcTerminates=\"yes\"/>\n      <Compiler Required=\"yes\" Options=\"-g;-O2\">\n        <Preprocessor Value=\"NDEBUG\"/>\n      </Compiler>\n      <Linker Required=\"yes\" Options=\"\">\n      </Linker>\n      <ResourceCompiler Required=\"no\" Options=\"\"/>\n      <CustomBuild Enabled=\"no\">\n        <CleanCommand></CleanCommand>\n        <BuildCommand></BuildCommand>\n        <SingleFileCommand></SingleFileCommand>\n        <MakefileGenerationCommand></MakefileGenerationCommand>\n        <ThirdPartyToolName>None</ThirdPartyToolName>\n        <WorkingDirectory></WorkingDirectory>\n      </CustomBuild>\n      <AdditionalRules>\n        <CustomPostBuild></CustomPostBuild>\n        <CustomPreBuild></CustomPreBuild>\n      </AdditionalRules>\n    </Configuration>\n  </Settings>\n  <Dependencies name=\"Debug\">\n  </Dependencies>\n  <Dependencies name=\"Release\">\n  </Dependencies>\n</CodeLite_Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_dll.rc",
    "content": "#include <winver.h>\n\n#define PUGIXML_VERSION_MAJOR 1\n#define PUGIXML_VERSION_MINOR 15\n#define PUGIXML_VERSION_PATCH 0\n#define PUGIXML_VERSION_NUMBER \"1.15.0\\0\"\n\n#if defined(GCC_WINDRES) || defined(__MINGW32__) || defined(__CYGWIN__)\nVS_VERSION_INFO\t\tVERSIONINFO\n#else\nVS_VERSION_INFO\t\tVERSIONINFO\tMOVEABLE IMPURE LOADONCALL DISCARDABLE\n#endif\n  FILEVERSION\t\tPUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0\n  PRODUCTVERSION\tPUGIXML_VERSION_MAJOR,PUGIXML_VERSION_MINOR,PUGIXML_VERSION_PATCH,0\n  FILEFLAGSMASK\t\tVS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n  FILEFLAGS\t\t1\n#else\n  FILEFLAGS\t\t0\n#endif\n  FILEOS\t\tVOS__WINDOWS32\n  FILETYPE\t\tVFT_DLL\n  FILESUBTYPE\t\t0\t// not used\nBEGIN\n  BLOCK \"StringFileInfo\"\n  BEGIN\n    BLOCK \"040904E4\"\n    //language ID = U.S. English, char set = Windows, Multilingual\n    BEGIN\n      VALUE \"CompanyName\",\t\"zeux/pugixml\\0\"\n      VALUE \"FileDescription\",\t\"pugixml library\\0\"\n      VALUE \"FileVersion\",\tPUGIXML_VERSION_NUMBER\n      VALUE \"InternalName\",\t\"pugixml.dll\\0\"\n      VALUE \"LegalCopyright\",\t\"Copyright (C) 2006-2025, by Arseny Kapoulkine\\0\"\n      VALUE \"OriginalFilename\",\t\"pugixml.dll\\0\"\n      VALUE \"ProductName\",\t\"pugixml\\0\"\n      VALUE \"ProductVersion\",\tPUGIXML_VERSION_NUMBER\n      VALUE \"Comments\",\t\t\"For more information visit https://github.com/zeux/pugixml/\\0\"\n    END\n  END\n  BLOCK \"VarFileInfo\"\n  BEGIN\n    VALUE \"Translation\", 0x0409, 1252\n  END\nEND\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2005.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"8.00\"\n\tName=\"pugixml\"\n\tProjectGUID=\"{89A1E353-E2DC-495C-B403-742BE206ACED}\"\n\tRootNamespace=\"pugixml\"\n\tKeyword=\"Win32Proj\"\n\t>\n\t<Platforms>\n\t\t<Platform\n\t\t\tName=\"Win32\"\n\t\t/>\n\t\t<Platform\n\t\t\tName=\"x64\"\n\t\t/>\n\t</Platforms>\n\t<ToolFiles>\n\t</ToolFiles>\n\t<Configurations>\n\t\t<Configuration\n\t\t\tName=\"Debug|Win32\"\n\t\t\tOutputDirectory=\"vs2005\\x32\"\n\t\t\tIntermediateDirectory=\"vs2005\\x32\\Debug\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"3\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmld.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmld.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Debug|x64\"\n\t\t\tOutputDirectory=\"vs2005\\x64\"\n\t\t\tIntermediateDirectory=\"vs2005\\x64\\Debug\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"3\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmld.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmld.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|Win32\"\n\t\t\tOutputDirectory=\"vs2005\\x32\"\n\t\t\tIntermediateDirectory=\"vs2005\\x32\\Release\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"2\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixml.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixml.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|x64\"\n\t\t\tOutputDirectory=\"vs2005\\x64\"\n\t\t\tIntermediateDirectory=\"vs2005\\x64\\Release\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"2\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixml.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixml.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t</Configurations>\n\t<References>\n\t</References>\n\t<Files>\n\t\t<Filter\n\t\t\tName=\"src\"\n\t\t\tFilter=\"\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugiconfig.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t</Files>\n\t<Globals>\n\t</Globals>\n</VisualStudioProject>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2005_static.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"8.00\"\n\tName=\"pugixml\"\n\tProjectGUID=\"{89A1E353-E2DC-495C-B403-742BE206ACED}\"\n\tRootNamespace=\"pugixml\"\n\tKeyword=\"Win32Proj\"\n\t>\n\t<Platforms>\n\t\t<Platform\n\t\t\tName=\"Win32\"\n\t\t/>\n\t\t<Platform\n\t\t\tName=\"x64\"\n\t\t/>\n\t</Platforms>\n\t<ToolFiles>\n\t</ToolFiles>\n\t<Configurations>\n\t\t<Configuration\n\t\t\tName=\"Debug|Win32\"\n\t\t\tOutputDirectory=\"vs2005\\x32\"\n\t\t\tIntermediateDirectory=\"vs2005\\x32\\DebugStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"1\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmlsd.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmlsd.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Debug|x64\"\n\t\t\tOutputDirectory=\"vs2005\\x64\"\n\t\t\tIntermediateDirectory=\"vs2005\\x64\\DebugStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"1\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmlsd.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmlsd.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|Win32\"\n\t\t\tOutputDirectory=\"vs2005\\x32\"\n\t\t\tIntermediateDirectory=\"vs2005\\x32\\ReleaseStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"0\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmls.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmls.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|x64\"\n\t\t\tOutputDirectory=\"vs2005\\x64\"\n\t\t\tIntermediateDirectory=\"vs2005\\x64\\ReleaseStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"0\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDetect64BitPortabilityProblems=\"true\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmls.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmls.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t</Configurations>\n\t<References>\n\t</References>\n\t<Files>\n\t\t<Filter\n\t\t\tName=\"src\"\n\t\t\tFilter=\"\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugiconfig.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t</Files>\n\t<Globals>\n\t</Globals>\n</VisualStudioProject>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2008.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"9.00\"\n\tName=\"pugixml\"\n\tProjectGUID=\"{89A1E353-E2DC-495C-B403-742BE206ACED}\"\n\tRootNamespace=\"pugixml\"\n\tKeyword=\"Win32Proj\"\n\t>\n\t<Platforms>\n\t\t<Platform\n\t\t\tName=\"Win32\"\n\t\t/>\n\t\t<Platform\n\t\t\tName=\"x64\"\n\t\t/>\n\t</Platforms>\n\t<ToolFiles>\n\t</ToolFiles>\n\t<Configurations>\n\t\t<Configuration\n\t\t\tName=\"Debug|Win32\"\n\t\t\tOutputDirectory=\"vs2008\\x32\"\n\t\t\tIntermediateDirectory=\"vs2008\\x32\\Debug\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"3\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmld.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmld.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Debug|x64\"\n\t\t\tOutputDirectory=\"vs2008\\x64\"\n\t\t\tIntermediateDirectory=\"vs2008\\x64\\Debug\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"3\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmld.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmld.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|Win32\"\n\t\t\tOutputDirectory=\"vs2008\\x32\"\n\t\t\tIntermediateDirectory=\"vs2008\\x32\\Release\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"2\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixml.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixml.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|x64\"\n\t\t\tOutputDirectory=\"vs2008\\x64\"\n\t\t\tIntermediateDirectory=\"vs2008\\x64\\Release\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"2\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixml.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixml.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t</Configurations>\n\t<References>\n\t</References>\n\t<Files>\n\t\t<Filter\n\t\t\tName=\"src\"\n\t\t\tFilter=\"\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugiconfig.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t</Files>\n\t<Globals>\n\t</Globals>\n</VisualStudioProject>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2008_static.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"9.00\"\n\tName=\"pugixml\"\n\tProjectGUID=\"{89A1E353-E2DC-495C-B403-742BE206ACED}\"\n\tRootNamespace=\"pugixml\"\n\tKeyword=\"Win32Proj\"\n\t>\n\t<Platforms>\n\t\t<Platform\n\t\t\tName=\"Win32\"\n\t\t/>\n\t\t<Platform\n\t\t\tName=\"x64\"\n\t\t/>\n\t</Platforms>\n\t<ToolFiles>\n\t</ToolFiles>\n\t<Configurations>\n\t\t<Configuration\n\t\t\tName=\"Debug|Win32\"\n\t\t\tOutputDirectory=\"vs2008\\x32\"\n\t\t\tIntermediateDirectory=\"vs2008\\x32\\DebugStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"1\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmlsd.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmlsd.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Debug|x64\"\n\t\t\tOutputDirectory=\"vs2008\\x64\"\n\t\t\tIntermediateDirectory=\"vs2008\\x64\\DebugStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"1\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmlsd.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"_DEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmlsd.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|Win32\"\n\t\t\tOutputDirectory=\"vs2008\\x32\"\n\t\t\tIntermediateDirectory=\"vs2008\\x32\\ReleaseStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"0\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmls.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmls.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|x64\"\n\t\t\tOutputDirectory=\"vs2008\\x64\"\n\t\t\tIntermediateDirectory=\"vs2008\\x64\\ReleaseStatic\"\n\t\t\tConfigurationType=\"4\"\n\t\t\tCharacterSet=\"2\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t\tTargetEnvironment=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"3\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t\tStringPooling=\"true\"\n\t\t\t\tRuntimeLibrary=\"0\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tProgramDataBaseFileName=\"$(OutDir)\\pugixmls.pdb\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t\tPreprocessorDefinitions=\"NDEBUG\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLibrarianTool\"\n\t\t\t\tOutputFile=\"$(OutDir)\\pugixmls.lib\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebDeploymentTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t</Configurations>\n\t<References>\n\t</References>\n\t<Files>\n\t\t<Filter\n\t\t\tName=\"src\"\n\t\t\tFilter=\"\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugiconfig.hpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\"..\\src\\pugixml.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t</Files>\n\t<Globals>\n\t</Globals>\n</VisualStudioProject>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2010.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\t<ItemGroup Label=\"ProjectConfigurations\">\n\t\t<ProjectConfiguration Include=\"Debug|Win32\">\n\t\t\t<Configuration>Debug</Configuration>\n\t\t\t<Platform>Win32</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Debug|x64\">\n\t\t\t<Configuration>Debug</Configuration>\n\t\t\t<Platform>x64</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Release|Win32\">\n\t\t\t<Configuration>Release</Configuration>\n\t\t\t<Platform>Win32</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Release|x64\">\n\t\t\t<Configuration>Release</Configuration>\n\t\t\t<Platform>x64</Platform>\n\t\t</ProjectConfiguration>\n\t</ItemGroup>\n\t<PropertyGroup Label=\"Globals\">\n\t\t<ProjectGuid>{89A1E353-E2DC-495C-B403-742BE206ACED}</ProjectGuid>\n\t\t<RootNamespace>pugixml</RootNamespace>\n\t\t<Keyword>Win32Proj</Keyword>\n\t</PropertyGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<UseDebugLibraries>true</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<UseDebugLibraries>true</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n\t\t<UseDebugLibraries>false</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n\t\t<UseDebugLibraries>false</UseDebugLibraries>\n\t</PropertyGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n\t<ImportGroup Label=\"ExtensionSettings\">\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<PropertyGroup Label=\"UserMacros\" />\n\t<PropertyGroup>\n\t\t<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2010\\Win32_Debug\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2010\\Win32_Debug\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2010\\x64_Debug\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2010\\x64_Debug\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2010\\Win32_Release\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2010\\Win32_Release\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2010\\x64_Release\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2010\\x64_Release\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">pugixml</TargetName>\n\t</PropertyGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Disabled</Optimization>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n\t\t\t<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Disabled</Optimization>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n\t\t\t<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Full</Optimization>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<StringPooling>true</StringPooling>\n\t\t\t<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<OptimizeReferences>true</OptimizeReferences>\n\t\t\t<EnableCOMDATFolding>true</EnableCOMDATFolding>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Full</Optimization>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<StringPooling>true</StringPooling>\n\t\t\t<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<OptimizeReferences>true</OptimizeReferences>\n\t\t\t<EnableCOMDATFolding>true</EnableCOMDATFolding>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemGroup>\n\t\t<ClInclude Include=\"..\\src\\pugixml.hpp\" />\n\t\t<ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n\t</ItemGroup>\n\t<ItemGroup>\n\t\t<ClCompile Include=\"..\\src\\pugixml.cpp\">\n\t\t</ClCompile>\n\t</ItemGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n\t<ImportGroup Label=\"ExtensionTargets\">\n\t</ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2010_static.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\t<ItemGroup Label=\"ProjectConfigurations\">\n\t\t<ProjectConfiguration Include=\"Debug|Win32\">\n\t\t\t<Configuration>Debug</Configuration>\n\t\t\t<Platform>Win32</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Debug|x64\">\n\t\t\t<Configuration>Debug</Configuration>\n\t\t\t<Platform>x64</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Release|Win32\">\n\t\t\t<Configuration>Release</Configuration>\n\t\t\t<Platform>Win32</Platform>\n\t\t</ProjectConfiguration>\n\t\t<ProjectConfiguration Include=\"Release|x64\">\n\t\t\t<Configuration>Release</Configuration>\n\t\t\t<Platform>x64</Platform>\n\t\t</ProjectConfiguration>\n\t</ItemGroup>\n\t<PropertyGroup Label=\"Globals\">\n\t\t<ProjectGuid>{89A1E353-E2DC-495C-B403-742BE206ACED}</ProjectGuid>\n\t\t<RootNamespace>pugixml</RootNamespace>\n\t\t<Keyword>Win32Proj</Keyword>\n\t</PropertyGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<UseDebugLibraries>true</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<UseDebugLibraries>true</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n\t\t<UseDebugLibraries>false</UseDebugLibraries>\n\t</PropertyGroup>\n\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n\t\t<ConfigurationType>StaticLibrary</ConfigurationType>\n\t\t<CharacterSet>MultiByte</CharacterSet>\n\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n\t\t<UseDebugLibraries>false</UseDebugLibraries>\n\t</PropertyGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n\t<ImportGroup Label=\"ExtensionSettings\">\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n\t\t<Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n\t</ImportGroup>\n\t<PropertyGroup Label=\"UserMacros\" />\n\t<PropertyGroup>\n\t\t<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2010\\Win32_DebugStatic\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2010\\Win32_DebugStatic\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2010\\x64_DebugStatic\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2010\\x64_DebugStatic\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2010\\Win32_ReleaseStatic\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2010\\Win32_ReleaseStatic\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">pugixml</TargetName>\n\t\t<OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2010\\x64_ReleaseStatic\\</OutDir>\n\t\t<IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2010\\x64_ReleaseStatic\\</IntDir>\n\t\t<TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">pugixml</TargetName>\n\t</PropertyGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Disabled</Optimization>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Disabled</Optimization>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Full</Optimization>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<StringPooling>true</StringPooling>\n\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<OptimizeReferences>true</OptimizeReferences>\n\t\t\t<EnableCOMDATFolding>true</EnableCOMDATFolding>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\t\t<ClCompile>\n\t\t\t<Optimization>Full</Optimization>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t\t<MinimalRebuild>false</MinimalRebuild>\n\t\t\t<StringPooling>true</StringPooling>\n\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n\t\t\t<PrecompiledHeader></PrecompiledHeader>\n\t\t\t<WarningLevel>Level3</WarningLevel>\n\t\t\t<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n\t\t</ClCompile>\n\t\t<ResourceCompile>\n\t\t\t<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n\t\t</ResourceCompile>\n\t<Lib>\n\t\t<OutputFile>$(OutDir)pugixml.lib</OutputFile>\n\t</Lib>\n\t\t<Link>\n\t\t\t<SubSystem>Windows</SubSystem>\n\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n\t\t\t<OptimizeReferences>true</OptimizeReferences>\n\t\t\t<EnableCOMDATFolding>true</EnableCOMDATFolding>\n\t\t\t<ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n\t\t</Link>\n\t</ItemDefinitionGroup>\n\t<ItemGroup>\n\t\t<ClInclude Include=\"..\\src\\pugixml.hpp\" />\n\t\t<ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n\t</ItemGroup>\n\t<ItemGroup>\n\t\t<ClCompile Include=\"..\\src\\pugixml.cpp\">\n\t\t</ClCompile>\n\t</ItemGroup>\n\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n\t<ImportGroup Label=\"ExtensionTargets\">\n\t</ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2013.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{89A1E353-E2DC-495C-B403-742BE206ACED}</ProjectGuid>\n    <RootNamespace>pugixml</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2013\\Win32_Debug\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2013\\Win32_Debug\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2013\\x64_Debug\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2013\\x64_Debug\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2013\\Win32_Release\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2013\\Win32_Release\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2013\\x64_Release\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2013\\x64_Release\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\">\n    </ClCompile>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2013_static.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{89A1E353-E2DC-495C-B403-742BE206ACED}</ProjectGuid>\n    <RootNamespace>pugixml</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2013\\Win32_DebugStatic\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">vs2013\\Win32_DebugStatic\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2013\\x64_DebugStatic\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">vs2013\\x64_DebugStatic\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2013\\Win32_ReleaseStatic\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">vs2013\\Win32_ReleaseStatic\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">pugixml</TargetName>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2013\\x64_ReleaseStatic\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">vs2013\\x64_ReleaseStatic\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>Full</Optimization>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ResourceCompile>\n    <Lib>\n      <OutputFile>$(OutDir)pugixml.lib</OutputFile>\n    </Lib>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <ProgramDataBaseFileName>$(OutDir)pugixml.pdb</ProgramDataBaseFileName>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\">\n    </ClCompile>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2015.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2015_static.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v140</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2015\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2015\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2017.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2017_static.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v141</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2017\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2017\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2019.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2019_static.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2019\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2019\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2022.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/pugixml_vs2022_static.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{07CF01C0-B887-499D-AD9C-799CB6A9FE64}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>pugixml</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>vs2022\\$(Platform)_$(Configuration)Static\\</OutDir>\n    <IntDir>vs2022\\$(Platform)_$(Configuration)Static\\</IntDir>\n    <TargetName>pugixml</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <MinimalRebuild>false</MinimalRebuild>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>\n      <DebugInformationFormat>OldStyle</DebugInformationFormat>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\src\\pugiconfig.hpp\" />\n    <ClInclude Include=\"..\\src\\pugixml.hpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\src\\pugixml.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>\n"
  },
  {
    "path": "external/pugixml/scripts/sbom.cdx.json",
    "content": "{\n  \"bomFormat\": \"CycloneDX\",\n  \"specVersion\": \"1.6\",\n  \"version\": 1,\n  \"metadata\": {\n    \"authors\": [\n      {\n        \"name\": \"@VCS_SBOM_AUTHORS@\"\n      }\n    ]\n  },\n  \"components\": [\n    {\n      \"type\": \"library\",\n      \"bom-ref\": \"pkg:github/zeux/pugixml@@VCS_TAG@\",\n      \"cpe\": \"cpe:2.3:a:pugixml_project:pugixml:@VCS_TAG@:*:*:*:*:*:*:*\",\n      \"name\": \"pugixml\",\n      \"version\": \"@VCS_VERSION@\",\n      \"description\": \"C++ XML processing library\",\n      \"supplier\": {\n        \"name\": \"pugixml developers\"\n      },\n      \"authors\": [\n        {\n          \"name\": \"@VCS_AUTHORS@\"\n        }\n      ],\n      \"licenses\": [\n        {\n          \"license\": {\n            \"id\": \"MIT\"\n          }\n        }\n      ],\n      \"externalReferences\": [\n        {\n          \"type\": \"website\",\n          \"url\": \"https://pugixml.org/\"\n        },\n        {\n          \"type\": \"vcs\",\n          \"url\": \"https://github.com/zeux/pugixml\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "external/pugixml/src/pugiconfig.hpp",
    "content": "/**\n * pugixml parser - version 1.15\n * --------------------------------------------------------\n * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)\n * Report bugs and download new versions at https://pugixml.org/\n *\n * This library is distributed under the MIT License. See notice at the end\n * of this file.\n *\n * This work is based on the pugxml parser, which is:\n * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)\n */\n\n#ifndef HEADER_PUGICONFIG_HPP\n#define HEADER_PUGICONFIG_HPP\n\n// Uncomment this to enable wchar_t mode\n// #define PUGIXML_WCHAR_MODE\n\n// Uncomment this to enable compact mode\n// #define PUGIXML_COMPACT\n\n// Uncomment this to disable XPath\n// #define PUGIXML_NO_XPATH\n\n// Uncomment this to disable STL\n// #define PUGIXML_NO_STL\n\n// Uncomment this to disable exceptions\n// #define PUGIXML_NO_EXCEPTIONS\n\n// Set this to control attributes for public classes/functions, i.e.:\n// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL\n// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL\n// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall\n// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead\n\n// Tune these constants to adjust memory-related behavior\n// #define PUGIXML_MEMORY_PAGE_SIZE 32768\n// #define PUGIXML_MEMORY_OUTPUT_STACK 10240\n// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096\n\n// Tune this constant to adjust max nesting for XPath queries\n// #define PUGIXML_XPATH_DEPTH_LIMIT 1024\n\n// Uncomment this to switch to header-only version\n// #define PUGIXML_HEADER_ONLY\n\n// Uncomment this to enable long long support (usually enabled automatically)\n// #define PUGIXML_HAS_LONG_LONG\n\n// Uncomment this to enable support for std::string_view (usually enabled automatically)\n// #define PUGIXML_HAS_STRING_VIEW\n\n#endif\n\n/**\n * Copyright (c) 2006-2025 Arseny Kapoulkine\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without\n * restriction, including without limitation the rights to use,\n * copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */\n"
  },
  {
    "path": "external/pugixml/src/pugixml.cpp",
    "content": "/**\n * pugixml parser - version 1.15\n * --------------------------------------------------------\n * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)\n * Report bugs and download new versions at https://pugixml.org/\n *\n * This library is distributed under the MIT License. See notice at the end\n * of this file.\n *\n * This work is based on the pugxml parser, which is:\n * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)\n */\n\n#ifndef SOURCE_PUGIXML_CPP\n#define SOURCE_PUGIXML_CPP\n\n#include \"pugixml.hpp\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n#include <limits.h>\n\n#ifdef PUGIXML_WCHAR_MODE\n#\tinclude <wchar.h>\n#endif\n\n#ifndef PUGIXML_NO_XPATH\n#\tinclude <math.h>\n#\tinclude <float.h>\n#endif\n\n#ifndef PUGIXML_NO_STL\n#\tinclude <istream>\n#\tinclude <ostream>\n#\tinclude <string>\n#endif\n\n// For placement new\n#include <new>\n\n// For load_file\n#if defined(__linux__) || defined(__APPLE__)\n#include <sys/stat.h>\n#endif\n\n#ifdef _MSC_VER\n#\tpragma warning(push)\n#\tpragma warning(disable: 4127) // conditional expression is constant\n#\tpragma warning(disable: 4324) // structure was padded due to __declspec(align())\n#\tpragma warning(disable: 4702) // unreachable code\n#\tpragma warning(disable: 4996) // this function or variable may be unsafe\n#endif\n\n#if defined(__clang__)\n#\tpragma clang diagnostic push\n#\tpragma clang diagnostic ignored \"-Wzero-as-null-pointer-constant\" // NULL as null pointer constant\n#endif\n\n#if defined(_MSC_VER) && defined(__c2__)\n#\tpragma clang diagnostic push\n#\tpragma clang diagnostic ignored \"-Wdeprecated\" // this function or variable may be unsafe\n#endif\n\n#ifdef __INTEL_COMPILER\n#\tpragma warning(disable: 177) // function was declared but never referenced\n#\tpragma warning(disable: 279) // controlling expression is constant\n#\tpragma warning(disable: 1478 1786) // function was declared \"deprecated\"\n#\tpragma warning(disable: 1684) // conversion from pointer to same-sized integral type\n#endif\n\n#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)\n#\tpragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away\n#endif\n\n#ifdef __BORLANDC__\n#\tpragma option push\n#\tpragma warn -8008 // condition is always false\n#\tpragma warn -8066 // unreachable code\n#endif\n\n#ifdef __SNC__\n// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug\n#\tpragma diag_suppress=178 // function was declared but never referenced\n#\tpragma diag_suppress=237 // controlling expression is constant\n#endif\n\n#ifdef __TI_COMPILER_VERSION__\n#\tpragma diag_suppress 179 // function was declared but never referenced\n#endif\n\n// Inlining controls\n#if defined(_MSC_VER) && _MSC_VER >= 1300\n#\tdefine PUGI_IMPL_NO_INLINE __declspec(noinline)\n#elif defined(__GNUC__)\n#\tdefine PUGI_IMPL_NO_INLINE __attribute__((noinline))\n#else\n#\tdefine PUGI_IMPL_NO_INLINE\n#endif\n\n// Branch weight controls\n#if defined(__GNUC__) && !defined(__c2__)\n#\tdefine PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)\n#else\n#\tdefine PUGI_IMPL_UNLIKELY(cond) (cond)\n#endif\n\n// Simple static assertion\n#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }\n\n// Digital Mars C++ bug workaround for passing char loaded from memory via stack\n#ifdef __DMC__\n#\tdefine PUGI_IMPL_DMC_VOLATILE volatile\n#else\n#\tdefine PUGI_IMPL_DMC_VOLATILE\n#endif\n\n// Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces \"attribute directive ignored\" warnings\n#if defined(__clang__) && defined(__has_attribute)\n#\tif __has_attribute(no_sanitize)\n#\t\tdefine PUGI_IMPL_UNSIGNED_OVERFLOW __attribute__((no_sanitize(\"unsigned-integer-overflow\")))\n#\telse\n#\t\tdefine PUGI_IMPL_UNSIGNED_OVERFLOW\n#\tendif\n#else\n#\tdefine PUGI_IMPL_UNSIGNED_OVERFLOW\n#endif\n\n// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)\n#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)\nusing std::memcpy;\nusing std::memmove;\nusing std::memset;\n#endif\n\n// Old versions of GCC do not define ::malloc and ::free depending on header include order\n#if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))\nusing std::malloc;\nusing std::free;\n#endif\n\n// Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations\n#if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)\n#\tdefine LLONG_MIN (-LLONG_MAX - 1LL)\n#\tdefine LLONG_MAX __LONG_LONG_MAX__\n#\tdefine ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)\n#endif\n\n// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features\n#if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE)\n#\tdefine PUGI_IMPL_MSVC_CRT_VERSION _MSC_VER\n#elif defined(_WIN32_WCE)\n#\tdefine PUGI_IMPL_MSVC_CRT_VERSION 1310 // MSVC7.1\n#endif\n\n// Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size.\n#if __cplusplus >= 201103\n#\tdefine PUGI_IMPL_SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)\n#elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400\n#\tdefine PUGI_IMPL_SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)\n#elif defined(__APPLE__) && __clang_major__ >= 14 // Xcode 14 marks sprintf as deprecated while still using C++98 by default\n#\tdefine PUGI_IMPL_SNPRINTF(buf, fmt, arg1, arg2) snprintf(buf, sizeof(buf), fmt, arg1, arg2)\n#else\n#\tdefine PUGI_IMPL_SNPRINTF sprintf\n#endif\n\n// We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat.\n#ifdef PUGIXML_HEADER_ONLY\n#\tdefine PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl {\n#\tdefine PUGI_IMPL_NS_END } }\n#\tdefine PUGI_IMPL_FN inline\n#\tdefine PUGI_IMPL_FN_NO_INLINE inline\n#else\n#\tif defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces\n#\t\tdefine PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl {\n#\t\tdefine PUGI_IMPL_NS_END } }\n#\telse\n#\t\tdefine PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { namespace {\n#\t\tdefine PUGI_IMPL_NS_END } } }\n#\tendif\n#\tdefine PUGI_IMPL_FN\n#\tdefine PUGI_IMPL_FN_NO_INLINE PUGI_IMPL_NO_INLINE\n#endif\n\n// uintptr_t\n#if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561)\nnamespace pugi\n{\n#\tifndef _UINTPTR_T_DEFINED\n\ttypedef size_t uintptr_t;\n#\tendif\n\n\ttypedef unsigned __int8 uint8_t;\n\ttypedef unsigned __int16 uint16_t;\n\ttypedef unsigned __int32 uint32_t;\n}\n#else\n#\tinclude <stdint.h>\n#endif\n\n// Memory allocation\nPUGI_IMPL_NS_BEGIN\n\tPUGI_IMPL_FN void* default_allocate(size_t size)\n\t{\n\t\treturn malloc(size);\n\t}\n\n\tPUGI_IMPL_FN void default_deallocate(void* ptr)\n\t{\n\t\tfree(ptr);\n\t}\n\n\ttemplate <typename T>\n\tstruct xml_memory_management_function_storage\n\t{\n\t\tstatic allocation_function allocate;\n\t\tstatic deallocation_function deallocate;\n\t};\n\n\t// Global allocation functions are stored in class statics so that in header mode linker deduplicates them\n\t// Without a template<> we'll get multiple definitions of the same static\n\ttemplate <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;\n\ttemplate <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;\n\n\ttypedef xml_memory_management_function_storage<int> xml_memory;\nPUGI_IMPL_NS_END\n\n// String utilities\nPUGI_IMPL_NS_BEGIN\n\t// Get string length\n\tPUGI_IMPL_FN size_t strlength(const char_t* s)\n\t{\n\t\tassert(s);\n\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcslen(s);\n\t#else\n\t\treturn strlen(s);\n\t#endif\n\t}\n\n\t// Compare two strings\n\tPUGI_IMPL_FN bool strequal(const char_t* src, const char_t* dst)\n\t{\n\t\tassert(src && dst);\n\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcscmp(src, dst) == 0;\n\t#else\n\t\treturn strcmp(src, dst) == 0;\n\t#endif\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\t// Check if the null-terminated dst string is equal to the entire contents of srcview\n\tPUGI_IMPL_FN bool stringview_equal(string_view_t srcview, const char_t* dst)\n\t{\n\t\t// std::basic_string_view::compare(const char*) has the right behavior, but it performs an\n\t\t// extra traversal of dst to compute its length.\n\t\tassert(dst);\n\t\tconst char_t* src = srcview.data();\n\t\tsize_t srclen = srcview.size();\n\n\t\twhile (srclen && *dst && *src == *dst)\n\t\t{\n\t\t\t--srclen; ++dst; ++src; \n\t\t}\n\t\treturn srclen == 0 && *dst == 0;\n\t}\n#endif\n\n\t// Compare lhs with [rhs_begin, rhs_end)\n\tPUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)\n\t{\n\t\tfor (size_t i = 0; i < count; ++i)\n\t\t\tif (lhs[i] != rhs[i])\n\t\t\t\treturn false;\n\n\t\treturn lhs[count] == 0;\n\t}\n\n\t// Get length of wide string, even if CRT lacks wide character support\n\tPUGI_IMPL_FN size_t strlength_wide(const wchar_t* s)\n\t{\n\t\tassert(s);\n\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcslen(s);\n\t#else\n\t\tconst wchar_t* end = s;\n\t\twhile (*end) end++;\n\t\treturn static_cast<size_t>(end - s);\n\t#endif\n\t}\nPUGI_IMPL_NS_END\n\n// auto_ptr-like object for exception recovery\nPUGI_IMPL_NS_BEGIN\n\ttemplate <typename T> struct auto_deleter\n\t{\n\t\ttypedef void (*D)(T*);\n\n\t\tT* data;\n\t\tD deleter;\n\n\t\tauto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)\n\t\t{\n\t\t}\n\n\t\t~auto_deleter()\n\t\t{\n\t\t\tif (data) deleter(data);\n\t\t}\n\n\t\tT* release()\n\t\t{\n\t\t\tT* result = data;\n\t\t\tdata = NULL;\n\t\t\treturn result;\n\t\t}\n\t};\nPUGI_IMPL_NS_END\n\n#ifdef PUGIXML_COMPACT\nPUGI_IMPL_NS_BEGIN\n\tclass compact_hash_table\n\t{\n\tpublic:\n\t\tcompact_hash_table(): _items(NULL), _capacity(0), _count(0)\n\t\t{\n\t\t}\n\n\t\tvoid clear()\n\t\t{\n\t\t\tif (_items)\n\t\t\t{\n\t\t\t\txml_memory::deallocate(_items);\n\t\t\t\t_items = NULL;\n\t\t\t\t_capacity = 0;\n\t\t\t\t_count = 0;\n\t\t\t}\n\t\t}\n\n\t\tvoid* find(const void* key)\n\t\t{\n\t\t\tif (_capacity == 0) return NULL;\n\n\t\t\titem_t* item = get_item(key);\n\t\t\tassert(item);\n\t\t\tassert(item->key == key || (item->key == NULL && item->value == NULL));\n\n\t\t\treturn item->value;\n\t\t}\n\n\t\tvoid insert(const void* key, void* value)\n\t\t{\n\t\t\tassert(_capacity != 0 && _count < _capacity - _capacity / 4);\n\n\t\t\titem_t* item = get_item(key);\n\t\t\tassert(item);\n\n\t\t\tif (item->key == NULL)\n\t\t\t{\n\t\t\t\t_count++;\n\t\t\t\titem->key = key;\n\t\t\t}\n\n\t\t\titem->value = value;\n\t\t}\n\n\t\tbool reserve(size_t extra = 16)\n\t\t{\n\t\t\tif (_count + extra >= _capacity - _capacity / 4)\n\t\t\t\treturn rehash(_count + extra);\n\n\t\t\treturn true;\n\t\t}\n\n\tprivate:\n\t\tstruct item_t\n\t\t{\n\t\t\tconst void* key;\n\t\t\tvoid* value;\n\t\t};\n\n\t\titem_t* _items;\n\t\tsize_t _capacity;\n\n\t\tsize_t _count;\n\n\t\tbool rehash(size_t count);\n\n\t\titem_t* get_item(const void* key)\n\t\t{\n\t\t\tassert(key);\n\t\t\tassert(_capacity > 0);\n\n\t\t\tsize_t hashmod = _capacity - 1;\n\t\t\tsize_t bucket = hash(key) & hashmod;\n\n\t\t\tfor (size_t probe = 0; probe <= hashmod; ++probe)\n\t\t\t{\n\t\t\t\titem_t& probe_item = _items[bucket];\n\n\t\t\t\tif (probe_item.key == key || probe_item.key == NULL)\n\t\t\t\t\treturn &probe_item;\n\n\t\t\t\t// hash collision, quadratic probing\n\t\t\t\tbucket = (bucket + probe + 1) & hashmod;\n\t\t\t}\n\n\t\t\tassert(false && \"Hash table is full\"); // unreachable\n\t\t\treturn NULL;\n\t\t}\n\n\t\tstatic PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash(const void* key)\n\t\t{\n\t\t\tunsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key) & 0xffffffff);\n\n\t\t\t// MurmurHash3 32-bit finalizer\n\t\t\th ^= h >> 16;\n\t\t\th *= 0x85ebca6bu;\n\t\t\th ^= h >> 13;\n\t\t\th *= 0xc2b2ae35u;\n\t\t\th ^= h >> 16;\n\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN_NO_INLINE bool compact_hash_table::rehash(size_t count)\n\t{\n\t\tsize_t capacity = 32;\n\t\twhile (count >= capacity - capacity / 4)\n\t\t\tcapacity *= 2;\n\n\t\tcompact_hash_table rt;\n\t\trt._capacity = capacity;\n\t\trt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * capacity));\n\n\t\tif (!rt._items)\n\t\t\treturn false;\n\n\t\tmemset(rt._items, 0, sizeof(item_t) * capacity);\n\n\t\tfor (size_t i = 0; i < _capacity; ++i)\n\t\t\tif (_items[i].key)\n\t\t\t\trt.insert(_items[i].key, _items[i].value);\n\n\t\tif (_items)\n\t\t\txml_memory::deallocate(_items);\n\n\t\t_capacity = capacity;\n\t\t_items = rt._items;\n\n\t\tassert(_count == rt._count);\n\n\t\treturn true;\n\t}\n\nPUGI_IMPL_NS_END\n#endif\n\nPUGI_IMPL_NS_BEGIN\n#ifdef PUGIXML_COMPACT\n\tstatic const uintptr_t xml_memory_block_alignment = 4;\n#else\n\tstatic const uintptr_t xml_memory_block_alignment = sizeof(void*);\n#endif\n\n\t// extra metadata bits\n\tstatic const uintptr_t xml_memory_page_contents_shared_mask = 64;\n\tstatic const uintptr_t xml_memory_page_name_allocated_mask = 32;\n\tstatic const uintptr_t xml_memory_page_value_allocated_mask = 16;\n\tstatic const uintptr_t xml_memory_page_type_mask = 15;\n\n\t// combined masks for string uniqueness\n\tstatic const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;\n\tstatic const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;\n\n#ifdef PUGIXML_COMPACT\n\t#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) // unused\n\t#define PUGI_IMPL_GETPAGE_IMPL(header) (header).get_page()\n#else\n\t#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))\n\t// this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings\n\t#define PUGI_IMPL_GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))\n#endif\n\n\t#define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header)\n\t#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)\n\n\tstruct xml_allocator;\n\n\tstruct xml_memory_page\n\t{\n\t\tstatic xml_memory_page* construct(void* memory)\n\t\t{\n\t\t\txml_memory_page* result = static_cast<xml_memory_page*>(memory);\n\n\t\t\tresult->allocator = NULL;\n\t\t\tresult->prev = NULL;\n\t\t\tresult->next = NULL;\n\t\t\tresult->busy_size = 0;\n\t\t\tresult->freed_size = 0;\n\n\t\t#ifdef PUGIXML_COMPACT\n\t\t\tresult->compact_string_base = NULL;\n\t\t\tresult->compact_shared_parent = NULL;\n\t\t\tresult->compact_page_marker = NULL;\n\t\t#endif\n\n\t\t\treturn result;\n\t\t}\n\n\t\txml_allocator* allocator;\n\n\t\txml_memory_page* prev;\n\t\txml_memory_page* next;\n\n\t\tsize_t busy_size;\n\t\tsize_t freed_size;\n\n\t#ifdef PUGIXML_COMPACT\n\t\tchar_t* compact_string_base;\n\t\tvoid* compact_shared_parent;\n\t\tuint32_t* compact_page_marker;\n\t#endif\n\t};\n\n\tstatic const size_t xml_memory_page_size =\n\t#ifdef PUGIXML_MEMORY_PAGE_SIZE\n\t\t(PUGIXML_MEMORY_PAGE_SIZE)\n\t#else\n\t\t32768\n\t#endif\n\t\t- sizeof(xml_memory_page);\n\n\tstruct xml_memory_string_header\n\t{\n\t\tuint16_t page_offset; // offset from page->data\n\t\tuint16_t full_size; // 0 if string occupies whole page\n\t};\n\n\tstruct xml_allocator\n\t{\n\t\txml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)\n\t\t{\n\t\t#ifdef PUGIXML_COMPACT\n\t\t\t_hash = NULL;\n\t\t#endif\n\t\t}\n\n\t\txml_memory_page* allocate_page(size_t data_size)\n\t\t{\n\t\t\tsize_t size = sizeof(xml_memory_page) + data_size;\n\n\t\t\t// allocate block with some alignment, leaving memory for worst-case padding\n\t\t\tvoid* memory = xml_memory::allocate(size);\n\t\t\tif (!memory) return NULL;\n\n\t\t\t// prepare page structure\n\t\t\txml_memory_page* page = xml_memory_page::construct(memory);\n\t\t\tassert(page);\n\n\t\t\tassert(this == _root->allocator);\n\t\t\tpage->allocator = this;\n\n\t\t\treturn page;\n\t\t}\n\n\t\tstatic void deallocate_page(xml_memory_page* page)\n\t\t{\n\t\t\txml_memory::deallocate(page);\n\t\t}\n\n\t\tvoid* allocate_memory_oob(size_t size, xml_memory_page*& out_page);\n\n\t\tvoid* allocate_memory(size_t size, xml_memory_page*& out_page)\n\t\t{\n\t\t\tif (PUGI_IMPL_UNLIKELY(_busy_size + size > xml_memory_page_size))\n\t\t\t\treturn allocate_memory_oob(size, out_page);\n\n\t\t\tvoid* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;\n\n\t\t\t_busy_size += size;\n\n\t\t\tout_page = _root;\n\n\t\t\treturn buf;\n\t\t}\n\n\t#ifdef PUGIXML_COMPACT\n\t\tvoid* allocate_object(size_t size, xml_memory_page*& out_page)\n\t\t{\n\t\t\tvoid* result = allocate_memory(size + sizeof(uint32_t), out_page);\n\t\t\tif (!result) return NULL;\n\n\t\t\t// adjust for marker\n\t\t\tptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);\n\n\t\t\tif (PUGI_IMPL_UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))\n\t\t\t{\n\t\t\t\t// insert new marker\n\t\t\t\tuint32_t* marker = static_cast<uint32_t*>(result);\n\n\t\t\t\t*marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));\n\t\t\t\tout_page->compact_page_marker = marker;\n\n\t\t\t\t// since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block\n\t\t\t\t// this will make sure deallocate_memory correctly tracks the size\n\t\t\t\tout_page->freed_size += sizeof(uint32_t);\n\n\t\t\t\treturn marker + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// roll back uint32_t part\n\t\t\t\t_busy_size -= sizeof(uint32_t);\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t#else\n\t\tvoid* allocate_object(size_t size, xml_memory_page*& out_page)\n\t\t{\n\t\t\treturn allocate_memory(size, out_page);\n\t\t}\n\t#endif\n\n\t\tvoid deallocate_memory(void* ptr, size_t size, xml_memory_page* page)\n\t\t{\n\t\t\tif (page == _root) page->busy_size = _busy_size;\n\n\t\t\tassert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size);\n\t\t\t(void)!ptr;\n\n\t\t\tpage->freed_size += size;\n\t\t\tassert(page->freed_size <= page->busy_size);\n\n\t\t\tif (page->freed_size == page->busy_size)\n\t\t\t{\n\t\t\t\tif (page->next == NULL)\n\t\t\t\t{\n\t\t\t\t\tassert(_root == page);\n\n\t\t\t\t\t// top page freed, just reset sizes\n\t\t\t\t\tpage->busy_size = 0;\n\t\t\t\t\tpage->freed_size = 0;\n\n\t\t\t\t#ifdef PUGIXML_COMPACT\n\t\t\t\t\t// reset compact state to maximize efficiency\n\t\t\t\t\tpage->compact_string_base = NULL;\n\t\t\t\t\tpage->compact_shared_parent = NULL;\n\t\t\t\t\tpage->compact_page_marker = NULL;\n\t\t\t\t#endif\n\n\t\t\t\t\t_busy_size = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tassert(_root != page);\n\t\t\t\t\tassert(page->prev);\n\n\t\t\t\t\t// remove from the list\n\t\t\t\t\tpage->prev->next = page->next;\n\t\t\t\t\tpage->next->prev = page->prev;\n\n\t\t\t\t\t// deallocate\n\t\t\t\t\tdeallocate_page(page);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tchar_t* allocate_string(size_t length)\n\t\t{\n\t\t\tstatic const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;\n\n\t\t\tPUGI_IMPL_STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);\n\n\t\t\t// allocate memory for string and header block\n\t\t\tsize_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);\n\n\t\t\t// round size up to block alignment boundary\n\t\t\tsize_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);\n\n\t\t\txml_memory_page* page;\n\t\t\txml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));\n\n\t\t\tif (!header) return NULL;\n\n\t\t\t// setup header\n\t\t\tptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);\n\n\t\t\tassert(page_offset % xml_memory_block_alignment == 0);\n\t\t\tassert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);\n\t\t\theader->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);\n\n\t\t\t// full_size == 0 for large strings that occupy the whole page\n\t\t\tassert(full_size % xml_memory_block_alignment == 0);\n\t\t\tassert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));\n\t\t\theader->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);\n\n\t\t\t// round-trip through void* to avoid 'cast increases required alignment of target type' warning\n\t\t\t// header is guaranteed a pointer-sized alignment, which should be enough for char_t\n\t\t\treturn static_cast<char_t*>(static_cast<void*>(header + 1));\n\t\t}\n\n\t\tvoid deallocate_string(char_t* string)\n\t\t{\n\t\t\t// this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings\n\t\t\t// we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string\n\n\t\t\t// get header\n\t\t\txml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;\n\t\t\tassert(header);\n\n\t\t\t// deallocate\n\t\t\tsize_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;\n\t\t\txml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));\n\n\t\t\t// if full_size == 0 then this string occupies the whole page\n\t\t\tsize_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;\n\n\t\t\tdeallocate_memory(header, full_size, page);\n\t\t}\n\n\t\tbool reserve()\n\t\t{\n\t\t#ifdef PUGIXML_COMPACT\n\t\t\treturn _hash->reserve();\n\t\t#else\n\t\t\treturn true;\n\t\t#endif\n\t\t}\n\n\t\txml_memory_page* _root;\n\t\tsize_t _busy_size;\n\n\t#ifdef PUGIXML_COMPACT\n\t\tcompact_hash_table* _hash;\n\t#endif\n\t};\n\n\tPUGI_IMPL_FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)\n\t{\n\t\tconst size_t large_allocation_threshold = xml_memory_page_size / 4;\n\n\t\txml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);\n\t\tout_page = page;\n\n\t\tif (!page) return NULL;\n\n\t\tif (size <= large_allocation_threshold)\n\t\t{\n\t\t\t_root->busy_size = _busy_size;\n\n\t\t\t// insert page at the end of linked list\n\t\t\tpage->prev = _root;\n\t\t\t_root->next = page;\n\t\t\t_root = page;\n\n\t\t\t_busy_size = size;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// insert page before the end of linked list, so that it is deleted as soon as possible\n\t\t\t// the last page is not deleted even if it's empty (see deallocate_memory)\n\t\t\tassert(_root->prev);\n\n\t\t\tpage->prev = _root->prev;\n\t\t\tpage->next = _root;\n\n\t\t\t_root->prev->next = page;\n\t\t\t_root->prev = page;\n\n\t\t\tpage->busy_size = size;\n\t\t}\n\n\t\treturn reinterpret_cast<char*>(page) + sizeof(xml_memory_page);\n\t}\nPUGI_IMPL_NS_END\n\n#ifdef PUGIXML_COMPACT\nPUGI_IMPL_NS_BEGIN\n\tstatic const uintptr_t compact_alignment_log2 = 2;\n\tstatic const uintptr_t compact_alignment = 1 << compact_alignment_log2;\n\n\tclass compact_header\n\t{\n\tpublic:\n\t\tcompact_header(xml_memory_page* page, unsigned int flags)\n\t\t{\n\t\t\tPUGI_IMPL_STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);\n\n\t\t\tptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));\n\t\t\tassert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);\n\n\t\t\t_page = static_cast<unsigned char>(offset >> compact_alignment_log2);\n\t\t\t_flags = static_cast<unsigned char>(flags);\n\t\t}\n\n\t\tvoid operator&=(uintptr_t mod)\n\t\t{\n\t\t\t_flags &= static_cast<unsigned char>(mod);\n\t\t}\n\n\t\tvoid operator|=(uintptr_t mod)\n\t\t{\n\t\t\t_flags |= static_cast<unsigned char>(mod);\n\t\t}\n\n\t\tuintptr_t operator&(uintptr_t mod) const\n\t\t{\n\t\t\treturn _flags & mod;\n\t\t}\n\n\t\txml_memory_page* get_page() const\n\t\t{\n\t\t\t// round-trip through void* to silence 'cast increases required alignment of target type' warnings\n\t\t\tconst char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);\n\t\t\tconst char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));\n\n\t\t\treturn const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));\n\t\t}\n\n\tprivate:\n\t\tunsigned char _page;\n\t\tunsigned char _flags;\n\t};\n\n\tPUGI_IMPL_FN xml_memory_page* compact_get_page(const void* object, int header_offset)\n\t{\n\t\tconst compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);\n\n\t\treturn header->get_page();\n\t}\n\n\ttemplate <int header_offset, typename T> PUGI_IMPL_FN_NO_INLINE T* compact_get_value(const void* object)\n\t{\n\t\treturn static_cast<T*>(compact_get_page(object, header_offset)->allocator->_hash->find(object));\n\t}\n\n\ttemplate <int header_offset, typename T> PUGI_IMPL_FN_NO_INLINE void compact_set_value(const void* object, T* value)\n\t{\n\t\tcompact_get_page(object, header_offset)->allocator->_hash->insert(object, value);\n\t}\n\n\ttemplate <typename T, int header_offset, int start = -126> class compact_pointer\n\t{\n\tpublic:\n\t\tcompact_pointer(): _data(0)\n\t\t{\n\t\t}\n\n\t\tvoid operator=(const compact_pointer& rhs)\n\t\t{\n\t\t\t*this = rhs + 0;\n\t\t}\n\n\t\tvoid operator=(T* value)\n\t\t{\n\t\t\tif (value)\n\t\t\t{\n\t\t\t\t// value is guaranteed to be compact-aligned; 'this' is not\n\t\t\t\t// our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)\n\t\t\t\t// so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to\n\t\t\t\t// compensate for arithmetic shift rounding for negative values\n\t\t\t\tptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);\n\t\t\t\tptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;\n\n\t\t\t\tif (static_cast<uintptr_t>(offset) <= 253)\n\t\t\t\t\t_data = static_cast<unsigned char>(offset + 1);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcompact_set_value<header_offset>(this, value);\n\n\t\t\t\t\t_data = 255;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\t_data = 0;\n\t\t}\n\n\t\toperator T*() const\n\t\t{\n\t\t\tif (_data)\n\t\t\t{\n\t\t\t\tif (_data < 255)\n\t\t\t\t{\n\t\t\t\t\tuintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);\n\n\t\t\t\t\treturn reinterpret_cast<T*>(base + (_data - 1 + start) * compact_alignment);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn compact_get_value<header_offset, T>(this);\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn NULL;\n\t\t}\n\n\t\tT* operator->() const\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\tunsigned char _data;\n\t};\n\n\ttemplate <typename T, int header_offset> class compact_pointer_parent\n\t{\n\tpublic:\n\t\tcompact_pointer_parent(): _data(0)\n\t\t{\n\t\t}\n\n\t\tvoid operator=(const compact_pointer_parent& rhs)\n\t\t{\n\t\t\t*this = rhs + 0;\n\t\t}\n\n\t\tvoid operator=(T* value)\n\t\t{\n\t\t\tif (value)\n\t\t\t{\n\t\t\t\t// value is guaranteed to be compact-aligned; 'this' is not\n\t\t\t\t// our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)\n\t\t\t\t// so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to\n\t\t\t\t// compensate for arithmetic shift behavior for negative values\n\t\t\t\tptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);\n\t\t\t\tptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;\n\n\t\t\t\tif (static_cast<uintptr_t>(offset) <= 65533)\n\t\t\t\t{\n\t\t\t\t\t_data = static_cast<unsigned short>(offset + 1);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\txml_memory_page* page = compact_get_page(this, header_offset);\n\n\t\t\t\t\tif (PUGI_IMPL_UNLIKELY(page->compact_shared_parent == NULL))\n\t\t\t\t\t\tpage->compact_shared_parent = value;\n\n\t\t\t\t\tif (page->compact_shared_parent == value)\n\t\t\t\t\t{\n\t\t\t\t\t\t_data = 65534;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcompact_set_value<header_offset>(this, value);\n\n\t\t\t\t\t\t_data = 65535;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_data = 0;\n\t\t\t}\n\t\t}\n\n\t\toperator T*() const\n\t\t{\n\t\t\tif (_data)\n\t\t\t{\n\t\t\t\tif (_data < 65534)\n\t\t\t\t{\n\t\t\t\t\tuintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);\n\n\t\t\t\t\treturn reinterpret_cast<T*>(base + (_data - 1 - 65533) * compact_alignment);\n\t\t\t\t}\n\t\t\t\telse if (_data == 65534)\n\t\t\t\t\treturn static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);\n\t\t\t\telse\n\t\t\t\t\treturn compact_get_value<header_offset, T>(this);\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn NULL;\n\t\t}\n\n\t\tT* operator->() const\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\n\tprivate:\n\t\tuint16_t _data;\n\t};\n\n\ttemplate <int header_offset, int base_offset> class compact_string\n\t{\n\tpublic:\n\t\tcompact_string(): _data(0)\n\t\t{\n\t\t}\n\n\t\tvoid operator=(const compact_string& rhs)\n\t\t{\n\t\t\t*this = rhs + 0;\n\t\t}\n\n\t\tvoid operator=(char_t* value)\n\t\t{\n\t\t\tif (value)\n\t\t\t{\n\t\t\t\txml_memory_page* page = compact_get_page(this, header_offset);\n\n\t\t\t\tif (PUGI_IMPL_UNLIKELY(page->compact_string_base == NULL))\n\t\t\t\t\tpage->compact_string_base = value;\n\n\t\t\t\tptrdiff_t offset = value - page->compact_string_base;\n\n\t\t\t\tif (static_cast<uintptr_t>(offset) < (65535 << 7))\n\t\t\t\t{\n\t\t\t\t\t// round-trip through void* to silence 'cast increases required alignment of target type' warnings\n\t\t\t\t\tuint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));\n\n\t\t\t\t\tif (*base == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t*base = static_cast<uint16_t>((offset >> 7) + 1);\n\t\t\t\t\t\t_data = static_cast<unsigned char>((offset & 127) + 1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tptrdiff_t remainder = offset - ((*base - 1) << 7);\n\n\t\t\t\t\t\tif (static_cast<uintptr_t>(remainder) <= 253)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_data = static_cast<unsigned char>(remainder + 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcompact_set_value<header_offset>(this, value);\n\n\t\t\t\t\t\t\t_data = 255;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcompact_set_value<header_offset>(this, value);\n\n\t\t\t\t\t_data = 255;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_data = 0;\n\t\t\t}\n\t\t}\n\n\t\toperator char_t*() const\n\t\t{\n\t\t\tif (_data)\n\t\t\t{\n\t\t\t\tif (_data < 255)\n\t\t\t\t{\n\t\t\t\t\txml_memory_page* page = compact_get_page(this, header_offset);\n\n\t\t\t\t\t// round-trip through void* to silence 'cast increases required alignment of target type' warnings\n\t\t\t\t\tconst uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));\n\t\t\t\t\tassert(*base);\n\n\t\t\t\t\tptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);\n\n\t\t\t\t\treturn page->compact_string_base + offset;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn compact_get_value<header_offset, char_t>(this);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn NULL;\n\t\t}\n\n\tprivate:\n\t\tunsigned char _data;\n\t};\nPUGI_IMPL_NS_END\n#endif\n\n#ifdef PUGIXML_COMPACT\nnamespace pugi\n{\n\tstruct xml_attribute_struct\n\t{\n\t\txml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)\n\t\t{\n\t\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);\n\t\t}\n\n\t\timpl::compact_header header;\n\n\t\tuint16_t namevalue_base;\n\n\t\timpl::compact_string<4, 2> name;\n\t\timpl::compact_string<5, 3> value;\n\n\t\timpl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;\n\t\timpl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;\n\t};\n\n\tstruct xml_node_struct\n\t{\n\t\txml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)\n\t\t{\n\t\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(xml_node_struct) == 12);\n\t\t}\n\n\t\timpl::compact_header header;\n\n\t\tuint16_t namevalue_base;\n\n\t\timpl::compact_string<4, 2> name;\n\t\timpl::compact_string<5, 3> value;\n\n\t\timpl::compact_pointer_parent<xml_node_struct, 6> parent;\n\n\t\timpl::compact_pointer<xml_node_struct, 8, 0> first_child;\n\n\t\timpl::compact_pointer<xml_node_struct,  9>    prev_sibling_c;\n\t\timpl::compact_pointer<xml_node_struct, 10, 0> next_sibling;\n\n\t\timpl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;\n\t};\n}\n#else\nnamespace pugi\n{\n\tstruct xml_attribute_struct\n\t{\n\t\txml_attribute_struct(impl::xml_memory_page* page): name(NULL), value(NULL), prev_attribute_c(NULL), next_attribute(NULL)\n\t\t{\n\t\t\theader = PUGI_IMPL_GETHEADER_IMPL(this, page, 0);\n\t\t}\n\n\t\tuintptr_t header;\n\n\t\tchar_t*\tname;\n\t\tchar_t*\tvalue;\n\n\t\txml_attribute_struct* prev_attribute_c;\n\t\txml_attribute_struct* next_attribute;\n\t};\n\n\tstruct xml_node_struct\n\t{\n\t\txml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(NULL), value(NULL), parent(NULL), first_child(NULL), prev_sibling_c(NULL), next_sibling(NULL), first_attribute(NULL)\n\t\t{\n\t\t\theader = PUGI_IMPL_GETHEADER_IMPL(this, page, type);\n\t\t}\n\n\t\tuintptr_t header;\n\n\t\tchar_t* name;\n\t\tchar_t* value;\n\n\t\txml_node_struct* parent;\n\n\t\txml_node_struct* first_child;\n\n\t\txml_node_struct* prev_sibling_c;\n\t\txml_node_struct* next_sibling;\n\n\t\txml_attribute_struct* first_attribute;\n\t};\n}\n#endif\n\nPUGI_IMPL_NS_BEGIN\n\tstruct xml_extra_buffer\n\t{\n\t\tchar_t* buffer;\n\t\txml_extra_buffer* next;\n\t};\n\n\tstruct xml_document_struct: public xml_node_struct, public xml_allocator\n\t{\n\t\txml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(NULL), extra_buffers(NULL)\n\t\t{\n\t\t}\n\n\t\tconst char_t* buffer;\n\n\t\txml_extra_buffer* extra_buffers;\n\n\t#ifdef PUGIXML_COMPACT\n\t\tcompact_hash_table hash;\n\t#endif\n\t};\n\n\ttemplate <typename Object> inline xml_allocator& get_allocator(const Object* object)\n\t{\n\t\tassert(object);\n\n\t\treturn *PUGI_IMPL_GETPAGE(object)->allocator;\n\t}\n\n\ttemplate <typename Object> inline xml_document_struct& get_document(const Object* object)\n\t{\n\t\tassert(object);\n\n\t\treturn *static_cast<xml_document_struct*>(PUGI_IMPL_GETPAGE(object)->allocator);\n\t}\nPUGI_IMPL_NS_END\n\n// Low-level DOM operations\nPUGI_IMPL_NS_BEGIN\n\tinline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)\n\t{\n\t\txml_memory_page* page;\n\t\tvoid* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);\n\t\tif (!memory) return NULL;\n\n\t\treturn new (memory) xml_attribute_struct(page);\n\t}\n\n\tinline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)\n\t{\n\t\txml_memory_page* page;\n\t\tvoid* memory = alloc.allocate_object(sizeof(xml_node_struct), page);\n\t\tif (!memory) return NULL;\n\n\t\treturn new (memory) xml_node_struct(page, type);\n\t}\n\n\tinline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)\n\t{\n\t\tif (a->header & impl::xml_memory_page_name_allocated_mask)\n\t\t\talloc.deallocate_string(a->name);\n\n\t\tif (a->header & impl::xml_memory_page_value_allocated_mask)\n\t\t\talloc.deallocate_string(a->value);\n\n\t\talloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI_IMPL_GETPAGE(a));\n\t}\n\n\tinline void destroy_node(xml_node_struct* n, xml_allocator& alloc)\n\t{\n\t\tif (n->header & impl::xml_memory_page_name_allocated_mask)\n\t\t\talloc.deallocate_string(n->name);\n\n\t\tif (n->header & impl::xml_memory_page_value_allocated_mask)\n\t\t\talloc.deallocate_string(n->value);\n\n\t\tfor (xml_attribute_struct* attr = n->first_attribute; attr; )\n\t\t{\n\t\t\txml_attribute_struct* next = attr->next_attribute;\n\n\t\t\tdestroy_attribute(attr, alloc);\n\n\t\t\tattr = next;\n\t\t}\n\n\t\tfor (xml_node_struct* child = n->first_child; child; )\n\t\t{\n\t\t\txml_node_struct* next = child->next_sibling;\n\n\t\t\tdestroy_node(child, alloc);\n\n\t\t\tchild = next;\n\t\t}\n\n\t\talloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI_IMPL_GETPAGE(n));\n\t}\n\n\tinline void append_node(xml_node_struct* child, xml_node_struct* node)\n\t{\n\t\tchild->parent = node;\n\n\t\txml_node_struct* head = node->first_child;\n\n\t\tif (head)\n\t\t{\n\t\t\txml_node_struct* tail = head->prev_sibling_c;\n\n\t\t\ttail->next_sibling = child;\n\t\t\tchild->prev_sibling_c = tail;\n\t\t\thead->prev_sibling_c = child;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnode->first_child = child;\n\t\t\tchild->prev_sibling_c = child;\n\t\t}\n\t}\n\n\tinline void prepend_node(xml_node_struct* child, xml_node_struct* node)\n\t{\n\t\tchild->parent = node;\n\n\t\txml_node_struct* head = node->first_child;\n\n\t\tif (head)\n\t\t{\n\t\t\tchild->prev_sibling_c = head->prev_sibling_c;\n\t\t\thead->prev_sibling_c = child;\n\t\t}\n\t\telse\n\t\t\tchild->prev_sibling_c = child;\n\n\t\tchild->next_sibling = head;\n\t\tnode->first_child = child;\n\t}\n\n\tinline void insert_node_after(xml_node_struct* child, xml_node_struct* node)\n\t{\n\t\txml_node_struct* parent = node->parent;\n\n\t\tchild->parent = parent;\n\n\t\txml_node_struct* next = node->next_sibling;\n\n\t\tif (next)\n\t\t\tnext->prev_sibling_c = child;\n\t\telse\n\t\t\tparent->first_child->prev_sibling_c = child;\n\n\t\tchild->next_sibling = next;\n\t\tchild->prev_sibling_c = node;\n\n\t\tnode->next_sibling = child;\n\t}\n\n\tinline void insert_node_before(xml_node_struct* child, xml_node_struct* node)\n\t{\n\t\txml_node_struct* parent = node->parent;\n\n\t\tchild->parent = parent;\n\n\t\txml_node_struct* prev = node->prev_sibling_c;\n\n\t\tif (prev->next_sibling)\n\t\t\tprev->next_sibling = child;\n\t\telse\n\t\t\tparent->first_child = child;\n\n\t\tchild->prev_sibling_c = prev;\n\t\tchild->next_sibling = node;\n\n\t\tnode->prev_sibling_c = child;\n\t}\n\n\tinline void remove_node(xml_node_struct* node)\n\t{\n\t\txml_node_struct* parent = node->parent;\n\n\t\txml_node_struct* next = node->next_sibling;\n\t\txml_node_struct* prev = node->prev_sibling_c;\n\n\t\tif (next)\n\t\t\tnext->prev_sibling_c = prev;\n\t\telse\n\t\t\tparent->first_child->prev_sibling_c = prev;\n\n\t\tif (prev->next_sibling)\n\t\t\tprev->next_sibling = next;\n\t\telse\n\t\t\tparent->first_child = next;\n\n\t\tnode->parent = NULL;\n\t\tnode->prev_sibling_c = NULL;\n\t\tnode->next_sibling = NULL;\n\t}\n\n\tinline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)\n\t{\n\t\txml_attribute_struct* head = node->first_attribute;\n\n\t\tif (head)\n\t\t{\n\t\t\txml_attribute_struct* tail = head->prev_attribute_c;\n\n\t\t\ttail->next_attribute = attr;\n\t\t\tattr->prev_attribute_c = tail;\n\t\t\thead->prev_attribute_c = attr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnode->first_attribute = attr;\n\t\t\tattr->prev_attribute_c = attr;\n\t\t}\n\t}\n\n\tinline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)\n\t{\n\t\txml_attribute_struct* head = node->first_attribute;\n\n\t\tif (head)\n\t\t{\n\t\t\tattr->prev_attribute_c = head->prev_attribute_c;\n\t\t\thead->prev_attribute_c = attr;\n\t\t}\n\t\telse\n\t\t\tattr->prev_attribute_c = attr;\n\n\t\tattr->next_attribute = head;\n\t\tnode->first_attribute = attr;\n\t}\n\n\tinline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)\n\t{\n\t\txml_attribute_struct* next = place->next_attribute;\n\n\t\tif (next)\n\t\t\tnext->prev_attribute_c = attr;\n\t\telse\n\t\t\tnode->first_attribute->prev_attribute_c = attr;\n\n\t\tattr->next_attribute = next;\n\t\tattr->prev_attribute_c = place;\n\t\tplace->next_attribute = attr;\n\t}\n\n\tinline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)\n\t{\n\t\txml_attribute_struct* prev = place->prev_attribute_c;\n\n\t\tif (prev->next_attribute)\n\t\t\tprev->next_attribute = attr;\n\t\telse\n\t\t\tnode->first_attribute = attr;\n\n\t\tattr->prev_attribute_c = prev;\n\t\tattr->next_attribute = place;\n\t\tplace->prev_attribute_c = attr;\n\t}\n\n\tinline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)\n\t{\n\t\txml_attribute_struct* next = attr->next_attribute;\n\t\txml_attribute_struct* prev = attr->prev_attribute_c;\n\n\t\tif (next)\n\t\t\tnext->prev_attribute_c = prev;\n\t\telse\n\t\t\tnode->first_attribute->prev_attribute_c = prev;\n\n\t\tif (prev->next_attribute)\n\t\t\tprev->next_attribute = next;\n\t\telse\n\t\t\tnode->first_attribute = next;\n\n\t\tattr->prev_attribute_c = NULL;\n\t\tattr->next_attribute = NULL;\n\t}\n\n\tPUGI_IMPL_FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)\n\t{\n\t\tif (!alloc.reserve()) return NULL;\n\n\t\txml_node_struct* child = allocate_node(alloc, type);\n\t\tif (!child) return NULL;\n\n\t\tappend_node(child, node);\n\n\t\treturn child;\n\t}\n\n\tPUGI_IMPL_FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)\n\t{\n\t\tif (!alloc.reserve()) return NULL;\n\n\t\txml_attribute_struct* attr = allocate_attribute(alloc);\n\t\tif (!attr) return NULL;\n\n\t\tappend_attribute(attr, node);\n\n\t\treturn attr;\n\t}\nPUGI_IMPL_NS_END\n\n// Helper classes for code generation\nPUGI_IMPL_NS_BEGIN\n\tstruct opt_false\n\t{\n\t\tenum { value = 0 };\n\t};\n\n\tstruct opt_true\n\t{\n\t\tenum { value = 1 };\n\t};\nPUGI_IMPL_NS_END\n\n// Unicode utilities\nPUGI_IMPL_NS_BEGIN\n\tinline uint16_t endian_swap(uint16_t value)\n\t{\n\t\treturn static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));\n\t}\n\n\tinline uint32_t endian_swap(uint32_t value)\n\t{\n\t\treturn ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);\n\t}\n\n\tstruct utf8_counter\n\t{\n\t\ttypedef size_t value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t ch)\n\t\t{\n\t\t\t// U+0000..U+007F\n\t\t\tif (ch < 0x80) return result + 1;\n\t\t\t// U+0080..U+07FF\n\t\t\telse if (ch < 0x800) return result + 2;\n\t\t\t// U+0800..U+FFFF\n\t\t\telse return result + 3;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t)\n\t\t{\n\t\t\t// U+10000..U+10FFFF\n\t\t\treturn result + 4;\n\t\t}\n\t};\n\n\tstruct utf8_writer\n\t{\n\t\ttypedef uint8_t* value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t ch)\n\t\t{\n\t\t\t// U+0000..U+007F\n\t\t\tif (ch < 0x80)\n\t\t\t{\n\t\t\t\t*result = static_cast<uint8_t>(ch);\n\t\t\t\treturn result + 1;\n\t\t\t}\n\t\t\t// U+0080..U+07FF\n\t\t\telse if (ch < 0x800)\n\t\t\t{\n\t\t\t\tresult[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));\n\t\t\t\tresult[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));\n\t\t\t\treturn result + 2;\n\t\t\t}\n\t\t\t// U+0800..U+FFFF\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));\n\t\t\t\tresult[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));\n\t\t\t\tresult[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));\n\t\t\t\treturn result + 3;\n\t\t\t}\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t ch)\n\t\t{\n\t\t\t// U+10000..U+10FFFF\n\t\t\tresult[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));\n\t\t\tresult[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));\n\t\t\tresult[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));\n\t\t\tresult[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));\n\t\t\treturn result + 4;\n\t\t}\n\n\t\tstatic value_type any(value_type result, uint32_t ch)\n\t\t{\n\t\t\treturn (ch < 0x10000) ? low(result, ch) : high(result, ch);\n\t\t}\n\t};\n\n\tstruct utf16_counter\n\t{\n\t\ttypedef size_t value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t)\n\t\t{\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t)\n\t\t{\n\t\t\treturn result + 2;\n\t\t}\n\t};\n\n\tstruct utf16_writer\n\t{\n\t\ttypedef uint16_t* value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t ch)\n\t\t{\n\t\t\t*result = static_cast<uint16_t>(ch);\n\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t ch)\n\t\t{\n\t\t\tuint32_t msh = (ch - 0x10000U) >> 10;\n\t\t\tuint32_t lsh = (ch - 0x10000U) & 0x3ff;\n\n\t\t\tresult[0] = static_cast<uint16_t>(0xD800 + msh);\n\t\t\tresult[1] = static_cast<uint16_t>(0xDC00 + lsh);\n\n\t\t\treturn result + 2;\n\t\t}\n\n\t\tstatic value_type any(value_type result, uint32_t ch)\n\t\t{\n\t\t\treturn (ch < 0x10000) ? low(result, ch) : high(result, ch);\n\t\t}\n\t};\n\n\tstruct utf32_counter\n\t{\n\t\ttypedef size_t value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t)\n\t\t{\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t)\n\t\t{\n\t\t\treturn result + 1;\n\t\t}\n\t};\n\n\tstruct utf32_writer\n\t{\n\t\ttypedef uint32_t* value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t ch)\n\t\t{\n\t\t\t*result = ch;\n\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t ch)\n\t\t{\n\t\t\t*result = ch;\n\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type any(value_type result, uint32_t ch)\n\t\t{\n\t\t\t*result = ch;\n\n\t\t\treturn result + 1;\n\t\t}\n\t};\n\n\tstruct latin1_writer\n\t{\n\t\ttypedef uint8_t* value_type;\n\n\t\tstatic value_type low(value_type result, uint32_t ch)\n\t\t{\n\t\t\t*result = static_cast<uint8_t>(ch > 255 ? '?' : ch);\n\n\t\t\treturn result + 1;\n\t\t}\n\n\t\tstatic value_type high(value_type result, uint32_t ch)\n\t\t{\n\t\t\t(void)ch;\n\n\t\t\t*result = '?';\n\n\t\t\treturn result + 1;\n\t\t}\n\t};\n\n\tstruct utf8_decoder\n\t{\n\t\ttypedef uint8_t type;\n\n\t\ttemplate <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)\n\t\t{\n\t\t\tconst uint8_t utf8_byte_mask = 0x3f;\n\n\t\t\twhile (size)\n\t\t\t{\n\t\t\t\tuint8_t lead = *data;\n\n\t\t\t\t// 0xxxxxxx -> U+0000..U+007F\n\t\t\t\tif (lead < 0x80)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, lead);\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\n\t\t\t\t\t// process aligned single-byte (ascii) blocks\n\t\t\t\t\tif ((reinterpret_cast<uintptr_t>(data) & 3) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// round-trip through void* to silence 'cast increases required alignment of target type' warnings\n\t\t\t\t\t\twhile (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult = Traits::low(result, data[0]);\n\t\t\t\t\t\t\tresult = Traits::low(result, data[1]);\n\t\t\t\t\t\t\tresult = Traits::low(result, data[2]);\n\t\t\t\t\t\t\tresult = Traits::low(result, data[3]);\n\t\t\t\t\t\t\tdata += 4;\n\t\t\t\t\t\t\tsize -= 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// 110xxxxx -> U+0080..U+07FF\n\t\t\t\telse if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tsize -= 2;\n\t\t\t\t}\n\t\t\t\t// 1110xxxx -> U+0800-U+FFFF\n\t\t\t\telse if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));\n\t\t\t\t\tdata += 3;\n\t\t\t\t\tsize -= 3;\n\t\t\t\t}\n\t\t\t\t// 11110xxx -> U+10000..U+10FFFF\n\t\t\t\telse if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));\n\t\t\t\t\tdata += 4;\n\t\t\t\t\tsize -= 4;\n\t\t\t\t}\n\t\t\t\t// 10xxxxxx or 11111xxx -> invalid\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate <typename opt_swap> struct utf16_decoder\n\t{\n\t\ttypedef uint16_t type;\n\n\t\ttemplate <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)\n\t\t{\n\t\t\twhile (size)\n\t\t\t{\n\t\t\t\tuint16_t lead = opt_swap::value ? endian_swap(*data) : *data;\n\n\t\t\t\t// U+0000..U+D7FF\n\t\t\t\tif (lead < 0xD800)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, lead);\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t\t// U+E000..U+FFFF\n\t\t\t\telse if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, lead);\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t\t// surrogate pair lead\n\t\t\t\telse if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)\n\t\t\t\t{\n\t\t\t\t\tuint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];\n\n\t\t\t\t\tif (static_cast<unsigned int>(next - 0xDC00) < 0x400)\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));\n\t\t\t\t\t\tdata += 2;\n\t\t\t\t\t\tsize -= 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tdata += 1;\n\t\t\t\t\t\tsize -= 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate <typename opt_swap> struct utf32_decoder\n\t{\n\t\ttypedef uint32_t type;\n\n\t\ttemplate <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)\n\t\t{\n\t\t\twhile (size)\n\t\t\t{\n\t\t\t\tuint32_t lead = opt_swap::value ? endian_swap(*data) : *data;\n\n\t\t\t\t// U+0000..U+FFFF\n\t\t\t\tif (lead < 0x10000)\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::low(result, lead);\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t\t// U+10000..U+10FFFF\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult = Traits::high(result, lead);\n\t\t\t\t\tdata += 1;\n\t\t\t\t\tsize -= 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n\n\tstruct latin1_decoder\n\t{\n\t\ttypedef uint8_t type;\n\n\t\ttemplate <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)\n\t\t{\n\t\t\twhile (size)\n\t\t\t{\n\t\t\t\tresult = Traits::low(result, *data);\n\t\t\t\tdata += 1;\n\t\t\t\tsize -= 1;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate <size_t size> struct wchar_selector;\n\n\ttemplate <> struct wchar_selector<2>\n\t{\n\t\ttypedef uint16_t type;\n\t\ttypedef utf16_counter counter;\n\t\ttypedef utf16_writer writer;\n\t\ttypedef utf16_decoder<opt_false> decoder;\n\t};\n\n\ttemplate <> struct wchar_selector<4>\n\t{\n\t\ttypedef uint32_t type;\n\t\ttypedef utf32_counter counter;\n\t\ttypedef utf32_writer writer;\n\t\ttypedef utf32_decoder<opt_false> decoder;\n\t};\n\n\ttypedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;\n\ttypedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;\n\n\tstruct wchar_decoder\n\t{\n\t\ttypedef wchar_t type;\n\n\t\ttemplate <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)\n\t\t{\n\t\t\ttypedef wchar_selector<sizeof(wchar_t)>::decoder decoder;\n\n\t\t\treturn decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);\n\t\t}\n\t};\n\n#ifdef PUGIXML_WCHAR_MODE\n\tPUGI_IMPL_FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)\n\t{\n\t\tfor (size_t i = 0; i < length; ++i)\n\t\t\tresult[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));\n\t}\n#endif\nPUGI_IMPL_NS_END\n\nPUGI_IMPL_NS_BEGIN\n\tenum chartype_t\n\t{\n\t\tct_parse_pcdata = 1,\t// \\0, &, \\r, <\n\t\tct_parse_attr = 2,\t\t// \\0, &, \\r, ', \"\n\t\tct_parse_attr_ws = 4,\t// \\0, &, \\r, ', \", \\n, tab\n\t\tct_space = 8,\t\t\t// \\r, \\n, space, tab\n\t\tct_parse_cdata = 16,\t// \\0, ], >, \\r\n\t\tct_parse_comment = 32,\t// \\0, -, >, \\r\n\t\tct_symbol = 64,\t\t\t// Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .\n\t\tct_start_symbol = 128\t// Any symbol > 127, a-z, A-Z, _, :\n\t};\n\n\tstatic const unsigned char chartype_table[256] =\n\t{\n\t\t55,  0,   0,   0,   0,   0,   0,   0,      0,   12,  12,  0,   0,   63,  0,   0,   // 0-15\n\t\t0,   0,   0,   0,   0,   0,   0,   0,      0,   0,   0,   0,   0,   0,   0,   0,   // 16-31\n\t\t8,   0,   6,   0,   0,   0,   7,   6,      0,   0,   0,   0,   0,   96,  64,  0,   // 32-47\n\t\t64,  64,  64,  64,  64,  64,  64,  64,     64,  64,  192, 0,   1,   0,   48,  0,   // 48-63\n\t\t0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 64-79\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0,   0,   16,  0,   192, // 80-95\n\t\t0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 96-111\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0, 0, 0, 0, 0,           // 112-127\n\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 128+\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,\n\t\t192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192\n\t};\n\n\tenum chartypex_t\n\t{\n\t\tctx_special_pcdata = 1,   // Any symbol >= 0 and < 32 (except \\t, \\r, \\n), &, <, >\n\t\tctx_special_attr = 2,     // Any symbol >= 0 and < 32, &, <, \", '\n\t\tctx_start_symbol = 4,\t  // Any symbol > 127, a-z, A-Z, _\n\t\tctx_digit = 8,\t\t\t  // 0-9\n\t\tctx_symbol = 16\t\t\t  // Any symbol > 127, a-z, A-Z, 0-9, _, -, .\n\t};\n\n\tstatic const unsigned char chartypex_table[256] =\n\t{\n\t\t3,  3,  3,  3,  3,  3,  3,  3,     3,  2,  2,  3,  3,  2,  3,  3,     // 0-15\n\t\t3,  3,  3,  3,  3,  3,  3,  3,     3,  3,  3,  3,  3,  3,  3,  3,     // 16-31\n\t\t0,  0,  2,  0,  0,  0,  3,  2,     0,  0,  0,  0,  0, 16, 16,  0,     // 32-47\n\t\t24, 24, 24, 24, 24, 24, 24, 24,    24, 24, 0,  0,  3,  0,  1,  0,     // 48-63\n\n\t\t0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 64-79\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  20,    // 80-95\n\t\t0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 96-111\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  0,     // 112-127\n\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 128+\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,\n\t\t20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20\n\t};\n\n#ifdef PUGIXML_WCHAR_MODE\n\t#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))\n#else\n\t#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))\n#endif\n\n\t#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)\n\t#define PUGI_IMPL_IS_CHARTYPEX(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartypex_table)\n\n\tPUGI_IMPL_FN bool is_little_endian()\n\t{\n\t\tunsigned int ui = 1;\n\n\t\treturn *reinterpret_cast<unsigned char*>(&ui) == 1;\n\t}\n\n\tPUGI_IMPL_FN xml_encoding get_wchar_encoding()\n\t{\n\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);\n\n\t\tif (sizeof(wchar_t) == 2)\n\t\t\treturn is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\t\telse\n\t\t\treturn is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\t}\n\n\tPUGI_IMPL_FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)\n\t{\n\t#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }\n\t#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }\n\n\t\t// check if we have a non-empty XML declaration\n\t\tif (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI_IMPL_IS_CHARTYPE(data[5], ct_space)))\n\t\t\treturn false;\n\n\t\t// scan XML declaration until the encoding field\n\t\tfor (size_t i = 6; i + 1 < size; ++i)\n\t\t{\n\t\t\t// declaration can not contain ? in quoted values\n\t\t\tif (data[i] == '?')\n\t\t\t\treturn false;\n\n\t\t\tif (data[i] == 'e' && data[i + 1] == 'n')\n\t\t\t{\n\t\t\t\tsize_t offset = i;\n\n\t\t\t\t// encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed\n\t\t\t\tPUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');\n\t\t\t\tPUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');\n\n\t\t\t\t// S? = S?\n\t\t\t\tPUGI_IMPL_SCANCHARTYPE(ct_space);\n\t\t\t\tPUGI_IMPL_SCANCHAR('=');\n\t\t\t\tPUGI_IMPL_SCANCHARTYPE(ct_space);\n\n\t\t\t\t// the only two valid delimiters are ' and \"\n\t\t\t\tuint8_t delimiter = (offset < size && data[offset] == '\"') ? '\"' : '\\'';\n\n\t\t\t\tPUGI_IMPL_SCANCHAR(delimiter);\n\n\t\t\t\tsize_t start = offset;\n\n\t\t\t\tout_encoding = data + offset;\n\n\t\t\t\tPUGI_IMPL_SCANCHARTYPE(ct_symbol);\n\n\t\t\t\tout_length = offset - start;\n\n\t\t\t\tPUGI_IMPL_SCANCHAR(delimiter);\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\n\t#undef PUGI_IMPL_SCANCHAR\n\t#undef PUGI_IMPL_SCANCHARTYPE\n\t}\n\n\tPUGI_IMPL_FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)\n\t{\n\t\t// skip encoding autodetection if input buffer is too small\n\t\tif (size < 4) return encoding_utf8;\n\n\t\tuint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];\n\n\t\t// look for BOM in first few bytes\n\t\tif (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;\n\t\tif (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;\n\t\tif (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;\n\t\tif (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;\n\t\tif (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;\n\n\t\t// look for <, <? or <?xm in various encodings\n\t\tif (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;\n\t\tif (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;\n\t\tif (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;\n\t\tif (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;\n\n\t\t// look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)\n\t\tif (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;\n\t\tif (d0 == 0x3c && d1 == 0) return encoding_utf16_le;\n\n\t\t// no known BOM detected; parse declaration\n\t\tconst uint8_t* enc = NULL;\n\t\tsize_t enc_length = 0;\n\n\t\tif (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))\n\t\t{\n\t\t\t// iso-8859-1 (case-insensitive)\n\t\t\tif (enc_length == 10\n\t\t\t\t&& (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o'\n\t\t\t\t&& enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9'\n\t\t\t\t&& enc[8] == '-' && enc[9] == '1')\n\t\t\t\treturn encoding_latin1;\n\n\t\t\t// latin1 (case-insensitive)\n\t\t\tif (enc_length == 6\n\t\t\t\t&& (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't'\n\t\t\t\t&& (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n'\n\t\t\t\t&& enc[5] == '1')\n\t\t\t\treturn encoding_latin1;\n\t\t}\n\n\t\treturn encoding_utf8;\n\t}\n\n\tPUGI_IMPL_FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)\n\t{\n\t\t// replace wchar encoding with utf implementation\n\t\tif (encoding == encoding_wchar) return get_wchar_encoding();\n\n\t\t// replace utf16 encoding with utf16 with specific endianness\n\t\tif (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t// replace utf32 encoding with utf32 with specific endianness\n\t\tif (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t// only do autodetection if no explicit encoding is requested\n\t\tif (encoding != encoding_auto) return encoding;\n\n\t\t// try to guess encoding (based on XML specification, Appendix F.1)\n\t\tconst uint8_t* data = static_cast<const uint8_t*>(contents);\n\n\t\treturn guess_buffer_encoding(data, size);\n\t}\n\n\tPUGI_IMPL_FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)\n\t{\n\t\tsize_t length = size / sizeof(char_t);\n\n\t\tif (is_mutable)\n\t\t{\n\t\t\tout_buffer = static_cast<char_t*>(const_cast<void*>(contents));\n\t\t\tout_length = length;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tchar_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!buffer) return false;\n\n\t\t\tif (contents)\n\t\t\t\tmemcpy(buffer, contents, length * sizeof(char_t));\n\t\t\telse\n\t\t\t\tassert(length == 0);\n\n\t\t\tbuffer[length] = 0;\n\n\t\t\tout_buffer = buffer;\n\t\t\tout_length = length + 1;\n\t\t}\n\n\t\treturn true;\n\t}\n\n#ifdef PUGIXML_WCHAR_MODE\n\tPUGI_IMPL_FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)\n\t{\n\t\treturn (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||\n\t\t\t   (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);\n\t}\n\n\tPUGI_IMPL_FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)\n\t{\n\t\tconst char_t* data = static_cast<const char_t*>(contents);\n\t\tsize_t length = size / sizeof(char_t);\n\n\t\tif (is_mutable)\n\t\t{\n\t\t\tchar_t* buffer = const_cast<char_t*>(data);\n\n\t\t\tconvert_wchar_endian_swap(buffer, data, length);\n\n\t\t\tout_buffer = buffer;\n\t\t\tout_length = length;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tchar_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!buffer) return false;\n\n\t\t\tconvert_wchar_endian_swap(buffer, data, length);\n\t\t\tbuffer[length] = 0;\n\n\t\t\tout_buffer = buffer;\n\t\t\tout_length = length + 1;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\ttemplate <typename D> PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)\n\t{\n\t\tconst typename D::type* data = static_cast<const typename D::type*>(contents);\n\t\tsize_t data_length = size / sizeof(typename D::type);\n\n\t\t// first pass: get length in wchar_t units\n\t\tsize_t length = D::process(data, data_length, 0, wchar_counter());\n\n\t\t// allocate buffer of suitable length\n\t\tchar_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\tif (!buffer) return false;\n\n\t\t// second pass: convert utf16 input to wchar_t\n\t\twchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);\n\t\twchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());\n\n\t\tassert(oend == obegin + length);\n\t\t*oend = 0;\n\n\t\tout_buffer = buffer;\n\t\tout_length = length + 1;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)\n\t{\n\t\t// get native encoding\n\t\txml_encoding wchar_encoding = get_wchar_encoding();\n\n\t\t// fast path: no conversion required\n\t\tif (encoding == wchar_encoding)\n\t\t\treturn get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);\n\n\t\t// only endian-swapping is required\n\t\tif (need_endian_swap_utf(encoding, wchar_encoding))\n\t\t\treturn convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);\n\n\t\t// source encoding is utf8\n\t\tif (encoding == encoding_utf8)\n\t\t\treturn convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());\n\n\t\t// source encoding is utf16\n\t\tif (encoding == encoding_utf16_be || encoding == encoding_utf16_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t\treturn (native_encoding == encoding) ?\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());\n\t\t}\n\n\t\t// source encoding is utf32\n\t\tif (encoding == encoding_utf32_be || encoding == encoding_utf32_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t\treturn (native_encoding == encoding) ?\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());\n\t\t}\n\n\t\t// source encoding is latin1\n\t\tif (encoding == encoding_latin1)\n\t\t\treturn convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());\n\n\t\tassert(false && \"Invalid encoding\"); // unreachable\n\t\treturn false;\n\t}\n#else\n\ttemplate <typename D> PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)\n\t{\n\t\tconst typename D::type* data = static_cast<const typename D::type*>(contents);\n\t\tsize_t data_length = size / sizeof(typename D::type);\n\n\t\t// first pass: get length in utf8 units\n\t\tsize_t length = D::process(data, data_length, 0, utf8_counter());\n\n\t\t// allocate buffer of suitable length\n\t\tchar_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\tif (!buffer) return false;\n\n\t\t// second pass: convert utf16 input to utf8\n\t\tuint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);\n\t\tuint8_t* oend = D::process(data, data_length, obegin, utf8_writer());\n\n\t\tassert(oend == obegin + length);\n\t\t*oend = 0;\n\n\t\tout_buffer = buffer;\n\t\tout_length = length + 1;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)\n\t{\n\t\tfor (size_t i = 0; i < size; ++i)\n\t\t\tif (data[i] > 127)\n\t\t\t\treturn i;\n\n\t\treturn size;\n\t}\n\n\tPUGI_IMPL_FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)\n\t{\n\t\tconst uint8_t* data = static_cast<const uint8_t*>(contents);\n\t\tsize_t data_length = size;\n\n\t\t// get size of prefix that does not need utf8 conversion\n\t\tsize_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);\n\t\tassert(prefix_length <= data_length);\n\n\t\tconst uint8_t* postfix = data + prefix_length;\n\t\tsize_t postfix_length = data_length - prefix_length;\n\n\t\t// if no conversion is needed, just return the original buffer\n\t\tif (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);\n\n\t\t// first pass: get length in utf8 units\n\t\tsize_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());\n\n\t\t// allocate buffer of suitable length\n\t\tchar_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\tif (!buffer) return false;\n\n\t\t// second pass: convert latin1 input to utf8\n\t\tmemcpy(buffer, data, prefix_length);\n\n\t\tuint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);\n\t\tuint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());\n\n\t\tassert(oend == obegin + length);\n\t\t*oend = 0;\n\n\t\tout_buffer = buffer;\n\t\tout_length = length + 1;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)\n\t{\n\t\t// fast path: no conversion required\n\t\tif (encoding == encoding_utf8)\n\t\t\treturn get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);\n\n\t\t// source encoding is utf16\n\t\tif (encoding == encoding_utf16_be || encoding == encoding_utf16_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t\treturn (native_encoding == encoding) ?\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());\n\t\t}\n\n\t\t// source encoding is utf32\n\t\tif (encoding == encoding_utf32_be || encoding == encoding_utf32_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t\treturn (native_encoding == encoding) ?\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :\n\t\t\t\tconvert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());\n\t\t}\n\n\t\t// source encoding is latin1\n\t\tif (encoding == encoding_latin1)\n\t\t\treturn convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);\n\n\t\tassert(false && \"Invalid encoding\"); // unreachable\n\t\treturn false;\n\t}\n#endif\n\n\tPUGI_IMPL_FN size_t as_utf8_begin(const wchar_t* str, size_t length)\n\t{\n\t\t// get length in utf8 characters\n\t\treturn wchar_decoder::process(str, length, 0, utf8_counter());\n\t}\n\n\tPUGI_IMPL_FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)\n\t{\n\t\t// convert to utf8\n\t\tuint8_t* begin = reinterpret_cast<uint8_t*>(buffer);\n\t\tuint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());\n\n\t\tassert(begin + size == end);\n\t\t(void)!end;\n\t\t(void)!size;\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN std::string as_utf8_impl(const wchar_t* str, size_t length)\n\t{\n\t\t// first pass: get length in utf8 characters\n\t\tsize_t size = as_utf8_begin(str, length);\n\n\t\t// allocate resulting string\n\t\tstd::string result;\n\t\tresult.resize(size);\n\n\t\t// second pass: convert to utf8\n\t\tif (size > 0) as_utf8_end(&result[0], size, str, length);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)\n\t{\n\t\tconst uint8_t* data = reinterpret_cast<const uint8_t*>(str);\n\n\t\t// first pass: get length in wchar_t units\n\t\tsize_t length = utf8_decoder::process(data, size, 0, wchar_counter());\n\n\t\t// allocate resulting string\n\t\tstd::basic_string<wchar_t> result;\n\t\tresult.resize(length);\n\n\t\t// second pass: convert to wchar_t\n\t\tif (length > 0)\n\t\t{\n\t\t\twchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);\n\t\t\twchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());\n\n\t\t\tassert(begin + length == end);\n\t\t\t(void)!end;\n\t\t}\n\n\t\treturn result;\n\t}\n#endif\n\n\ttemplate <typename Header>\n\tinline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)\n\t{\n\t\t// never reuse shared memory\n\t\tif (header & xml_memory_page_contents_shared_mask) return false;\n\n\t\tsize_t target_length = strlength(target);\n\n\t\t// always reuse document buffer memory if possible\n\t\tif ((header & header_mask) == 0) return target_length >= length;\n\n\t\t// reuse heap memory if waste is not too great\n\t\tconst size_t reuse_threshold = 32;\n\n\t\treturn target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);\n\t}\n\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)\n\t{\n\t\tassert((header & header_mask) == 0 || dest); // header bit indicates whether dest was previously allocated\n\n\t\tif (source_length == 0)\n\t\t{\n\t\t\t// empty string and null pointer are equivalent, so just deallocate old memory\n\t\t\txml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator;\n\n\t\t\tif (header & header_mask) alloc->deallocate_string(dest);\n\n\t\t\t// mark the string as not allocated\n\t\t\tdest = NULL;\n\t\t\theader &= ~header_mask;\n\n\t\t\treturn true;\n\t\t}\n\t\telse if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))\n\t\t{\n\t\t\t// we can reuse old buffer, so just copy the new data (including zero terminator)\n\t\t\tmemcpy(dest, source, source_length * sizeof(char_t));\n\t\t\tdest[source_length] = 0;\n\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\txml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator;\n\n\t\t\tif (!alloc->reserve()) return false;\n\n\t\t\t// allocate new buffer\n\t\t\tchar_t* buf = alloc->allocate_string(source_length + 1);\n\t\t\tif (!buf) return false;\n\n\t\t\t// copy the string (including zero terminator)\n\t\t\tmemcpy(buf, source, source_length * sizeof(char_t));\n\t\t\tbuf[source_length] = 0;\n\n\t\t\t// deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)\n\t\t\tif (header & header_mask) alloc->deallocate_string(dest);\n\n\t\t\t// the string is now allocated, so set the flag\n\t\t\tdest = buf;\n\t\t\theader |= header_mask;\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tstruct gap\n\t{\n\t\tchar_t* end;\n\t\tsize_t size;\n\n\t\tgap(): end(NULL), size(0)\n\t\t{\n\t\t}\n\n\t\t// Push new gap, move s count bytes further (skipping the gap).\n\t\t// Collapse previous gap.\n\t\tvoid push(char_t*& s, size_t count)\n\t\t{\n\t\t\tif (end) // there was a gap already; collapse it\n\t\t\t{\n\t\t\t\t// Move [old_gap_end, new_gap_start) to [old_gap_start, ...)\n\t\t\t\tassert(s >= end);\n\t\t\t\tmemmove(end - size, end, (s - end) * sizeof(char_t));\n\t\t\t}\n\n\t\t\ts += count; // end of current gap\n\n\t\t\t// \"merge\" two gaps\n\t\t\tend = s;\n\t\t\tsize += count;\n\t\t}\n\n\t\t// Collapse all gaps, return past-the-end pointer\n\t\tchar_t* flush(char_t* s)\n\t\t{\n\t\t\tif (end)\n\t\t\t{\n\t\t\t\t// Move [old_gap_end, current_pos) to [old_gap_start, ...)\n\t\t\t\tassert(s >= end);\n\t\t\t\tmemmove(end - size, end, (s - end) * sizeof(char_t));\n\n\t\t\t\treturn s - size;\n\t\t\t}\n\t\t\telse return s;\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN char_t* strconv_escape(char_t* s, gap& g)\n\t{\n\t\tchar_t* stre = s + 1;\n\n\t\tswitch (*stre)\n\t\t{\n\t\t\tcase '#':\t// &#...\n\t\t\t{\n\t\t\t\tunsigned int ucsc = 0;\n\n\t\t\t\tif (stre[1] == 'x') // &#x... (hex code)\n\t\t\t\t{\n\t\t\t\t\tstre += 2;\n\n\t\t\t\t\tchar_t ch = *stre;\n\n\t\t\t\t\tif (ch == ';') return stre;\n\n\t\t\t\t\tfor (;;)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (static_cast<unsigned int>(ch - '0') <= 9)\n\t\t\t\t\t\t\tucsc = 16 * ucsc + (ch - '0');\n\t\t\t\t\t\telse if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)\n\t\t\t\t\t\t\tucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);\n\t\t\t\t\t\telse if (ch == ';')\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse // cancel\n\t\t\t\t\t\t\treturn stre;\n\n\t\t\t\t\t\tch = *++stre;\n\t\t\t\t\t}\n\n\t\t\t\t\t++stre;\n\t\t\t\t}\n\t\t\t\telse\t// &#... (dec code)\n\t\t\t\t{\n\t\t\t\t\tchar_t ch = *++stre;\n\n\t\t\t\t\tif (ch == ';') return stre;\n\n\t\t\t\t\tfor (;;)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (static_cast<unsigned int>(ch - '0') <= 9)\n\t\t\t\t\t\t\tucsc = 10 * ucsc + (ch - '0');\n\t\t\t\t\t\telse if (ch == ';')\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse // cancel\n\t\t\t\t\t\t\treturn stre;\n\n\t\t\t\t\t\tch = *++stre;\n\t\t\t\t\t}\n\n\t\t\t\t\t++stre;\n\t\t\t\t}\n\n\t\t\t#ifdef PUGIXML_WCHAR_MODE\n\t\t\t\ts = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));\n\t\t\t#else\n\t\t\t\ts = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));\n\t\t\t#endif\n\n\t\t\t\tg.push(s, stre - s);\n\t\t\t\treturn stre;\n\t\t\t}\n\n\t\t\tcase 'a':\t// &a\n\t\t\t{\n\t\t\t\t++stre;\n\n\t\t\t\tif (*stre == 'm') // &am\n\t\t\t\t{\n\t\t\t\t\tif (*++stre == 'p' && *++stre == ';') // &amp;\n\t\t\t\t\t{\n\t\t\t\t\t\t*s++ = '&';\n\t\t\t\t\t\t++stre;\n\n\t\t\t\t\t\tg.push(s, stre - s);\n\t\t\t\t\t\treturn stre;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (*stre == 'p') // &ap\n\t\t\t\t{\n\t\t\t\t\tif (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;\n\t\t\t\t\t{\n\t\t\t\t\t\t*s++ = '\\'';\n\t\t\t\t\t\t++stre;\n\n\t\t\t\t\t\tg.push(s, stre - s);\n\t\t\t\t\t\treturn stre;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'g': // &g\n\t\t\t{\n\t\t\t\tif (*++stre == 't' && *++stre == ';') // &gt;\n\t\t\t\t{\n\t\t\t\t\t*s++ = '>';\n\t\t\t\t\t++stre;\n\n\t\t\t\t\tg.push(s, stre - s);\n\t\t\t\t\treturn stre;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'l': // &l\n\t\t\t{\n\t\t\t\tif (*++stre == 't' && *++stre == ';') // &lt;\n\t\t\t\t{\n\t\t\t\t\t*s++ = '<';\n\t\t\t\t\t++stre;\n\n\t\t\t\t\tg.push(s, stre - s);\n\t\t\t\t\treturn stre;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'q': // &q\n\t\t\t{\n\t\t\t\tif (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;\n\t\t\t\t{\n\t\t\t\t\t*s++ = '\"';\n\t\t\t\t\t++stre;\n\n\t\t\t\t\tg.push(s, stre - s);\n\t\t\t\t\treturn stre;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn stre;\n\t}\n\n\t// Parser utilities\n\t#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))\n\t#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }\n\t#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )\n\t#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }\n\t#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }\n\t#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }\n\t#define PUGI_IMPL_SCANWHILE(X)          { while (X) ++s; }\n\t#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }\n\t#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }\n\t#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(NULL)\n\t#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }\n\n\tPUGI_IMPL_FN char_t* strconv_comment(char_t* s, char_t endch)\n\t{\n\t\tgap g;\n\n\t\twhile (true)\n\t\t{\n\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_comment));\n\n\t\t\tif (*s == '\\r') // Either a single 0x0d or 0x0d 0x0a pair\n\t\t\t{\n\t\t\t\t*s++ = '\\n'; // replace first one with 0x0a\n\n\t\t\t\tif (*s == '\\n') g.push(s, 1);\n\t\t\t}\n\t\t\telse if (s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')) // comment ends here\n\t\t\t{\n\t\t\t\t*g.flush(s) = 0;\n\n\t\t\t\treturn s + (s[2] == '>' ? 3 : 2);\n\t\t\t}\n\t\t\telse if (*s == 0)\n\t\t\t{\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\telse ++s;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN char_t* strconv_cdata(char_t* s, char_t endch)\n\t{\n\t\tgap g;\n\n\t\twhile (true)\n\t\t{\n\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_cdata));\n\n\t\t\tif (*s == '\\r') // Either a single 0x0d or 0x0d 0x0a pair\n\t\t\t{\n\t\t\t\t*s++ = '\\n'; // replace first one with 0x0a\n\n\t\t\t\tif (*s == '\\n') g.push(s, 1);\n\t\t\t}\n\t\t\telse if (s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')) // CDATA ends here\n\t\t\t{\n\t\t\t\t*g.flush(s) = 0;\n\n\t\t\t\treturn s + 1;\n\t\t\t}\n\t\t\telse if (*s == 0)\n\t\t\t{\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\telse ++s;\n\t\t}\n\t}\n\n\ttypedef char_t* (*strconv_pcdata_t)(char_t*);\n\n\ttemplate <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl\n\t{\n\t\tstatic char_t* parse(char_t* s)\n\t\t{\n\t\t\tgap g;\n\n\t\t\tchar_t* begin = s;\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_pcdata));\n\n\t\t\t\tif (*s == '<') // PCDATA ends here\n\t\t\t\t{\n\t\t\t\t\tchar_t* end = g.flush(s);\n\n\t\t\t\t\tif (opt_trim::value)\n\t\t\t\t\t\twhile (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))\n\t\t\t\t\t\t\t--end;\n\n\t\t\t\t\t*end = 0;\n\n\t\t\t\t\treturn s + 1;\n\t\t\t\t}\n\t\t\t\telse if (opt_eol::value && *s == '\\r') // Either a single 0x0d or 0x0d 0x0a pair\n\t\t\t\t{\n\t\t\t\t\t*s++ = '\\n'; // replace first one with 0x0a\n\n\t\t\t\t\tif (*s == '\\n') g.push(s, 1);\n\t\t\t\t}\n\t\t\t\telse if (opt_escape::value && *s == '&')\n\t\t\t\t{\n\t\t\t\t\ts = strconv_escape(s, g);\n\t\t\t\t}\n\t\t\t\telse if (*s == 0)\n\t\t\t\t{\n\t\t\t\t\tchar_t* end = g.flush(s);\n\n\t\t\t\t\tif (opt_trim::value)\n\t\t\t\t\t\twhile (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))\n\t\t\t\t\t\t\t--end;\n\n\t\t\t\t\t*end = 0;\n\n\t\t\t\t\treturn s;\n\t\t\t\t}\n\t\t\t\telse ++s;\n\t\t\t}\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)\n\t{\n\t\tPUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);\n\n\t\tswitch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above\n\t\t{\n\t\tcase 0: return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse;\n\t\tcase 1: return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse;\n\t\tcase 2: return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse;\n\t\tcase 3: return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse;\n\t\tcase 4: return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse;\n\t\tcase 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;\n\t\tcase 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;\n\t\tcase 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse;\n\t\tdefault: assert(false); return NULL; // unreachable\n\t\t}\n\t}\n\n\ttypedef char_t* (*strconv_attribute_t)(char_t*, char_t);\n\n\ttemplate <typename opt_escape> struct strconv_attribute_impl\n\t{\n\t\tstatic char_t* parse_wnorm(char_t* s, char_t end_quote)\n\t\t{\n\t\t\tgap g;\n\n\t\t\t// trim leading whitespaces\n\t\t\tif (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))\n\t\t\t{\n\t\t\t\tchar_t* str = s;\n\n\t\t\t\tdo ++str;\n\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*str, ct_space));\n\n\t\t\t\tg.push(s, str - s);\n\t\t\t}\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));\n\n\t\t\t\tif (*s == end_quote)\n\t\t\t\t{\n\t\t\t\t\tchar_t* str = g.flush(s);\n\n\t\t\t\t\tdo *str-- = 0;\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*str, ct_space));\n\n\t\t\t\t\treturn s + 1;\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))\n\t\t\t\t{\n\t\t\t\t\t*s++ = ' ';\n\n\t\t\t\t\tif (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))\n\t\t\t\t\t{\n\t\t\t\t\t\tchar_t* str = s + 1;\n\t\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)) ++str;\n\n\t\t\t\t\t\tg.push(s, str - s);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (opt_escape::value && *s == '&')\n\t\t\t\t{\n\t\t\t\t\ts = strconv_escape(s, g);\n\t\t\t\t}\n\t\t\t\telse if (!*s)\n\t\t\t\t{\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t\telse ++s;\n\t\t\t}\n\t\t}\n\n\t\tstatic char_t* parse_wconv(char_t* s, char_t end_quote)\n\t\t{\n\t\t\tgap g;\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws));\n\n\t\t\t\tif (*s == end_quote)\n\t\t\t\t{\n\t\t\t\t\t*g.flush(s) = 0;\n\n\t\t\t\t\treturn s + 1;\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))\n\t\t\t\t{\n\t\t\t\t\tif (*s == '\\r')\n\t\t\t\t\t{\n\t\t\t\t\t\t*s++ = ' ';\n\n\t\t\t\t\t\tif (*s == '\\n') g.push(s, 1);\n\t\t\t\t\t}\n\t\t\t\t\telse *s++ = ' ';\n\t\t\t\t}\n\t\t\t\telse if (opt_escape::value && *s == '&')\n\t\t\t\t{\n\t\t\t\t\ts = strconv_escape(s, g);\n\t\t\t\t}\n\t\t\t\telse if (!*s)\n\t\t\t\t{\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t\telse ++s;\n\t\t\t}\n\t\t}\n\n\t\tstatic char_t* parse_eol(char_t* s, char_t end_quote)\n\t\t{\n\t\t\tgap g;\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr));\n\n\t\t\t\tif (*s == end_quote)\n\t\t\t\t{\n\t\t\t\t\t*g.flush(s) = 0;\n\n\t\t\t\t\treturn s + 1;\n\t\t\t\t}\n\t\t\t\telse if (*s == '\\r')\n\t\t\t\t{\n\t\t\t\t\t*s++ = '\\n';\n\n\t\t\t\t\tif (*s == '\\n') g.push(s, 1);\n\t\t\t\t}\n\t\t\t\telse if (opt_escape::value && *s == '&')\n\t\t\t\t{\n\t\t\t\t\ts = strconv_escape(s, g);\n\t\t\t\t}\n\t\t\t\telse if (!*s)\n\t\t\t\t{\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t\telse ++s;\n\t\t\t}\n\t\t}\n\n\t\tstatic char_t* parse_simple(char_t* s, char_t end_quote)\n\t\t{\n\t\t\tgap g;\n\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr));\n\n\t\t\t\tif (*s == end_quote)\n\t\t\t\t{\n\t\t\t\t\t*g.flush(s) = 0;\n\n\t\t\t\t\treturn s + 1;\n\t\t\t\t}\n\t\t\t\telse if (opt_escape::value && *s == '&')\n\t\t\t\t{\n\t\t\t\t\ts = strconv_escape(s, g);\n\t\t\t\t}\n\t\t\t\telse if (!*s)\n\t\t\t\t{\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t\telse ++s;\n\t\t\t}\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)\n\t{\n\t\tPUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);\n\n\t\tswitch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above\n\t\t{\n\t\tcase 0:  return strconv_attribute_impl<opt_false>::parse_simple;\n\t\tcase 1:  return strconv_attribute_impl<opt_true>::parse_simple;\n\t\tcase 2:  return strconv_attribute_impl<opt_false>::parse_eol;\n\t\tcase 3:  return strconv_attribute_impl<opt_true>::parse_eol;\n\t\tcase 4:  return strconv_attribute_impl<opt_false>::parse_wconv;\n\t\tcase 5:  return strconv_attribute_impl<opt_true>::parse_wconv;\n\t\tcase 6:  return strconv_attribute_impl<opt_false>::parse_wconv;\n\t\tcase 7:  return strconv_attribute_impl<opt_true>::parse_wconv;\n\t\tcase 8:  return strconv_attribute_impl<opt_false>::parse_wnorm;\n\t\tcase 9:  return strconv_attribute_impl<opt_true>::parse_wnorm;\n\t\tcase 10: return strconv_attribute_impl<opt_false>::parse_wnorm;\n\t\tcase 11: return strconv_attribute_impl<opt_true>::parse_wnorm;\n\t\tcase 12: return strconv_attribute_impl<opt_false>::parse_wnorm;\n\t\tcase 13: return strconv_attribute_impl<opt_true>::parse_wnorm;\n\t\tcase 14: return strconv_attribute_impl<opt_false>::parse_wnorm;\n\t\tcase 15: return strconv_attribute_impl<opt_true>::parse_wnorm;\n\t\tdefault: assert(false); return NULL; // unreachable\n\t\t}\n\t}\n\n\tinline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)\n\t{\n\t\txml_parse_result result;\n\t\tresult.status = status;\n\t\tresult.offset = offset;\n\n\t\treturn result;\n\t}\n\n\tstruct xml_parser\n\t{\n\t\txml_allocator* alloc;\n\t\tchar_t* error_offset;\n\t\txml_parse_status error_status;\n\n\t\txml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(NULL), error_status(status_ok)\n\t\t{\n\t\t}\n\n\t\t// DOCTYPE consists of nested sections of the following possible types:\n\t\t// <!-- ... -->, <? ... ?>, \"...\", '...'\n\t\t// <![...]]>\n\t\t// <!...>\n\t\t// First group can not contain nested groups\n\t\t// Second group can contain nested groups of the same type\n\t\t// Third group can contain all other groups\n\t\tchar_t* parse_doctype_primitive(char_t* s)\n\t\t{\n\t\t\tif (*s == '\"' || *s == '\\'')\n\t\t\t{\n\t\t\t\t// quoted string\n\t\t\t\tchar_t ch = *s++;\n\t\t\t\tPUGI_IMPL_SCANFOR(*s == ch);\n\t\t\t\tif (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\t\ts++;\n\t\t\t}\n\t\t\telse if (s[0] == '<' && s[1] == '?')\n\t\t\t{\n\t\t\t\t// <? ... ?>\n\t\t\t\ts += 2;\n\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype\n\t\t\t\tif (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\t\ts += 2;\n\t\t\t}\n\t\t\telse if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')\n\t\t\t{\n\t\t\t\ts += 4;\n\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype\n\t\t\t\tif (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\t\ts += 3;\n\t\t\t}\n\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\treturn s;\n\t\t}\n\n\t\tchar_t* parse_doctype_ignore(char_t* s)\n\t\t{\n\t\t\tsize_t depth = 0;\n\n\t\t\tassert(s[0] == '<' && s[1] == '!' && s[2] == '[');\n\t\t\ts += 3;\n\n\t\t\twhile (*s)\n\t\t\t{\n\t\t\t\tif (s[0] == '<' && s[1] == '!' && s[2] == '[')\n\t\t\t\t{\n\t\t\t\t\t// nested ignore section\n\t\t\t\t\ts += 3;\n\t\t\t\t\tdepth++;\n\t\t\t\t}\n\t\t\t\telse if (s[0] == ']' && s[1] == ']' && s[2] == '>')\n\t\t\t\t{\n\t\t\t\t\t// ignore section end\n\t\t\t\t\ts += 3;\n\n\t\t\t\t\tif (depth == 0)\n\t\t\t\t\t\treturn s;\n\n\t\t\t\t\tdepth--;\n\t\t\t\t}\n\t\t\t\telse s++;\n\t\t\t}\n\n\t\t\tPUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\t\t}\n\n\t\tchar_t* parse_doctype_group(char_t* s, char_t endch)\n\t\t{\n\t\t\tsize_t depth = 0;\n\n\t\t\tassert((s[0] == '<' || s[0] == 0) && s[1] == '!');\n\t\t\ts += 2;\n\n\t\t\twhile (*s)\n\t\t\t{\n\t\t\t\tif (s[0] == '<' && s[1] == '!' && s[2] != '-')\n\t\t\t\t{\n\t\t\t\t\tif (s[2] == '[')\n\t\t\t\t\t{\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t\ts = parse_doctype_ignore(s);\n\t\t\t\t\t\tif (!s) return s;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// some control group\n\t\t\t\t\t\ts += 2;\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (s[0] == '<' || s[0] == '\"' || s[0] == '\\'')\n\t\t\t\t{\n\t\t\t\t\t// unknown tag (forbidden), or some primitive group\n\t\t\t\t\ts = parse_doctype_primitive(s);\n\t\t\t\t\tif (!s) return s;\n\t\t\t\t}\n\t\t\t\telse if (*s == '>')\n\t\t\t\t{\n\t\t\t\t\tif (depth == 0)\n\t\t\t\t\t\treturn s;\n\n\t\t\t\t\tdepth--;\n\t\t\t\t\ts++;\n\t\t\t\t}\n\t\t\t\telse s++;\n\t\t\t}\n\n\t\t\tif (depth != 0 || endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\treturn s;\n\t\t}\n\n\t\tchar_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)\n\t\t{\n\t\t\t// parse node contents, starting with exclamation mark\n\t\t\t++s;\n\n\t\t\tif (*s == '-') // '<!-...'\n\t\t\t{\n\t\t\t\t++s;\n\n\t\t\t\tif (*s == '-') // '<!--...'\n\t\t\t\t{\n\t\t\t\t\t++s;\n\n\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_comments))\n\t\t\t\t\t{\n\t\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_comment); // Append a new node on the tree.\n\t\t\t\t\t\tcursor->value = s; // Save the offset.\n\t\t\t\t\t}\n\n\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments))\n\t\t\t\t\t{\n\t\t\t\t\t\ts = strconv_comment(s, endch);\n\n\t\t\t\t\t\tif (!s) PUGI_IMPL_THROW_ERROR(status_bad_comment, cursor->value);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Scan for terminating '-->'.\n\t\t\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>'));\n\t\t\t\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_comment, s);\n\n\t\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_comments))\n\t\t\t\t\t\t\t*s = 0; // Zero-terminate this segment at the first terminating '-'.\n\n\t\t\t\t\t\ts += (s[2] == '>' ? 3 : 2); // Step over the '\\0->'.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_comment, s);\n\t\t\t}\n\t\t\telse if (*s == '[')\n\t\t\t{\n\t\t\t\t// '<![CDATA[...'\n\t\t\t\tif (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')\n\t\t\t\t{\n\t\t\t\t\t++s;\n\n\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_cdata))\n\t\t\t\t\t{\n\t\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_cdata); // Append a new node on the tree.\n\t\t\t\t\t\tcursor->value = s; // Save the offset.\n\n\t\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_eol))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ts = strconv_cdata(s, endch);\n\n\t\t\t\t\t\t\tif (!s) PUGI_IMPL_THROW_ERROR(status_bad_cdata, cursor->value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Scan for terminating ']]>'.\n\t\t\t\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));\n\t\t\t\t\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);\n\n\t\t\t\t\t\t\t*s++ = 0; // Zero-terminate this segment.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse // Flagged for discard, but we still have to scan for the terminator.\n\t\t\t\t\t{\n\t\t\t\t\t\t// Scan for terminating ']]>'.\n\t\t\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));\n\t\t\t\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);\n\n\t\t\t\t\t\t++s;\n\t\t\t\t\t}\n\n\t\t\t\t\ts += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.\n\t\t\t\t}\n\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);\n\t\t\t}\n\t\t\telse if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI_IMPL_ENDSWITH(s[6], 'E'))\n\t\t\t{\n\t\t\t\ts -= 2;\n\n\t\t\t\tif (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);\n\n\t\t\t\tchar_t* mark = s + 9;\n\n\t\t\t\ts = parse_doctype_group(s, endch);\n\t\t\t\tif (!s) return s;\n\n\t\t\t\tassert((*s == 0 && endch == '>') || *s == '>');\n\t\t\t\tif (*s) *s++ = 0;\n\n\t\t\t\tif (PUGI_IMPL_OPTSET(parse_doctype))\n\t\t\t\t{\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*mark, ct_space)) ++mark;\n\n\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_doctype);\n\n\t\t\t\t\tcursor->value = mark;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (*s == 0 && endch == '-') PUGI_IMPL_THROW_ERROR(status_bad_comment, s);\n\t\t\telse if (*s == 0 && endch == '[') PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);\n\t\t\telse PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);\n\n\t\t\treturn s;\n\t\t}\n\n\t\tchar_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)\n\t\t{\n\t\t\t// load into registers\n\t\t\txml_node_struct* cursor = ref_cursor;\n\t\t\tchar_t ch = 0;\n\n\t\t\t// parse node contents, starting with question mark\n\t\t\t++s;\n\n\t\t\t// read PI target\n\t\t\tchar_t* target = s;\n\n\t\t\tif (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);\n\n\t\t\tPUGI_IMPL_SCANWHILE(PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol));\n\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_pi, s);\n\n\t\t\t// determine node type; stricmp / strcasecmp is not portable\n\t\t\tbool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;\n\n\t\t\tif (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi))\n\t\t\t{\n\t\t\t\tif (declaration)\n\t\t\t\t{\n\t\t\t\t\t// disallow non top-level declarations\n\t\t\t\t\tif (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);\n\n\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_declaration);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_pi);\n\t\t\t\t}\n\n\t\t\t\tcursor->name = target;\n\n\t\t\t\tPUGI_IMPL_ENDSEG();\n\n\t\t\t\t// parse value/attributes\n\t\t\t\tif (ch == '?')\n\t\t\t\t{\n\t\t\t\t\t// empty node\n\t\t\t\t\tif (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);\n\t\t\t\t\ts += (*s == '>');\n\n\t\t\t\t\tPUGI_IMPL_POPNODE();\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))\n\t\t\t\t{\n\t\t\t\t\tPUGI_IMPL_SKIPWS();\n\n\t\t\t\t\t// scan for tag end\n\t\t\t\t\tchar_t* value = s;\n\n\t\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));\n\t\t\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_pi, s);\n\n\t\t\t\t\tif (declaration)\n\t\t\t\t\t{\n\t\t\t\t\t\t// replace ending ? with / so that 'element' terminates properly\n\t\t\t\t\t\t*s = '/';\n\n\t\t\t\t\t\t// we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES\n\t\t\t\t\t\ts = value;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// store value and step over >\n\t\t\t\t\t\tcursor->value = value;\n\n\t\t\t\t\t\tPUGI_IMPL_POPNODE();\n\n\t\t\t\t\t\tPUGI_IMPL_ENDSEG();\n\n\t\t\t\t\t\ts += (*s == '>');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_pi, s);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// scan for tag end\n\t\t\t\tPUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));\n\t\t\t\tPUGI_IMPL_CHECK_ERROR(status_bad_pi, s);\n\n\t\t\t\ts += (s[1] == '>' ? 2 : 1);\n\t\t\t}\n\n\t\t\t// store from registers\n\t\t\tref_cursor = cursor;\n\n\t\t\treturn s;\n\t\t}\n\n\t\tchar_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch)\n\t\t{\n\t\t\tstrconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);\n\t\t\tstrconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);\n\n\t\t\tchar_t ch = 0;\n\t\t\txml_node_struct* cursor = root;\n\t\t\tchar_t* mark = s;\n\t\t\tchar_t* merged_pcdata = s;\n\n\t\t\twhile (*s != 0)\n\t\t\t{\n\t\t\t\tif (*s == '<')\n\t\t\t\t{\n\t\t\t\t\t++s;\n\n\t\t\t\tLOC_TAG:\n\t\t\t\t\tif (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'\n\t\t\t\t\t{\n\t\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_element); // Append a new node to the tree.\n\n\t\t\t\t\t\tcursor->name = s;\n\n\t\t\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.\n\t\t\t\t\t\tPUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.\n\n\t\t\t\t\t\tif (ch == '>')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// end of tag\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))\n\t\t\t\t\t\t{\n\t\t\t\t\t\tLOC_ATTRIBUTES:\n\t\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tPUGI_IMPL_SKIPWS(); // Eat any whitespace.\n\n\t\t\t\t\t\t\t\tif (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // <... #...\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\txml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.\n\t\t\t\t\t\t\t\t\tif (!a) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s);\n\n\t\t\t\t\t\t\t\t\ta->name = s; // Save the offset.\n\n\t\t\t\t\t\t\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.\n\t\t\t\t\t\t\t\t\tPUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.\n\n\t\t\t\t\t\t\t\t\tif (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPUGI_IMPL_SKIPWS(); // Eat any whitespace.\n\n\t\t\t\t\t\t\t\t\t\tch = *s;\n\t\t\t\t\t\t\t\t\t\t++s;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (ch == '=') // '<... #=...'\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPUGI_IMPL_SKIPWS(); // Eat any whitespace.\n\n\t\t\t\t\t\t\t\t\t\tif (*s == '\"' || *s == '\\'') // '<... #=\"...'\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tch = *s; // Save quote char to avoid breaking on \"''\" -or- '\"\"'.\n\t\t\t\t\t\t\t\t\t\t\t++s; // Step over the quote.\n\t\t\t\t\t\t\t\t\t\t\ta->value = s; // Save the offset.\n\n\t\t\t\t\t\t\t\t\t\t\ts = strconv_attribute(s, ch);\n\n\t\t\t\t\t\t\t\t\t\t\tif (!s) PUGI_IMPL_THROW_ERROR(status_bad_attribute, a->value);\n\n\t\t\t\t\t\t\t\t\t\t\t// After this line the loop continues from the start;\n\t\t\t\t\t\t\t\t\t\t\t// Whitespaces, / and > are ok, symbols and EOF are wrong,\n\t\t\t\t\t\t\t\t\t\t\t// everything else will be detected\n\t\t\t\t\t\t\t\t\t\t\tif (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (*s == '/')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t++s;\n\n\t\t\t\t\t\t\t\t\tif (*s == '>')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPUGI_IMPL_POPNODE();\n\t\t\t\t\t\t\t\t\t\ts++;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (*s == 0 && endch == '>')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tPUGI_IMPL_POPNODE();\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (*s == '>')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t++s;\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (*s == 0 && endch == '>')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// !!!\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (ch == '/') // '<#.../'\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);\n\n\t\t\t\t\t\t\tPUGI_IMPL_POPNODE(); // Pop.\n\n\t\t\t\t\t\t\ts += (*s == '>');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (ch == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we stepped over null terminator, backtrack & handle closing tag\n\t\t\t\t\t\t\t--s;\n\n\t\t\t\t\t\t\tif (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);\n\t\t\t\t\t}\n\t\t\t\t\telse if (*s == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\t++s;\n\n\t\t\t\t\t\tmark = s;\n\n\t\t\t\t\t\tchar_t* name = cursor->name;\n\t\t\t\t\t\tif (!name) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);\n\n\t\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (*s++ != *name++) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (*name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (*s == 0 && name[0] == endch && name[1] == 0) PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);\n\t\t\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tPUGI_IMPL_POPNODE(); // Pop.\n\n\t\t\t\t\t\tPUGI_IMPL_SKIPWS();\n\n\t\t\t\t\t\tif (*s == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (*s != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);\n\t\t\t\t\t\t\t++s;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (*s == '?') // '<?...'\n\t\t\t\t\t{\n\t\t\t\t\t\ts = parse_question(s, cursor, optmsk, endch);\n\t\t\t\t\t\tif (!s) return s;\n\n\t\t\t\t\t\tassert(cursor);\n\t\t\t\t\t\tif (PUGI_IMPL_NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;\n\t\t\t\t\t}\n\t\t\t\t\telse if (*s == '!') // '<!...'\n\t\t\t\t\t{\n\t\t\t\t\t\ts = parse_exclamation(s, cursor, optmsk, endch);\n\t\t\t\t\t\tif (!s) return s;\n\t\t\t\t\t}\n\t\t\t\t\telse if (*s == 0 && endch == '?') PUGI_IMPL_THROW_ERROR(status_bad_pi, s);\n\t\t\t\t\telse PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmark = s; // Save this offset while searching for a terminator.\n\n\t\t\t\t\tPUGI_IMPL_SKIPWS(); // Eat whitespace if no genuine PCDATA here.\n\n\t\t\t\t\tif (*s == '<' || !*s)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one\n\t\t\t\t\t\tassert(mark != s);\n\n\t\t\t\t\t\tif (!PUGI_IMPL_OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI_IMPL_OPTSET(parse_trim_pcdata))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (PUGI_IMPL_OPTSET(parse_ws_pcdata_single))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!PUGI_IMPL_OPTSET(parse_trim_pcdata))\n\t\t\t\t\t\ts = mark;\n\n\t\t\t\t\tif (cursor->parent || PUGI_IMPL_OPTSET(parse_fragment))\n\t\t\t\t\t{\n\t\t\t\t\t\tchar_t* parsed_pcdata = s;\n\n\t\t\t\t\t\ts = strconv_pcdata(s);\n\n\t\t\t\t\t\tif (PUGI_IMPL_OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcursor->value = parsed_pcdata; // Save the offset.\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tassert(merged_pcdata >= cursor->first_child->prev_sibling_c->value);\n\n\t\t\t\t\t\t\t// Catch up to the end of last parsed value; only needed for the first fragment.\n\t\t\t\t\t\t\tmerged_pcdata += strlength(merged_pcdata);\n\n\t\t\t\t\t\t\tsize_t length = strlength(parsed_pcdata);\n\n\t\t\t\t\t\t\t// Must use memmove instead of memcpy as this move may overlap\n\t\t\t\t\t\t\tmemmove(merged_pcdata, parsed_pcdata, (length + 1) * sizeof(char_t));\n\t\t\t\t\t\t\tmerged_pcdata += length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\txml_node_struct* prev_cursor = cursor;\n\t\t\t\t\t\t\tPUGI_IMPL_PUSHNODE(node_pcdata); // Append a new node on the tree.\n\n\t\t\t\t\t\t\tcursor->value = parsed_pcdata; // Save the offset.\n\t\t\t\t\t\t\tmerged_pcdata = parsed_pcdata; // Used for parse_merge_pcdata above, cheaper to save unconditionally\n\n\t\t\t\t\t\t\tcursor = prev_cursor; // Pop since this is a standalone.\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!*s) break;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tPUGI_IMPL_SCANFOR(*s == '<'); // '...<'\n\t\t\t\t\t\tif (!*s) break;\n\n\t\t\t\t\t\t++s;\n\t\t\t\t\t}\n\n\t\t\t\t\t// We're after '<'\n\t\t\t\t\tgoto LOC_TAG;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check that last tag is closed\n\t\t\tif (cursor != root) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, s);\n\n\t\t\treturn s;\n\t\t}\n\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\tstatic char_t* parse_skip_bom(char_t* s)\n\t\t{\n\t\t\tunsigned int bom = 0xfeff;\n\t\t\treturn (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;\n\t\t}\n\t#else\n\t\tstatic char_t* parse_skip_bom(char_t* s)\n\t\t{\n\t\t\treturn (s[0] == '\\xef' && s[1] == '\\xbb' && s[2] == '\\xbf') ? s + 3 : s;\n\t\t}\n\t#endif\n\n\t\tstatic bool has_element_node_siblings(xml_node_struct* node)\n\t\t{\n\t\t\twhile (node)\n\t\t\t{\n\t\t\t\tif (PUGI_IMPL_NODETYPE(node) == node_element) return true;\n\n\t\t\t\tnode = node->next_sibling;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tstatic xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)\n\t\t{\n\t\t\t// early-out for empty documents\n\t\t\tif (length == 0)\n\t\t\t\treturn make_parse_result(PUGI_IMPL_OPTSET(parse_fragment) ? status_ok : status_no_document_element);\n\n\t\t\t// get last child of the root before parsing\n\t\t\txml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : NULL;\n\n\t\t\t// create parser on stack\n\t\t\txml_parser parser(static_cast<xml_allocator*>(xmldoc));\n\n\t\t\t// save last character and make buffer zero-terminated (speeds up parsing)\n\t\t\tchar_t endch = buffer[length - 1];\n\t\t\tbuffer[length - 1] = 0;\n\n\t\t\t// skip BOM to make sure it does not end up as part of parse output\n\t\t\tchar_t* buffer_data = parse_skip_bom(buffer);\n\n\t\t\t// perform actual parsing\n\t\t\tparser.parse_tree(buffer_data, root, optmsk, endch);\n\n\t\t\txml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);\n\t\t\tassert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);\n\n\t\t\tif (result)\n\t\t\t{\n\t\t\t\t// since we removed last character, we have to handle the only possible false positive (stray <)\n\t\t\t\tif (endch == '<')\n\t\t\t\t\treturn make_parse_result(status_unrecognized_tag, length - 1);\n\n\t\t\t\t// check if there are any element nodes parsed\n\t\t\t\txml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child + 0;\n\n\t\t\t\tif (!PUGI_IMPL_OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))\n\t\t\t\t\treturn make_parse_result(status_no_document_element, length - 1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// roll back offset if it occurs on a null terminator in the source buffer\n\t\t\t\tif (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)\n\t\t\t\t\tresult.offset--;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n\n\t// Output facilities\n\tPUGI_IMPL_FN xml_encoding get_write_native_encoding()\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn get_wchar_encoding();\n\t#else\n\t\treturn encoding_utf8;\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN xml_encoding get_write_encoding(xml_encoding encoding)\n\t{\n\t\t// replace wchar encoding with utf implementation\n\t\tif (encoding == encoding_wchar) return get_wchar_encoding();\n\n\t\t// replace utf16 encoding with utf16 with specific endianness\n\t\tif (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t// replace utf32 encoding with utf32 with specific endianness\n\t\tif (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t// only do autodetection if no explicit encoding is requested\n\t\tif (encoding != encoding_auto) return encoding;\n\n\t\t// assume utf8 encoding\n\t\treturn encoding_utf8;\n\t}\n\n\ttemplate <typename D, typename T> PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T)\n\t{\n\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));\n\n\t\ttypename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());\n\n\t\treturn static_cast<size_t>(end - dest) * sizeof(*dest);\n\t}\n\n\ttemplate <typename D, typename T> PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap)\n\t{\n\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));\n\n\t\ttypename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());\n\n\t\tif (opt_swap)\n\t\t{\n\t\t\tfor (typename T::value_type i = dest; i != end; ++i)\n\t\t\t\t*i = endian_swap(*i);\n\t\t}\n\n\t\treturn static_cast<size_t>(end - dest) * sizeof(*dest);\n\t}\n\n#ifdef PUGIXML_WCHAR_MODE\n\tPUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)\n\t{\n\t\tif (length < 1) return 0;\n\n\t\t// discard last character if it's the lead of a surrogate pair\n\t\treturn (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;\n\t}\n\n\tPUGI_IMPL_FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)\n\t{\n\t\t// only endian-swapping is required\n\t\tif (need_endian_swap_utf(encoding, get_wchar_encoding()))\n\t\t{\n\t\t\tconvert_wchar_endian_swap(r_char, data, length);\n\n\t\t\treturn length * sizeof(char_t);\n\t\t}\n\n\t\t// convert to utf8\n\t\tif (encoding == encoding_utf8)\n\t\t\treturn convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());\n\n\t\t// convert to utf16\n\t\tif (encoding == encoding_utf16_be || encoding == encoding_utf16_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t\treturn convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);\n\t\t}\n\n\t\t// convert to utf32\n\t\tif (encoding == encoding_utf32_be || encoding == encoding_utf32_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t\treturn convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);\n\t\t}\n\n\t\t// convert to latin1\n\t\tif (encoding == encoding_latin1)\n\t\t\treturn convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());\n\n\t\tassert(false && \"Invalid encoding\"); // unreachable\n\t\treturn 0;\n\t}\n#else\n\tPUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)\n\t{\n\t\tif (length < 5) return 0;\n\n\t\tfor (size_t i = 1; i <= 4; ++i)\n\t\t{\n\t\t\tuint8_t ch = static_cast<uint8_t>(data[length - i]);\n\n\t\t\t// either a standalone character or a leading one\n\t\t\tif ((ch & 0xc0) != 0x80) return length - i;\n\t\t}\n\n\t\t// there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk\n\t\treturn length;\n\t}\n\n\tPUGI_IMPL_FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)\n\t{\n\t\tif (encoding == encoding_utf16_be || encoding == encoding_utf16_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;\n\n\t\t\treturn convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);\n\t\t}\n\n\t\tif (encoding == encoding_utf32_be || encoding == encoding_utf32_le)\n\t\t{\n\t\t\txml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;\n\n\t\t\treturn convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);\n\t\t}\n\n\t\tif (encoding == encoding_latin1)\n\t\t\treturn convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());\n\n\t\tassert(false && \"Invalid encoding\"); // unreachable\n\t\treturn 0;\n\t}\n#endif\n\n\tclass xml_buffered_writer\n\t{\n\t\txml_buffered_writer(const xml_buffered_writer&);\n\t\txml_buffered_writer& operator=(const xml_buffered_writer&);\n\n\tpublic:\n\t\txml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))\n\t\t{\n\t\t\tPUGI_IMPL_STATIC_ASSERT(bufcapacity >= 8);\n\t\t}\n\n\t\tsize_t flush()\n\t\t{\n\t\t\tflush(buffer, bufsize);\n\t\t\tbufsize = 0;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvoid flush(const char_t* data, size_t size)\n\t\t{\n\t\t\tif (size == 0) return;\n\n\t\t\t// fast path, just write data\n\t\t\tif (encoding == get_write_native_encoding())\n\t\t\t\twriter.write(data, size * sizeof(char_t));\n\t\t\telse\n\t\t\t{\n\t\t\t\t// convert chunk\n\t\t\t\tsize_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);\n\t\t\t\tassert(result <= sizeof(scratch));\n\n\t\t\t\t// write data\n\t\t\t\twriter.write(scratch.data_u8, result);\n\t\t\t}\n\t\t}\n\n\t\tvoid write_direct(const char_t* data, size_t length)\n\t\t{\n\t\t\t// flush the remaining buffer contents\n\t\t\tflush();\n\n\t\t\t// handle large chunks\n\t\t\tif (length > bufcapacity)\n\t\t\t{\n\t\t\t\tif (encoding == get_write_native_encoding())\n\t\t\t\t{\n\t\t\t\t\t// fast path, can just write data chunk\n\t\t\t\t\twriter.write(data, length * sizeof(char_t));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// need to convert in suitable chunks\n\t\t\t\twhile (length > bufcapacity)\n\t\t\t\t{\n\t\t\t\t\t// get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer\n\t\t\t\t\t// and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)\n\t\t\t\t\tsize_t chunk_size = get_valid_length(data, bufcapacity);\n\t\t\t\t\tassert(chunk_size);\n\n\t\t\t\t\t// convert chunk and write\n\t\t\t\t\tflush(data, chunk_size);\n\n\t\t\t\t\t// iterate\n\t\t\t\t\tdata += chunk_size;\n\t\t\t\t\tlength -= chunk_size;\n\t\t\t\t}\n\n\t\t\t\t// small tail is copied below\n\t\t\t\tbufsize = 0;\n\t\t\t}\n\n\t\t\tmemcpy(buffer + bufsize, data, length * sizeof(char_t));\n\t\t\tbufsize += length;\n\t\t}\n\n\t\tvoid write_buffer(const char_t* data, size_t length)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\n\t\t\tif (offset + length <= bufcapacity)\n\t\t\t{\n\t\t\t\tmemcpy(buffer + offset, data, length * sizeof(char_t));\n\t\t\t\tbufsize = offset + length;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twrite_direct(data, length);\n\t\t\t}\n\t\t}\n\n\t\tvoid write_string(const char_t* data)\n\t\t{\n\t\t\t// write the part of the string that fits in the buffer\n\t\t\tsize_t offset = bufsize;\n\n\t\t\twhile (*data && offset < bufcapacity)\n\t\t\t\tbuffer[offset++] = *data++;\n\n\t\t\t// write the rest\n\t\t\tif (offset < bufcapacity)\n\t\t\t{\n\t\t\t\tbufsize = offset;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// backtrack a bit if we have split the codepoint\n\t\t\t\tsize_t length = offset - bufsize;\n\t\t\t\tsize_t extra = length - get_valid_length(data - length, length);\n\n\t\t\t\tbufsize = offset - extra;\n\n\t\t\t\twrite_direct(data - extra, strlength(data) + extra);\n\t\t\t}\n\t\t}\n\n\t\tvoid write(char_t d0)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 1) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbufsize = offset + 1;\n\t\t}\n\n\t\tvoid write(char_t d0, char_t d1)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 2) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbuffer[offset + 1] = d1;\n\t\t\tbufsize = offset + 2;\n\t\t}\n\n\t\tvoid write(char_t d0, char_t d1, char_t d2)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 3) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbuffer[offset + 1] = d1;\n\t\t\tbuffer[offset + 2] = d2;\n\t\t\tbufsize = offset + 3;\n\t\t}\n\n\t\tvoid write(char_t d0, char_t d1, char_t d2, char_t d3)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 4) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbuffer[offset + 1] = d1;\n\t\t\tbuffer[offset + 2] = d2;\n\t\t\tbuffer[offset + 3] = d3;\n\t\t\tbufsize = offset + 4;\n\t\t}\n\n\t\tvoid write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 5) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbuffer[offset + 1] = d1;\n\t\t\tbuffer[offset + 2] = d2;\n\t\t\tbuffer[offset + 3] = d3;\n\t\t\tbuffer[offset + 4] = d4;\n\t\t\tbufsize = offset + 5;\n\t\t}\n\n\t\tvoid write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)\n\t\t{\n\t\t\tsize_t offset = bufsize;\n\t\t\tif (offset > bufcapacity - 6) offset = flush();\n\n\t\t\tbuffer[offset + 0] = d0;\n\t\t\tbuffer[offset + 1] = d1;\n\t\t\tbuffer[offset + 2] = d2;\n\t\t\tbuffer[offset + 3] = d3;\n\t\t\tbuffer[offset + 4] = d4;\n\t\t\tbuffer[offset + 5] = d5;\n\t\t\tbufsize = offset + 6;\n\t\t}\n\n\t\t// utf8 maximum expansion: x4 (-> utf32)\n\t\t// utf16 maximum expansion: x2 (-> utf32)\n\t\t// utf32 maximum expansion: x1\n\t\tenum\n\t\t{\n\t\t\tbufcapacitybytes =\n\t\t\t#ifdef PUGIXML_MEMORY_OUTPUT_STACK\n\t\t\t\tPUGIXML_MEMORY_OUTPUT_STACK\n\t\t\t#else\n\t\t\t\t10240\n\t\t\t#endif\n\t\t\t,\n\t\t\tbufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)\n\t\t};\n\n\t\tchar_t buffer[bufcapacity];\n\n\t\tunion\n\t\t{\n\t\t\tuint8_t data_u8[4 * bufcapacity];\n\t\t\tuint16_t data_u16[2 * bufcapacity];\n\t\t\tuint32_t data_u32[bufcapacity];\n\t\t\tchar_t data_char[bufcapacity];\n\t\t} scratch;\n\n\t\txml_writer& writer;\n\t\tsize_t bufsize;\n\t\txml_encoding encoding;\n\t};\n\n\tPUGI_IMPL_FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)\n\t{\n\t\twhile (*s)\n\t\t{\n\t\t\tconst char_t* prev = s;\n\n\t\t\t// While *s is a usual symbol\n\t\t\tPUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPEX(ss, type));\n\n\t\t\twriter.write_buffer(prev, static_cast<size_t>(s - prev));\n\n\t\t\tswitch (*s)\n\t\t\t{\n\t\t\t\tcase 0: break;\n\t\t\t\tcase '&':\n\t\t\t\t\twriter.write('&', 'a', 'm', 'p', ';');\n\t\t\t\t\t++s;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '<':\n\t\t\t\t\twriter.write('&', 'l', 't', ';');\n\t\t\t\t\t++s;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '>':\n\t\t\t\t\twriter.write('&', 'g', 't', ';');\n\t\t\t\t\t++s;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\"':\n\t\t\t\t\tif (flags & format_attribute_single_quote)\n\t\t\t\t\t\twriter.write('\"');\n\t\t\t\t\telse\n\t\t\t\t\t\twriter.write('&', 'q', 'u', 'o', 't', ';');\n\t\t\t\t\t++s;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '\\'':\n\t\t\t\t\tif (flags & format_attribute_single_quote)\n\t\t\t\t\t\twriter.write('&', 'a', 'p', 'o', 's', ';');\n\t\t\t\t\telse\n\t\t\t\t\t\twriter.write('\\'');\n\t\t\t\t\t++s;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: // s is not a usual symbol\n\t\t\t\t{\n\t\t\t\t\tunsigned int ch = static_cast<unsigned int>(*s++);\n\t\t\t\t\tassert(ch < 32);\n\n\t\t\t\t\tif (!(flags & format_skip_control_chars))\n\t\t\t\t\t\twriter.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)\n\t{\n\t\tif (flags & format_no_escapes)\n\t\t\twriter.write_string(s);\n\t\telse\n\t\t\ttext_output_escaped(writer, s, type, flags);\n\t}\n\n\tPUGI_IMPL_FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)\n\t{\n\t\tdo\n\t\t{\n\t\t\twriter.write('<', '!', '[', 'C', 'D');\n\t\t\twriter.write('A', 'T', 'A', '[');\n\n\t\t\tconst char_t* prev = s;\n\n\t\t\t// look for ]]> sequence - we can't output it as is since it terminates CDATA\n\t\t\twhile (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;\n\n\t\t\t// skip ]] if we stopped at ]]>, > will go to the next CDATA section\n\t\t\tif (*s) s += 2;\n\n\t\t\twriter.write_buffer(prev, static_cast<size_t>(s - prev));\n\n\t\t\twriter.write(']', ']', '>');\n\t\t}\n\t\twhile (*s);\n\t}\n\n\tPUGI_IMPL_FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)\n\t{\n\t\tswitch (indent_length)\n\t\t{\n\t\tcase 1:\n\t\t{\n\t\t\tfor (unsigned int i = 0; i < depth; ++i)\n\t\t\t\twriter.write(indent[0]);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 2:\n\t\t{\n\t\t\tfor (unsigned int i = 0; i < depth; ++i)\n\t\t\t\twriter.write(indent[0], indent[1]);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 3:\n\t\t{\n\t\t\tfor (unsigned int i = 0; i < depth; ++i)\n\t\t\t\twriter.write(indent[0], indent[1], indent[2]);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 4:\n\t\t{\n\t\t\tfor (unsigned int i = 0; i < depth; ++i)\n\t\t\t\twriter.write(indent[0], indent[1], indent[2], indent[3]);\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault:\n\t\t{\n\t\t\tfor (unsigned int i = 0; i < depth; ++i)\n\t\t\t\twriter.write_buffer(indent, indent_length);\n\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)\n\t{\n\t\twriter.write('<', '!', '-', '-');\n\n\t\twhile (*s)\n\t\t{\n\t\t\tconst char_t* prev = s;\n\n\t\t\t// look for -\\0 or -- sequence - we can't output it since -- is illegal in comment body\n\t\t\twhile (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s;\n\n\t\t\twriter.write_buffer(prev, static_cast<size_t>(s - prev));\n\n\t\t\tif (*s)\n\t\t\t{\n\t\t\t\tassert(*s == '-');\n\n\t\t\t\twriter.write('-', ' ');\n\t\t\t\t++s;\n\t\t\t}\n\t\t}\n\n\t\twriter.write('-', '-', '>');\n\t}\n\n\tPUGI_IMPL_FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)\n\t{\n\t\twhile (*s)\n\t\t{\n\t\t\tconst char_t* prev = s;\n\n\t\t\t// look for ?> sequence - we can't output it since ?> terminates PI\n\t\t\twhile (*s && !(s[0] == '?' && s[1] == '>')) ++s;\n\n\t\t\twriter.write_buffer(prev, static_cast<size_t>(s - prev));\n\n\t\t\tif (*s)\n\t\t\t{\n\t\t\t\tassert(s[0] == '?' && s[1] == '>');\n\n\t\t\t\twriter.write('?', ' ', '>');\n\t\t\t\ts += 2;\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)\n\t{\n\t\tconst char_t* default_name = PUGIXML_TEXT(\":anonymous\");\n\t\tconst char_t enquotation_char = (flags & format_attribute_single_quote) ? '\\'' : '\"';\n\n\t\tfor (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)\n\t\t{\n\t\t\tif ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes)\n\t\t\t{\n\t\t\t\twriter.write('\\n');\n\n\t\t\t\ttext_output_indent(writer, indent, indent_length, depth + 1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twriter.write(' ');\n\t\t\t}\n\n\t\t\twriter.write_string(a->name ? a->name + 0 : default_name);\n\t\t\twriter.write('=', enquotation_char);\n\n\t\t\tif (a->value)\n\t\t\t\ttext_output(writer, a->value, ctx_special_attr, flags);\n\n\t\t\twriter.write(enquotation_char);\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)\n\t{\n\t\tconst char_t* default_name = PUGIXML_TEXT(\":anonymous\");\n\t\tconst char_t* name = node->name ? node->name + 0 : default_name;\n\n\t\twriter.write('<');\n\t\twriter.write_string(name);\n\n\t\tif (node->first_attribute)\n\t\t\tnode_output_attributes(writer, node, indent, indent_length, flags, depth);\n\n\t\t// element nodes can have value if parse_embed_pcdata was used\n\t\tif (!node->value)\n\t\t{\n\t\t\tif (!node->first_child)\n\t\t\t{\n\t\t\t\tif (flags & format_no_empty_element_tags)\n\t\t\t\t{\n\t\t\t\t\twriter.write('>', '<', '/');\n\t\t\t\t\twriter.write_string(name);\n\t\t\t\t\twriter.write('>');\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif ((flags & format_raw) == 0)\n\t\t\t\t\t\twriter.write(' ');\n\n\t\t\t\t\twriter.write('/', '>');\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twriter.write('>');\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\twriter.write('>');\n\n\t\t\ttext_output(writer, node->value, ctx_special_pcdata, flags);\n\n\t\t\tif (!node->first_child)\n\t\t\t{\n\t\t\t\twriter.write('<', '/');\n\t\t\t\twriter.write_string(name);\n\t\t\t\twriter.write('>');\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)\n\t{\n\t\tconst char_t* default_name = PUGIXML_TEXT(\":anonymous\");\n\t\tconst char_t* name = node->name ? node->name + 0 : default_name;\n\n\t\twriter.write('<', '/');\n\t\twriter.write_string(name);\n\t\twriter.write('>');\n\t}\n\n\tPUGI_IMPL_FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)\n\t{\n\t\tconst char_t* default_name = PUGIXML_TEXT(\":anonymous\");\n\n\t\tswitch (PUGI_IMPL_NODETYPE(node))\n\t\t{\n\t\t\tcase node_pcdata:\n\t\t\t\ttext_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(\"\"), ctx_special_pcdata, flags);\n\t\t\t\tbreak;\n\n\t\t\tcase node_cdata:\n\t\t\t\ttext_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(\"\"));\n\t\t\t\tbreak;\n\n\t\t\tcase node_comment:\n\t\t\t\tnode_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(\"\"));\n\t\t\t\tbreak;\n\n\t\t\tcase node_pi:\n\t\t\t\twriter.write('<', '?');\n\t\t\t\twriter.write_string(node->name ? node->name + 0 : default_name);\n\n\t\t\t\tif (node->value)\n\t\t\t\t{\n\t\t\t\t\twriter.write(' ');\n\t\t\t\t\tnode_output_pi_value(writer, node->value);\n\t\t\t\t}\n\n\t\t\t\twriter.write('?', '>');\n\t\t\t\tbreak;\n\n\t\t\tcase node_declaration:\n\t\t\t\twriter.write('<', '?');\n\t\t\t\twriter.write_string(node->name ? node->name + 0 : default_name);\n\t\t\t\tnode_output_attributes(writer, node, PUGIXML_TEXT(\"\"), 0, flags | format_raw, 0);\n\t\t\t\twriter.write('?', '>');\n\t\t\t\tbreak;\n\n\t\t\tcase node_doctype:\n\t\t\t\twriter.write('<', '!', 'D', 'O', 'C');\n\t\t\t\twriter.write('T', 'Y', 'P', 'E');\n\n\t\t\t\tif (node->value)\n\t\t\t\t{\n\t\t\t\t\twriter.write(' ');\n\t\t\t\t\twriter.write_string(node->value);\n\t\t\t\t}\n\n\t\t\t\twriter.write('>');\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Invalid node type\"); // unreachable\n\t\t}\n\t}\n\n\tenum indent_flags_t\n\t{\n\t\tindent_newline = 1,\n\t\tindent_indent = 2\n\t};\n\n\tPUGI_IMPL_FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)\n\t{\n\t\tsize_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;\n\t\tunsigned int indent_flags = indent_indent;\n\n\t\txml_node_struct* node = root;\n\n\t\tdo\n\t\t{\n\t\t\tassert(node);\n\n\t\t\t// begin writing current node\n\t\t\tif (PUGI_IMPL_NODETYPE(node) == node_pcdata || PUGI_IMPL_NODETYPE(node) == node_cdata)\n\t\t\t{\n\t\t\t\tnode_output_simple(writer, node, flags);\n\n\t\t\t\tindent_flags = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((indent_flags & indent_newline) && (flags & format_raw) == 0)\n\t\t\t\t\twriter.write('\\n');\n\n\t\t\t\tif ((indent_flags & indent_indent) && indent_length)\n\t\t\t\t\ttext_output_indent(writer, indent, indent_length, depth);\n\n\t\t\t\tif (PUGI_IMPL_NODETYPE(node) == node_element)\n\t\t\t\t{\n\t\t\t\t\tindent_flags = indent_newline | indent_indent;\n\n\t\t\t\t\tif (node_output_start(writer, node, indent, indent_length, flags, depth))\n\t\t\t\t\t{\n\t\t\t\t\t\t// element nodes can have value if parse_embed_pcdata was used\n\t\t\t\t\t\tif (node->value)\n\t\t\t\t\t\t\tindent_flags = 0;\n\n\t\t\t\t\t\tnode = node->first_child;\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_NODETYPE(node) == node_document)\n\t\t\t\t{\n\t\t\t\t\tindent_flags = indent_indent;\n\n\t\t\t\t\tif (node->first_child)\n\t\t\t\t\t{\n\t\t\t\t\t\tnode = node->first_child;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnode_output_simple(writer, node, flags);\n\n\t\t\t\t\tindent_flags = indent_newline | indent_indent;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// continue to the next node\n\t\t\twhile (node != root)\n\t\t\t{\n\t\t\t\tif (node->next_sibling)\n\t\t\t\t{\n\t\t\t\t\tnode = node->next_sibling;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tnode = node->parent;\n\n\t\t\t\t// write closing node\n\t\t\t\tif (PUGI_IMPL_NODETYPE(node) == node_element)\n\t\t\t\t{\n\t\t\t\t\tdepth--;\n\n\t\t\t\t\tif ((indent_flags & indent_newline) && (flags & format_raw) == 0)\n\t\t\t\t\t\twriter.write('\\n');\n\n\t\t\t\t\tif ((indent_flags & indent_indent) && indent_length)\n\t\t\t\t\t\ttext_output_indent(writer, indent, indent_length, depth);\n\n\t\t\t\t\tnode_output_end(writer, node);\n\n\t\t\t\t\tindent_flags = indent_newline | indent_indent;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twhile (node != root);\n\n\t\tif ((indent_flags & indent_newline) && (flags & format_raw) == 0)\n\t\t\twriter.write('\\n');\n\t}\n\n\tPUGI_IMPL_FN bool has_declaration(xml_node_struct* node)\n\t{\n\t\tfor (xml_node_struct* child = node->first_child; child; child = child->next_sibling)\n\t\t{\n\t\t\txml_node_type type = PUGI_IMPL_NODETYPE(child);\n\n\t\t\tif (type == node_declaration) return true;\n\t\t\tif (type == node_element) return false;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tPUGI_IMPL_FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)\n\t{\n\t\tfor (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)\n\t\t\tif (a == attr)\n\t\t\t\treturn true;\n\n\t\treturn false;\n\t}\n\n\tPUGI_IMPL_FN bool allow_insert_attribute(xml_node_type parent)\n\t{\n\t\treturn parent == node_element || parent == node_declaration;\n\t}\n\n\tPUGI_IMPL_FN bool allow_insert_child(xml_node_type parent, xml_node_type child)\n\t{\n\t\tif (parent != node_document && parent != node_element) return false;\n\t\tif (child == node_document || child == node_null) return false;\n\t\tif (parent != node_document && (child == node_declaration || child == node_doctype)) return false;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool allow_move(xml_node parent, xml_node child)\n\t{\n\t\t// check that child can be a child of parent\n\t\tif (!allow_insert_child(parent.type(), child.type()))\n\t\t\treturn false;\n\n\t\t// check that node is not moved between documents\n\t\tif (parent.root() != child.root())\n\t\t\treturn false;\n\n\t\t// check that new parent is not in the child subtree\n\t\txml_node cur = parent;\n\n\t\twhile (cur)\n\t\t{\n\t\t\tif (cur == child)\n\t\t\t\treturn false;\n\n\t\t\tcur = cur.parent();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)\n\t{\n\t\tassert(!dest && (header & header_mask) == 0); // copies are performed into fresh nodes\n\n\t\tif (source)\n\t\t{\n\t\t\tif (alloc && (source_header & header_mask) == 0)\n\t\t\t{\n\t\t\t\tdest = source;\n\n\t\t\t\t// since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared\n\t\t\t\theader |= xml_memory_page_contents_shared_mask;\n\t\t\t\tsource_header |= xml_memory_page_contents_shared_mask;\n\t\t\t}\n\t\t\telse\n\t\t\t\tstrcpy_insitu(dest, header, header_mask, source, strlength(source));\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)\n\t{\n\t\tnode_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);\n\t\tnode_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);\n\n\t\tfor (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)\n\t\t{\n\t\t\txml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));\n\n\t\t\tif (da)\n\t\t\t{\n\t\t\t\tnode_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);\n\t\t\t\tnode_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)\n\t{\n\t\txml_allocator& alloc = get_allocator(dn);\n\t\txml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : NULL;\n\n\t\tnode_copy_contents(dn, sn, shared_alloc);\n\n\t\txml_node_struct* dit = dn;\n\t\txml_node_struct* sit = sn->first_child;\n\n\t\twhile (sit && sit != sn)\n\t\t{\n\t\t\t// loop invariant: dit is inside the subtree rooted at dn\n\t\t\tassert(dit);\n\n\t\t\t// when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop\n\t\t\tif (sit != dn)\n\t\t\t{\n\t\t\t\txml_node_struct* copy = append_new_node(dit, alloc, PUGI_IMPL_NODETYPE(sit));\n\n\t\t\t\tif (copy)\n\t\t\t\t{\n\t\t\t\t\tnode_copy_contents(copy, sit, shared_alloc);\n\n\t\t\t\t\tif (sit->first_child)\n\t\t\t\t\t{\n\t\t\t\t\t\tdit = copy;\n\t\t\t\t\t\tsit = sit->first_child;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// continue to the next node\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (sit->next_sibling)\n\t\t\t\t{\n\t\t\t\t\tsit = sit->next_sibling;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tsit = sit->parent;\n\t\t\t\tdit = dit->parent;\n\n\t\t\t\t// loop invariant: dit is inside the subtree rooted at dn while sit is inside sn\n\t\t\t\tassert(sit == sn || dit);\n\t\t\t}\n\t\t\twhile (sit != sn);\n\t\t}\n\n\t\tassert(!sit || dit == dn->parent);\n\t}\n\n\tPUGI_IMPL_FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)\n\t{\n\t\txml_allocator& alloc = get_allocator(da);\n\t\txml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : NULL;\n\n\t\tnode_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);\n\t\tnode_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);\n\t}\n\n\tinline bool is_text_node(xml_node_struct* node)\n\t{\n\t\txml_node_type type = PUGI_IMPL_NODETYPE(node);\n\n\t\treturn type == node_pcdata || type == node_cdata;\n\t}\n\n\t// get value with conversion functions\n\ttemplate <typename U> PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv)\n\t{\n\t\tU result = 0;\n\t\tconst char_t* s = value;\n\n\t\twhile (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))\n\t\t\ts++;\n\n\t\tbool negative = (*s == '-');\n\n\t\ts += (*s == '+' || *s == '-');\n\n\t\tbool overflow = false;\n\n\t\tif (s[0] == '0' && (s[1] | ' ') == 'x')\n\t\t{\n\t\t\ts += 2;\n\n\t\t\t// since overflow detection relies on length of the sequence skip leading zeros\n\t\t\twhile (*s == '0')\n\t\t\t\ts++;\n\n\t\t\tconst char_t* start = s;\n\n\t\t\tfor (;;)\n\t\t\t{\n\t\t\t\tif (static_cast<unsigned>(*s - '0') < 10)\n\t\t\t\t\tresult = result * 16 + (*s - '0');\n\t\t\t\telse if (static_cast<unsigned>((*s | ' ') - 'a') < 6)\n\t\t\t\t\tresult = result * 16 + ((*s | ' ') - 'a' + 10);\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\n\t\t\t\ts++;\n\t\t\t}\n\n\t\t\tsize_t digits = static_cast<size_t>(s - start);\n\n\t\t\toverflow = digits > sizeof(U) * 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// since overflow detection relies on length of the sequence skip leading zeros\n\t\t\twhile (*s == '0')\n\t\t\t\ts++;\n\n\t\t\tconst char_t* start = s;\n\n\t\t\tfor (;;)\n\t\t\t{\n\t\t\t\tif (static_cast<unsigned>(*s - '0') < 10)\n\t\t\t\t\tresult = result * 10 + (*s - '0');\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\n\t\t\t\ts++;\n\t\t\t}\n\n\t\t\tsize_t digits = static_cast<size_t>(s - start);\n\n\t\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);\n\n\t\t\tconst size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;\n\t\t\tconst char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';\n\t\t\tconst size_t high_bit = sizeof(U) * 8 - 1;\n\n\t\t\toverflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));\n\t\t}\n\n\t\tif (negative)\n\t\t{\n\t\t\t// Workaround for crayc++ CC-3059: Expected no overflow in routine.\n\t\t#ifdef _CRAYC\n\t\t\treturn (overflow || result > ~minv + 1) ? minv : ~result + 1;\n\t\t#else\n\t\t\treturn (overflow || result > 0 - minv) ? minv : 0 - result;\n\t\t#endif\n\t\t}\n\t\telse\n\t\t\treturn (overflow || result > maxv) ? maxv : result;\n\t}\n\n\tPUGI_IMPL_FN int get_value_int(const char_t* value)\n\t{\n\t\treturn string_to_integer<unsigned int>(value, static_cast<unsigned int>(INT_MIN), INT_MAX);\n\t}\n\n\tPUGI_IMPL_FN unsigned int get_value_uint(const char_t* value)\n\t{\n\t\treturn string_to_integer<unsigned int>(value, 0, UINT_MAX);\n\t}\n\n\tPUGI_IMPL_FN double get_value_double(const char_t* value)\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcstod(value, NULL);\n\t#else\n\t\treturn strtod(value, NULL);\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN float get_value_float(const char_t* value)\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn static_cast<float>(wcstod(value, NULL));\n\t#else\n\t\treturn static_cast<float>(strtod(value, NULL));\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN bool get_value_bool(const char_t* value)\n\t{\n\t\t// only look at first char\n\t\tchar_t first = *value;\n\n\t\t// 1*, t* (true), T* (True), y* (yes), Y* (YES)\n\t\treturn (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');\n\t}\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN long long get_value_llong(const char_t* value)\n\t{\n\t\treturn string_to_integer<unsigned long long>(value, static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);\n\t}\n\n\tPUGI_IMPL_FN unsigned long long get_value_ullong(const char_t* value)\n\t{\n\t\treturn string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);\n\t}\n#endif\n\n\ttemplate <typename U> PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)\n\t{\n\t\tchar_t* result = end - 1;\n\t\tU rest = negative ? 0 - value : value;\n\n\t\tdo\n\t\t{\n\t\t\t*result-- = static_cast<char_t>('0' + (rest % 10));\n\t\t\trest /= 10;\n\t\t}\n\t\twhile (rest);\n\n\t\tassert(result >= begin);\n\t\t(void)begin;\n\n\t\t*result = '-';\n\n\t\treturn result + !negative;\n\t}\n\n\t// set value with conversion functions\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\tchar_t wbuf[128];\n\t\tassert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));\n\n\t\tsize_t offset = 0;\n\t\tfor (; buf[offset]; ++offset) wbuf[offset] = buf[offset];\n\n\t\treturn strcpy_insitu(dest, header, header_mask, wbuf, offset);\n\t#else\n\t\treturn strcpy_insitu(dest, header, header_mask, buf, strlen(buf));\n\t#endif\n\t}\n\n\ttemplate <typename U, typename String, typename Header>\n\tPUGI_IMPL_FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)\n\t{\n\t\tchar_t buf[64];\n\t\tchar_t* end = buf + sizeof(buf) / sizeof(buf[0]);\n\t\tchar_t* begin = integer_to_string(buf, end, value, negative);\n\n\t\treturn strcpy_insitu(dest, header, header_mask, begin, end - begin);\n\t}\n\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision)\n\t{\n\t\tchar buf[128];\n\t\tPUGI_IMPL_SNPRINTF(buf, \"%.*g\", precision, double(value));\n\n\t\treturn set_value_ascii(dest, header, header_mask, buf);\n\t}\n\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision)\n\t{\n\t\tchar buf[128];\n\t\tPUGI_IMPL_SNPRINTF(buf, \"%.*g\", precision, value);\n\n\t\treturn set_value_ascii(dest, header, header_mask, buf);\n\t}\n\n\ttemplate <typename String, typename Header>\n\tPUGI_IMPL_FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)\n\t{\n\t\treturn strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT(\"true\") : PUGIXML_TEXT(\"false\"), value ? 4 : 5);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer)\n\t{\n\t\t// check input buffer\n\t\tif (!contents && size) return make_parse_result(status_io_error);\n\n\t\t// get actual encoding\n\t\txml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);\n\n\t\t// if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it\n\t\tauto_deleter<void> contents_guard(own ? contents : NULL, xml_memory::deallocate);\n\n\t\t// get private buffer\n\t\tchar_t* buffer = NULL;\n\t\tsize_t length = 0;\n\n\t\t// coverity[var_deref_model]\n\t\tif (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);\n\n\t\t// after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it\n\t\tcontents_guard.release();\n\n\t\t// delete original buffer if we performed a conversion\n\t\tif (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);\n\n\t\t// grab onto buffer if it's our buffer, user is responsible for deallocating contents himself\n\t\tif (own || buffer != contents) *out_buffer = buffer;\n\n\t\t// store buffer for offset_debug\n\t\tdoc->buffer = buffer;\n\n\t\t// parse\n\t\txml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);\n\n\t\t// remember encoding\n\t\tres.encoding = buffer_encoding;\n\n\t\treturn res;\n\t}\n\n\ttemplate <typename T> PUGI_IMPL_FN xml_parse_status convert_file_size(T length, size_t& out_result)\n\t{\n\t\t// check for I/O errors\n\t\tif (length < 0) return status_io_error;\n\n\t\t// check for overflow\n\t\tsize_t result = static_cast<size_t>(length);\n\n\t\tif (static_cast<T>(result) != length) return status_out_of_memory;\n\n\t\tout_result = result;\n\t\treturn status_ok;\n\t}\n\n\t// we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick\n\tPUGI_IMPL_FN xml_parse_status get_file_size(FILE* file, size_t& out_result)\n\t{\n\t#if defined(__linux__) || defined(__APPLE__)\n\t\t// this simultaneously retrieves the file size and file mode (to guard against loading non-files)\n\t\tstruct stat st;\n\t\tif (fstat(fileno(file), &st) != 0) return status_io_error;\n\n\t\t// anything that's not a regular file doesn't have a coherent length\n\t\tif (!S_ISREG(st.st_mode)) return status_io_error;\n\n\t\txml_parse_status status = convert_file_size(st.st_size, out_result);\n\t#elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400\n\t\t// there are 64-bit versions of fseek/ftell, let's use them\n\t\t_fseeki64(file, 0, SEEK_END);\n\t\t__int64 length = _ftelli64(file);\n\t\t_fseeki64(file, 0, SEEK_SET);\n\n\t\txml_parse_status status = convert_file_size(length, out_result);\n\t#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))\n\t\t// there are 64-bit versions of fseek/ftell, let's use them\n\t\tfseeko64(file, 0, SEEK_END);\n\t\toff64_t length = ftello64(file);\n\t\tfseeko64(file, 0, SEEK_SET);\n\n\t\txml_parse_status status = convert_file_size(length, out_result);\n\t#else\n\t\t// if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway.\n\t\tfseek(file, 0, SEEK_END);\n\t\tlong length = ftell(file);\n\t\tfseek(file, 0, SEEK_SET);\n\n\t\txml_parse_status status = convert_file_size(length, out_result);\n\t#endif\n\n\t\treturn status;\n\t}\n\n\t// This function assumes that buffer has extra sizeof(char_t) writable bytes after size\n\tPUGI_IMPL_FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)\n\t{\n\t\t// We only need to zero-terminate if encoding conversion does not do it for us\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\txml_encoding wchar_encoding = get_wchar_encoding();\n\n\t\tif (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))\n\t\t{\n\t\t\tsize_t length = size / sizeof(char_t);\n\n\t\t\tstatic_cast<char_t*>(buffer)[length] = 0;\n\t\t\treturn (length + 1) * sizeof(char_t);\n\t\t}\n\t#else\n\t\tif (encoding == encoding_utf8)\n\t\t{\n\t\t\tstatic_cast<char*>(buffer)[size] = 0;\n\t\t\treturn size + 1;\n\t\t}\n\t#endif\n\n\t\treturn size;\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)\n\t{\n\t\tif (!file) return make_parse_result(status_file_not_found);\n\n\t\t// get file size (can result in I/O errors)\n\t\tsize_t size = 0;\n\t\txml_parse_status size_status = get_file_size(file, size);\n\t\tif (size_status != status_ok) return make_parse_result(size_status);\n\n\t\tsize_t max_suffix_size = sizeof(char_t);\n\n\t\t// allocate buffer for the whole file\n\t\tchar* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));\n\t\tif (!contents) return make_parse_result(status_out_of_memory);\n\n\t\t// read file in memory\n\t\tsize_t read_size = fread(contents, 1, size, file);\n\n\t\tif (read_size != size)\n\t\t{\n\t\t\txml_memory::deallocate(contents);\n\t\t\treturn make_parse_result(status_io_error);\n\t\t}\n\n\t\txml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);\n\n\t\treturn load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);\n\t}\n\n\tPUGI_IMPL_FN void close_file(FILE* file)\n\t{\n\t\tfclose(file);\n\t}\n\n#ifndef PUGIXML_NO_STL\n\ttemplate <typename T> struct xml_stream_chunk\n\t{\n\t\tstatic xml_stream_chunk* create()\n\t\t{\n\t\t\tvoid* memory = xml_memory::allocate(sizeof(xml_stream_chunk));\n\t\t\tif (!memory) return NULL;\n\n\t\t\treturn new (memory) xml_stream_chunk();\n\t\t}\n\n\t\tstatic void destroy(xml_stream_chunk* chunk)\n\t\t{\n\t\t\t// free chunk chain\n\t\t\twhile (chunk)\n\t\t\t{\n\t\t\t\txml_stream_chunk* next_ = chunk->next;\n\n\t\t\t\txml_memory::deallocate(chunk);\n\n\t\t\t\tchunk = next_;\n\t\t\t}\n\t\t}\n\n\t\txml_stream_chunk(): next(NULL), size(0)\n\t\t{\n\t\t}\n\n\t\txml_stream_chunk* next;\n\t\tsize_t size;\n\n\t\tT data[xml_memory_page_size / sizeof(T)];\n\t};\n\n\ttemplate <typename T> PUGI_IMPL_FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)\n\t{\n\t\tauto_deleter<xml_stream_chunk<T> > chunks(NULL, xml_stream_chunk<T>::destroy);\n\n\t\t// read file to a chunk list\n\t\tsize_t total = 0;\n\t\txml_stream_chunk<T>* last = NULL;\n\n\t\twhile (!stream.eof())\n\t\t{\n\t\t\t// allocate new chunk\n\t\t\txml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();\n\t\t\tif (!chunk) return status_out_of_memory;\n\n\t\t\t// append chunk to list\n\t\t\tif (last) last = last->next = chunk;\n\t\t\telse chunks.data = last = chunk;\n\n\t\t\t// read data to chunk\n\t\t\tstream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));\n\t\t\tchunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);\n\n\t\t\t// read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors\n\t\t\tif (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;\n\n\t\t\t// guard against huge files (chunk size is small enough to make this overflow check work)\n\t\t\tif (total + chunk->size < total) return status_out_of_memory;\n\t\t\ttotal += chunk->size;\n\t\t}\n\n\t\tsize_t max_suffix_size = sizeof(char_t);\n\n\t\t// copy chunk list to a contiguous buffer\n\t\tchar* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size));\n\t\tif (!buffer) return status_out_of_memory;\n\n\t\tchar* write = buffer;\n\n\t\tfor (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)\n\t\t{\n\t\t\tassert(write + chunk->size <= buffer + total);\n\t\t\tmemcpy(write, chunk->data, chunk->size);\n\t\t\twrite += chunk->size;\n\t\t}\n\n\t\tassert(write == buffer + total);\n\n\t\t// return buffer\n\t\t*out_buffer = buffer;\n\t\t*out_size = total;\n\n\t\treturn status_ok;\n\t}\n\n\ttemplate <typename T> PUGI_IMPL_FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)\n\t{\n\t\t// get length of remaining data in stream\n\t\ttypename std::basic_istream<T>::pos_type pos = stream.tellg();\n\t\tstream.seekg(0, std::ios::end);\n\t\tstd::streamoff length = stream.tellg() - pos;\n\t\tstream.seekg(pos);\n\n\t\tif (stream.fail() || pos < 0) return status_io_error;\n\n\t\t// guard against huge files\n\t\tsize_t read_length = static_cast<size_t>(length);\n\n\t\tif (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;\n\n\t\tsize_t max_suffix_size = sizeof(char_t);\n\n\t\t// read stream data into memory (guard against stream exceptions with buffer holder)\n\t\tauto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);\n\t\tif (!buffer.data) return status_out_of_memory;\n\n\t\tstream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));\n\n\t\t// read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors\n\t\tif (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;\n\n\t\t// return buffer\n\t\tsize_t actual_length = static_cast<size_t>(stream.gcount());\n\t\tassert(actual_length <= read_length);\n\n\t\t*out_buffer = buffer.release();\n\t\t*out_size = actual_length * sizeof(T);\n\n\t\treturn status_ok;\n\t}\n\n\ttemplate <typename T> PUGI_IMPL_FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer)\n\t{\n\t\tvoid* buffer = NULL;\n\t\tsize_t size = 0;\n\t\txml_parse_status status = status_ok;\n\n\t\t// if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)\n\t\tif (stream.fail()) return make_parse_result(status_io_error);\n\n\t\t// load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)\n\t\tif (stream.tellg() < 0)\n\t\t{\n\t\t\tstream.clear(); // clear error flags that could be set by a failing tellg\n\t\t\tstatus = load_stream_data_noseek(stream, &buffer, &size);\n\t\t}\n\t\telse\n\t\t\tstatus = load_stream_data_seek(stream, &buffer, &size);\n\n\t\tif (status != status_ok) return make_parse_result(status);\n\n\t\txml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);\n\n\t\treturn load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);\n\t}\n#endif\n\n#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))\n\tPUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)\n\t{\n#ifdef PUGIXML_NO_STL\n\t\t// ensure these symbols are consistently referenced to avoid 'unreferenced function' warnings\n\t\t// note that generally these functions are used in STL builds, but PUGIXML_NO_STL leaves the only usage in convert_path_heap\n\t\t(void)&as_utf8_begin;\n\t\t(void)&as_utf8_end;\n\t\t(void)&strlength_wide;\n#endif\n\n#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400\n\t\tFILE* file = NULL;\n\t\treturn _wfopen_s(&file, path, mode) == 0 ? file : NULL;\n#else\n\t\treturn _wfopen(path, mode);\n#endif\n\t}\n#else\n\tPUGI_IMPL_FN char* convert_path_heap(const wchar_t* str)\n\t{\n\t\tassert(str);\n\n\t\t// first pass: get length in utf8 characters\n\t\tsize_t length = strlength_wide(str);\n\t\tsize_t size = as_utf8_begin(str, length);\n\n\t\t// allocate resulting string\n\t\tchar* result = static_cast<char*>(xml_memory::allocate(size + 1));\n\t\tif (!result) return NULL;\n\n\t\t// second pass: convert to utf8\n\t\tas_utf8_end(result, size, str, length);\n\n\t\t// zero-terminate\n\t\tresult[size] = 0;\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)\n\t{\n\t\t// there is no standard function to open wide paths, so our best bet is to try utf8 path\n\t\tchar* path_utf8 = convert_path_heap(path);\n\t\tif (!path_utf8) return NULL;\n\n\t\t// convert mode to ASCII (we mirror _wfopen interface)\n\t\tchar mode_ascii[4] = {0};\n\t\tfor (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);\n\n\t\t// try to open the utf8 path\n\t\tFILE* result = fopen(path_utf8, mode_ascii);\n\n\t\t// free dummy buffer\n\t\txml_memory::deallocate(path_utf8);\n\n\t\treturn result;\n\t}\n#endif\n\n\tPUGI_IMPL_FN FILE* open_file(const char* path, const char* mode)\n\t{\n#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400\n\t\tFILE* file = NULL;\n\t\treturn fopen_s(&file, path, mode) == 0 ? file : NULL;\n#else\n\t\treturn fopen(path, mode);\n#endif\n\t}\n\n\tPUGI_IMPL_FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)\n\t{\n\t\tif (!file) return false;\n\n\t\txml_writer_file writer(file);\n\t\tdoc.save(writer, indent, flags, encoding);\n\n\t\treturn fflush(file) == 0 && ferror(file) == 0;\n\t}\n\n\tstruct name_null_sentry\n\t{\n\t\txml_node_struct* node;\n\t\tchar_t* name;\n\n\t\tname_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)\n\t\t{\n\t\t\tnode->name = NULL;\n\t\t}\n\n\t\t~name_null_sentry()\n\t\t{\n\t\t\tnode->name = name;\n\t\t}\n\t};\nPUGI_IMPL_NS_END\n\nnamespace pugi\n{\n\tPUGI_IMPL_FN xml_writer::~xml_writer()\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_writer_file::xml_writer_file(void* file_): file(file_)\n\t{\n\t}\n\n\tPUGI_IMPL_FN void xml_writer_file::write(const void* data, size_t size)\n\t{\n\t\tsize_t result = fwrite(data, 1, size, static_cast<FILE*>(file));\n\t\t(void)!result; // unfortunately we can't do proper error handling here\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char>& stream): narrow_stream(&stream), wide_stream(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t>& stream): narrow_stream(NULL), wide_stream(&stream)\n\t{\n\t}\n\n\tPUGI_IMPL_FN void xml_writer_stream::write(const void* data, size_t size)\n\t{\n\t\tif (narrow_stream)\n\t\t{\n\t\t\tassert(!wide_stream);\n\t\t\tnarrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert(wide_stream);\n\t\t\tassert(size % sizeof(wchar_t) == 0);\n\n\t\t\twide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));\n\t\t}\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_tree_walker::xml_tree_walker(): _depth(0)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_tree_walker::~xml_tree_walker()\n\t{\n\t}\n\n\tPUGI_IMPL_FN int xml_tree_walker::depth() const\n\t{\n\t\treturn _depth;\n\t}\n\n\tPUGI_IMPL_FN bool xml_tree_walker::begin(xml_node&)\n\t{\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xml_tree_walker::end(xml_node&)\n\t{\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)\n\t{\n\t}\n\n\tPUGI_IMPL_FN static void unspecified_bool_xml_attribute(xml_attribute***)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_attribute::operator xml_attribute::unspecified_bool_type() const\n\t{\n\t\treturn _attr ? unspecified_bool_xml_attribute : NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator!() const\n\t{\n\t\treturn !_attr;\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator==(const xml_attribute& r) const\n\t{\n\t\treturn (_attr == r._attr);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator!=(const xml_attribute& r) const\n\t{\n\t\treturn (_attr != r._attr);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator<(const xml_attribute& r) const\n\t{\n\t\treturn (_attr < r._attr);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator>(const xml_attribute& r) const\n\t{\n\t\treturn (_attr > r._attr);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator<=(const xml_attribute& r) const\n\t{\n\t\treturn (_attr <= r._attr);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::operator>=(const xml_attribute& r) const\n\t{\n\t\treturn (_attr >= r._attr);\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_attribute::next_attribute() const\n\t{\n\t\tif (!_attr) return xml_attribute();\n\t\treturn xml_attribute(_attr->next_attribute);\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_attribute::previous_attribute() const\n\t{\n\t\tif (!_attr) return xml_attribute();\n\t\txml_attribute_struct* prev = _attr->prev_attribute_c;\n\t\treturn prev->next_attribute ? xml_attribute(prev) : xml_attribute();\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_attribute::as_string(const char_t* def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? value : def;\n\t}\n\n\tPUGI_IMPL_FN int xml_attribute::as_int(int def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_int(value) : def;\n\t}\n\n\tPUGI_IMPL_FN unsigned int xml_attribute::as_uint(unsigned int def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_uint(value) : def;\n\t}\n\n\tPUGI_IMPL_FN double xml_attribute::as_double(double def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_double(value) : def;\n\t}\n\n\tPUGI_IMPL_FN float xml_attribute::as_float(float def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_float(value) : def;\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::as_bool(bool def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_bool(value) : def;\n\t}\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN long long xml_attribute::as_llong(long long def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_llong(value) : def;\n\t}\n\n\tPUGI_IMPL_FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const\n\t{\n\t\tif (!_attr) return def;\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? impl::get_value_ullong(value) : def;\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_attribute::empty() const\n\t{\n\t\treturn !_attr;\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_attribute::name() const\n\t{\n\t\tif (!_attr) return PUGIXML_TEXT(\"\");\n\t\tconst char_t* name = _attr->name;\n\t\treturn name ? name : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_attribute::value() const\n\t{\n\t\tif (!_attr) return PUGIXML_TEXT(\"\");\n\t\tconst char_t* value = _attr->value;\n\t\treturn value ? value : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN size_t xml_attribute::hash_value() const\n\t{\n\t\treturn reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct);\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_struct* xml_attribute::internal_object() const\n\t{\n\t\treturn _attr;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(const char_t* rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(int rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned int rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(double rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(float rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(bool rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(string_view_t rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n#endif\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long long rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)\n\t{\n\t\tset_value(rhs);\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs, size_t size)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size);\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_attribute::set_name(string_view_t rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size());\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs, size_t size)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size);\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_attribute::set_value(string_view_t rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size());\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(int rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(unsigned int rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(long rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(unsigned long rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(double rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(double rhs, int precision)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(float rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(float rhs, int precision)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(bool rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);\n\t}\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN bool xml_attribute::set_value(long long rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute::set_value(unsigned long long rhs)\n\t{\n\t\tif (!_attr) return false;\n\n\t\treturn impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);\n\t}\n#endif\n\n#ifdef __BORLANDC__\n\tPUGI_IMPL_FN bool operator&&(const xml_attribute& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs && rhs;\n\t}\n\n\tPUGI_IMPL_FN bool operator||(const xml_attribute& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs || rhs;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node::xml_node(): _root(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node::xml_node(xml_node_struct* p): _root(p)\n\t{\n\t}\n\n\tPUGI_IMPL_FN static void unspecified_bool_xml_node(xml_node***)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node::operator xml_node::unspecified_bool_type() const\n\t{\n\t\treturn _root ? unspecified_bool_xml_node : NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator!() const\n\t{\n\t\treturn !_root;\n\t}\n\n\tPUGI_IMPL_FN xml_node::iterator xml_node::begin() const\n\t{\n\t\treturn iterator(_root ? _root->first_child + 0 : NULL, _root);\n\t}\n\n\tPUGI_IMPL_FN xml_node::iterator xml_node::end() const\n\t{\n\t\treturn iterator(NULL, _root);\n\t}\n\n\tPUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_begin() const\n\t{\n\t\treturn attribute_iterator(_root ? _root->first_attribute + 0 : NULL, _root);\n\t}\n\n\tPUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_end() const\n\t{\n\t\treturn attribute_iterator(NULL, _root);\n\t}\n\n\tPUGI_IMPL_FN xml_object_range<xml_node_iterator> xml_node::children() const\n\t{\n\t\treturn xml_object_range<xml_node_iterator>(begin(), end());\n\t}\n\n\tPUGI_IMPL_FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const\n\t{\n\t\treturn xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(NULL, _root, name_));\n\t}\n\n\tPUGI_IMPL_FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const\n\t{\n\t\treturn xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator==(const xml_node& r) const\n\t{\n\t\treturn (_root == r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator!=(const xml_node& r) const\n\t{\n\t\treturn (_root != r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator<(const xml_node& r) const\n\t{\n\t\treturn (_root < r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator>(const xml_node& r) const\n\t{\n\t\treturn (_root > r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator<=(const xml_node& r) const\n\t{\n\t\treturn (_root <= r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::operator>=(const xml_node& r) const\n\t{\n\t\treturn (_root >= r._root);\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::empty() const\n\t{\n\t\treturn !_root;\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_node::name() const\n\t{\n\t\tif (!_root) return PUGIXML_TEXT(\"\");\n\t\tconst char_t* name = _root->name;\n\t\treturn name ? name : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN xml_node_type xml_node::type() const\n\t{\n\t\treturn _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_node::value() const\n\t{\n\t\tif (!_root) return PUGIXML_TEXT(\"\");\n\t\tconst char_t* value = _root->value;\n\t\treturn value ? value : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::child(const char_t* name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_) const\n\t{\n\t\tif (!_root) return xml_attribute();\n\n\t\tfor (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t\treturn xml_attribute(i);\n\t\t}\n\n\t\treturn xml_attribute();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::next_sibling(const char_t* name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::next_sibling() const\n\t{\n\t\treturn _root ? xml_node(_root->next_sibling) : xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::previous_sibling(const char_t* name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_node xml_node::child(string_view_t name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::stringview_equal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_) const\n\t{\n\t\tif (!_root) return xml_attribute();\n\n\t\tfor (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::stringview_equal(name_, iname))\n\t\t\t\treturn xml_attribute(i);\n\t\t}\n\n\t\treturn xml_attribute();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::next_sibling(string_view_t name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::stringview_equal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::previous_sibling(string_view_t name_) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::stringview_equal(name_, iname))\n\t\t\t\treturn xml_node(i);\n\t\t}\n\n\t\treturn xml_node();\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const\n\t{\n\t\txml_attribute_struct* hint = hint_._attr;\n\n\t\t// if hint is not an attribute of node, behavior is not defined\n\t\tassert(!hint || (_root && impl::is_attribute_of(hint, _root)));\n\n\t\tif (!_root) return xml_attribute();\n\n\t\t// optimistically search from hint up until the end\n\t\tfor (xml_attribute_struct* i = hint; i; i = i->next_attribute)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t{\n\t\t\t\t// update hint to maximize efficiency of searching for consecutive attributes\n\t\t\t\thint_._attr = i->next_attribute;\n\n\t\t\t\treturn xml_attribute(i);\n\t\t\t}\n\t\t}\n\n\t\t// wrap around and search from the first attribute until the hint\n\t\t// 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails\n\t\tfor (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)\n\t\t{\n\t\t\tconst char_t* jname = j->name;\n\t\t\tif (jname && impl::strequal(name_, jname))\n\t\t\t{\n\t\t\t\t// update hint to maximize efficiency of searching for consecutive attributes\n\t\t\t\thint_._attr = j->next_attribute;\n\n\t\t\t\treturn xml_attribute(j);\n\t\t\t}\n\t\t}\n\n\t\treturn xml_attribute();\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const\n\t{\n\t\txml_attribute_struct* hint = hint_._attr;\n\n\t\t// if hint is not an attribute of node, behavior is not defined\n\t\tassert(!hint || (_root && impl::is_attribute_of(hint, _root)));\n\n\t\tif (!_root) return xml_attribute();\n\n\t\t// optimistically search from hint up until the end\n\t\tfor (xml_attribute_struct* i = hint; i; i = i->next_attribute)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::stringview_equal(name_, iname))\n\t\t\t{\n\t\t\t\t// update hint to maximize efficiency of searching for consecutive attributes\n\t\t\t\thint_._attr = i->next_attribute;\n\n\t\t\t\treturn xml_attribute(i);\n\t\t\t}\n\t\t}\n\n\t\t// wrap around and search from the first attribute until the hint\n\t\t// 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails\n\t\tfor (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)\n\t\t{\n\t\t\tconst char_t* jname = j->name;\n\t\t\tif (jname && impl::stringview_equal(name_, jname))\n\t\t\t{\n\t\t\t\t// update hint to maximize efficiency of searching for consecutive attributes\n\t\t\t\thint_._attr = j->next_attribute;\n\n\t\t\t\treturn xml_attribute(j);\n\t\t\t}\n\t\t}\n\n\t\treturn xml_attribute();\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node xml_node::previous_sibling() const\n\t{\n\t\tif (!_root) return xml_node();\n\t\txml_node_struct* prev = _root->prev_sibling_c;\n\t\treturn prev->next_sibling ? xml_node(prev) : xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::parent() const\n\t{\n\t\treturn _root ? xml_node(_root->parent) : xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::root() const\n\t{\n\t\treturn _root ? xml_node(&impl::get_document(_root)) : xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_text xml_node::text() const\n\t{\n\t\treturn xml_text(_root);\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_node::child_value() const\n\t{\n\t\tif (!_root) return PUGIXML_TEXT(\"\");\n\n\t\t// element nodes can have value if parse_embed_pcdata was used\n\t\tif (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value)\n\t\t\treturn _root->value;\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* ivalue = i->value;\n\t\t\tif (impl::is_text_node(i) && ivalue)\n\t\t\t\treturn ivalue;\n\t\t}\n\n\t\treturn PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_node::child_value(const char_t* name_) const\n\t{\n\t\treturn child(name_).child_value();\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::first_attribute() const\n\t{\n\t\tif (!_root) return xml_attribute();\n\t\treturn xml_attribute(_root->first_attribute);\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::last_attribute() const\n\t{\n\t\tif (!_root) return xml_attribute();\n\t\txml_attribute_struct* first = _root->first_attribute;\n\t\treturn first ? xml_attribute(first->prev_attribute_c) : xml_attribute();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::first_child() const\n\t{\n\t\tif (!_root) return xml_node();\n\t\treturn xml_node(_root->first_child);\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::last_child() const\n\t{\n\t\tif (!_root) return xml_node();\n\t\txml_node_struct* first = _root->first_child;\n\t\treturn first ? xml_node(first->prev_sibling_c) : xml_node();\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_element && type_ != node_pi && type_ != node_declaration)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs, size_t size)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_element && type_ != node_pi && type_ != node_declaration)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size);\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_node::set_name(string_view_t rhs)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_element && type_ != node_pi && type_ != node_declaration)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size());\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs, size_t size)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size);\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_node::set_value(string_view_t rhs)\n\t{\n\t\txml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;\n\n\t\tif (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)\n\t\t\treturn false;\n\n\t\treturn impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size());\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_attribute xml_node::append_attribute(const char_t* name_)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::append_attribute(a._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(const char_t* name_)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::prepend_attribute(a._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_after(a._attr, attr._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_before(a._attr, attr._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_attribute xml_node::append_attribute(string_view_t name_)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::append_attribute(a._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(string_view_t name_)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::prepend_attribute(a._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_after(a._attr, attr._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr)\n\t{\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_before(a._attr, attr._attr, _root);\n\n\t\ta.set_name(name_);\n\n\t\treturn a;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_attribute xml_node::append_copy(const xml_attribute& proto)\n\t{\n\t\tif (!proto) return xml_attribute();\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::append_attribute(a._attr, _root);\n\t\timpl::node_copy_attribute(a._attr, proto._attr);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)\n\t{\n\t\tif (!proto) return xml_attribute();\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::prepend_attribute(a._attr, _root);\n\t\timpl::node_copy_attribute(a._attr, proto._attr);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)\n\t{\n\t\tif (!proto) return xml_attribute();\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_after(a._attr, attr._attr, _root);\n\t\timpl::node_copy_attribute(a._attr, proto._attr);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)\n\t{\n\t\tif (!proto) return xml_attribute();\n\t\tif (!impl::allow_insert_attribute(type())) return xml_attribute();\n\t\tif (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_attribute();\n\n\t\txml_attribute a(impl::allocate_attribute(alloc));\n\t\tif (!a) return xml_attribute();\n\n\t\timpl::insert_attribute_before(a._attr, attr._attr, _root);\n\t\timpl::node_copy_attribute(a._attr, proto._attr);\n\n\t\treturn a;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::append_child(xml_node_type type_)\n\t{\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::append_node(n._root, _root);\n\n\t\tif (type_ == node_declaration) n.set_name(PUGIXML_TEXT(\"xml\"));\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::prepend_child(xml_node_type type_)\n\t{\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::prepend_node(n._root, _root);\n\n\t\tif (type_ == node_declaration) n.set_name(PUGIXML_TEXT(\"xml\"));\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)\n\t{\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::insert_node_before(n._root, node._root);\n\n\t\tif (type_ == node_declaration) n.set_name(PUGIXML_TEXT(\"xml\"));\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)\n\t{\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::insert_node_after(n._root, node._root);\n\n\t\tif (type_ == node_declaration) n.set_name(PUGIXML_TEXT(\"xml\"));\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::append_child(const char_t* name_)\n\t{\n\t\txml_node result = append_child(node_element);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::prepend_child(const char_t* name_)\n\t{\n\t\txml_node result = prepend_child(node_element);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)\n\t{\n\t\txml_node result = insert_child_after(node_element, node);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)\n\t{\n\t\txml_node result = insert_child_before(node_element, node);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_node xml_node::append_child(string_view_t name_)\n\t{\n\t\txml_node result = append_child(node_element);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::prepend_child(string_view_t name_)\n\t{\n\t\txml_node result = prepend_child(node_element);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node)\n\t{\n\t\txml_node result = insert_child_after(node_element, node);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node)\n\t{\n\t\txml_node result = insert_child_before(node_element, node);\n\n\t\tresult.set_name(name_);\n\n\t\treturn result;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node xml_node::append_copy(const xml_node& proto)\n\t{\n\t\txml_node_type type_ = proto.type();\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::append_node(n._root, _root);\n\t\timpl::node_copy_tree(n._root, proto._root);\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::prepend_copy(const xml_node& proto)\n\t{\n\t\txml_node_type type_ = proto.type();\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::prepend_node(n._root, _root);\n\t\timpl::node_copy_tree(n._root, proto._root);\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)\n\t{\n\t\txml_node_type type_ = proto.type();\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::insert_node_after(n._root, node._root);\n\t\timpl::node_copy_tree(n._root, proto._root);\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)\n\t{\n\t\txml_node_type type_ = proto.type();\n\t\tif (!impl::allow_insert_child(type(), type_)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\txml_node n(impl::allocate_node(alloc, type_));\n\t\tif (!n) return xml_node();\n\n\t\timpl::insert_node_before(n._root, node._root);\n\t\timpl::node_copy_tree(n._root, proto._root);\n\n\t\treturn n;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::append_move(const xml_node& moved)\n\t{\n\t\tif (!impl::allow_move(*this, moved)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\t// disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers\n\t\timpl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;\n\n\t\timpl::remove_node(moved._root);\n\t\timpl::append_node(moved._root, _root);\n\n\t\treturn moved;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::prepend_move(const xml_node& moved)\n\t{\n\t\tif (!impl::allow_move(*this, moved)) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\t// disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers\n\t\timpl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;\n\n\t\timpl::remove_node(moved._root);\n\t\timpl::prepend_node(moved._root, _root);\n\n\t\treturn moved;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node)\n\t{\n\t\tif (!impl::allow_move(*this, moved)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\t\tif (moved._root == node._root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\t// disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers\n\t\timpl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;\n\n\t\timpl::remove_node(moved._root);\n\t\timpl::insert_node_after(moved._root, node._root);\n\n\t\treturn moved;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node)\n\t{\n\t\tif (!impl::allow_move(*this, moved)) return xml_node();\n\t\tif (!node._root || node._root->parent != _root) return xml_node();\n\t\tif (moved._root == node._root) return xml_node();\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return xml_node();\n\n\t\t// disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers\n\t\timpl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;\n\n\t\timpl::remove_node(moved._root);\n\t\timpl::insert_node_before(moved._root, node._root);\n\n\t\treturn moved;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::remove_attribute(const char_t* name_)\n\t{\n\t\treturn remove_attribute(attribute(name_));\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_node::remove_attribute(string_view_t name_)\n\t{\n\t\treturn remove_attribute(attribute(name_));\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_node::remove_attribute(const xml_attribute& a)\n\t{\n\t\tif (!_root || !a._attr) return false;\n\t\tif (!impl::is_attribute_of(a._attr, _root)) return false;\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return false;\n\n\t\timpl::remove_attribute(a._attr, _root);\n\t\timpl::destroy_attribute(a._attr, alloc);\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::remove_attributes()\n\t{\n\t\tif (!_root) return false;\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return false;\n\n\t\tfor (xml_attribute_struct* attr = _root->first_attribute; attr; )\n\t\t{\n\t\t\txml_attribute_struct* next = attr->next_attribute;\n\n\t\t\timpl::destroy_attribute(attr, alloc);\n\n\t\t\tattr = next;\n\t\t}\n\n\t\t_root->first_attribute = NULL;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::remove_child(const char_t* name_)\n\t{\n\t\treturn remove_child(child(name_));\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_node::remove_child(string_view_t name_)\n\t{\n\t\treturn remove_child(child(name_));\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_node::remove_child(const xml_node& n)\n\t{\n\t\tif (!_root || !n._root || n._root->parent != _root) return false;\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return false;\n\n\t\timpl::remove_node(n._root);\n\t\timpl::destroy_node(n._root, alloc);\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::remove_children()\n\t{\n\t\tif (!_root) return false;\n\n\t\timpl::xml_allocator& alloc = impl::get_allocator(_root);\n\t\tif (!alloc.reserve()) return false;\n\n\t\tfor (xml_node_struct* cur = _root->first_child; cur; )\n\t\t{\n\t\t\txml_node_struct* next = cur->next_sibling;\n\n\t\t\timpl::destroy_node(cur, alloc);\n\n\t\t\tcur = next;\n\t\t}\n\n\t\t_root->first_child = NULL;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)\n\t{\n\t\t// append_buffer is only valid for elements/documents\n\t\tif (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);\n\n\t\t// append buffer can not merge PCDATA into existing PCDATA nodes\n\t\tif ((options & parse_merge_pcdata) != 0 && last_child().type() == node_pcdata) return impl::make_parse_result(status_append_invalid_root);\n\n\t\t// get document node\n\t\timpl::xml_document_struct* doc = &impl::get_document(_root);\n\n\t\t// disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense\n\t\tdoc->header |= impl::xml_memory_page_contents_shared_mask;\n\n\t\t// get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)\n\t\timpl::xml_memory_page* page = NULL;\n\t\timpl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page));\n\t\t(void)page;\n\n\t\tif (!extra) return impl::make_parse_result(status_out_of_memory);\n\n\t#ifdef PUGIXML_COMPACT\n\t\t// align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned\n\t\t// note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account\n\t\textra = reinterpret_cast<impl::xml_extra_buffer*>((reinterpret_cast<uintptr_t>(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1));\n\t#endif\n\n\t\t// add extra buffer to the list\n\t\textra->buffer = NULL;\n\t\textra->next = doc->extra_buffers;\n\t\tdoc->extra_buffers = extra;\n\n\t\t// name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level\n\t\timpl::name_null_sentry sentry(_root);\n\n\t\treturn impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\tif (iname && impl::strequal(name_, iname))\n\t\t\t{\n\t\t\t\tfor (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)\n\t\t\t\t{\n\t\t\t\t\tconst char_t* aname = a->name;\n\t\t\t\t\tif (aname && impl::strequal(attr_name, aname))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst char_t* avalue = a->value;\n\t\t\t\t\t\tif (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(\"\")))\n\t\t\t\t\t\t\treturn xml_node(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn xml_node();\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const\n\t{\n\t\tif (!_root) return xml_node();\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t\tfor (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)\n\t\t\t{\n\t\t\t\tconst char_t* aname = a->name;\n\t\t\t\tif (aname && impl::strequal(attr_name, aname))\n\t\t\t\t{\n\t\t\t\t\tconst char_t* avalue = a->value;\n\t\t\t\t\tif (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(\"\")))\n\t\t\t\t\t\treturn xml_node(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\treturn xml_node();\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN string_t xml_node::path(char_t delimiter) const\n\t{\n\t\tif (!_root) return string_t();\n\n\t\tsize_t offset = 0;\n\n\t\tfor (xml_node_struct* i = _root; i; i = i->parent)\n\t\t{\n\t\t\tconst char_t* iname = i->name;\n\t\t\toffset += (i != _root);\n\t\t\toffset += iname ? impl::strlength(iname) : 0;\n\t\t}\n\n\t\tstring_t result;\n\t\tresult.resize(offset);\n\n\t\tfor (xml_node_struct* j = _root; j; j = j->parent)\n\t\t{\n\t\t\tif (j != _root)\n\t\t\t\tresult[--offset] = delimiter;\n\n\t\t\tconst char_t* jname = j->name;\n\t\t\tif (jname)\n\t\t\t{\n\t\t\t\tsize_t length = impl::strlength(jname);\n\n\t\t\t\toffset -= length;\n\t\t\t\tmemcpy(&result[offset], jname, length * sizeof(char_t));\n\t\t\t}\n\t\t}\n\n\t\tassert(offset == 0);\n\n\t\treturn result;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const\n\t{\n\t\txml_node context = path_[0] == delimiter ? root() : *this;\n\n\t\tif (!context._root) return xml_node();\n\n\t\tconst char_t* path_segment = path_;\n\n\t\twhile (*path_segment == delimiter) ++path_segment;\n\n\t\tconst char_t* path_segment_end = path_segment;\n\n\t\twhile (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;\n\n\t\tif (path_segment == path_segment_end) return context;\n\n\t\tconst char_t* next_segment = path_segment_end;\n\n\t\twhile (*next_segment == delimiter) ++next_segment;\n\n\t\tif (*path_segment == '.' && path_segment + 1 == path_segment_end)\n\t\t\treturn context.first_element_by_path(next_segment, delimiter);\n\t\telse if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)\n\t\t\treturn context.parent().first_element_by_path(next_segment, delimiter);\n\t\telse\n\t\t{\n\t\t\tfor (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling)\n\t\t\t{\n\t\t\t\tconst char_t* jname = j->name;\n\t\t\t\tif (jname && impl::strequalrange(jname, path_segment, static_cast<size_t>(path_segment_end - path_segment)))\n\t\t\t\t{\n\t\t\t\t\txml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);\n\n\t\t\t\t\tif (subsearch) return subsearch;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn xml_node();\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN bool xml_node::traverse(xml_tree_walker& walker)\n\t{\n\t\twalker._depth = -1;\n\n\t\txml_node arg_begin(_root);\n\t\tif (!walker.begin(arg_begin)) return false;\n\n\t\txml_node_struct* cur = _root ? _root->first_child + 0 : NULL;\n\n\t\tif (cur)\n\t\t{\n\t\t\t++walker._depth;\n\n\t\t\tdo\n\t\t\t{\n\t\t\t\txml_node arg_for_each(cur);\n\t\t\t\tif (!walker.for_each(arg_for_each))\n\t\t\t\t\treturn false;\n\n\t\t\t\tif (cur->first_child)\n\t\t\t\t{\n\t\t\t\t\t++walker._depth;\n\t\t\t\t\tcur = cur->first_child;\n\t\t\t\t}\n\t\t\t\telse if (cur->next_sibling)\n\t\t\t\t\tcur = cur->next_sibling;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twhile (!cur->next_sibling && cur != _root && cur->parent)\n\t\t\t\t\t{\n\t\t\t\t\t\t--walker._depth;\n\t\t\t\t\t\tcur = cur->parent;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (cur != _root)\n\t\t\t\t\t\tcur = cur->next_sibling;\n\t\t\t\t}\n\t\t\t}\n\t\t\twhile (cur && cur != _root);\n\t\t}\n\n\t\tassert(walker._depth == -1);\n\n\t\txml_node arg_end(_root);\n\t\treturn walker.end(arg_end);\n\t}\n\n\tPUGI_IMPL_FN size_t xml_node::hash_value() const\n\t{\n\t\treturn reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct);\n\t}\n\n\tPUGI_IMPL_FN xml_node_struct* xml_node::internal_object() const\n\t{\n\t\treturn _root;\n\t}\n\n\tPUGI_IMPL_FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const\n\t{\n\t\tif (!_root) return;\n\n\t\timpl::xml_buffered_writer buffered_writer(writer, encoding);\n\n\t\timpl::node_output(buffered_writer, _root, indent, flags, depth);\n\n\t\tbuffered_writer.flush();\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN void xml_node::print(std::basic_ostream<char>& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const\n\t{\n\t\txml_writer_stream writer(stream);\n\n\t\tprint(writer, indent, flags, encoding, depth);\n\t}\n\n\tPUGI_IMPL_FN void xml_node::print(std::basic_ostream<wchar_t>& stream, const char_t* indent, unsigned int flags, unsigned int depth) const\n\t{\n\t\txml_writer_stream writer(stream);\n\n\t\tprint(writer, indent, flags, encoding_wchar, depth);\n\t}\n#endif\n\n\tPUGI_IMPL_FN ptrdiff_t xml_node::offset_debug() const\n\t{\n\t\tif (!_root) return -1;\n\n\t\timpl::xml_document_struct& doc = impl::get_document(_root);\n\n\t\t// we can determine the offset reliably only if there is exactly once parse buffer\n\t\tif (!doc.buffer || doc.extra_buffers) return -1;\n\n\t\tswitch (type())\n\t\t{\n\t\tcase node_document:\n\t\t\treturn 0;\n\n\t\tcase node_element:\n\t\tcase node_declaration:\n\t\tcase node_pi:\n\t\t\treturn _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;\n\n\t\tcase node_pcdata:\n\t\tcase node_cdata:\n\t\tcase node_comment:\n\t\tcase node_doctype:\n\t\t\treturn _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;\n\n\t\tdefault:\n\t\t\tassert(false && \"Invalid node type\"); // unreachable\n\t\t\treturn -1;\n\t\t}\n\t}\n\n#ifdef __BORLANDC__\n\tPUGI_IMPL_FN bool operator&&(const xml_node& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs && rhs;\n\t}\n\n\tPUGI_IMPL_FN bool operator||(const xml_node& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs || rhs;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_text::xml_text(xml_node_struct* root): _root(root)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node_struct* xml_text::_data() const\n\t{\n\t\tif (!_root || impl::is_text_node(_root)) return _root;\n\n\t\t// element nodes can have value if parse_embed_pcdata was used\n\t\tif (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value)\n\t\t\treturn _root;\n\n\t\tfor (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)\n\t\t\tif (impl::is_text_node(node))\n\t\t\t\treturn node;\n\n\t\treturn NULL;\n\t}\n\n\tPUGI_IMPL_FN xml_node_struct* xml_text::_data_new()\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (d) return d;\n\n\t\treturn xml_node(_root).append_child(node_pcdata).internal_object();\n\t}\n\n\tPUGI_IMPL_FN xml_text::xml_text(): _root(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN static void unspecified_bool_xml_text(xml_text***)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_text::operator xml_text::unspecified_bool_type() const\n\t{\n\t\treturn _data() ? unspecified_bool_xml_text : NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::operator!() const\n\t{\n\t\treturn !_data();\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::empty() const\n\t{\n\t\treturn _data() == NULL;\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_text::get() const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return PUGIXML_TEXT(\"\");\n\t\tconst char_t* value = d->value;\n\t\treturn value ? value : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const char_t* xml_text::as_string(const char_t* def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? value : def;\n\t}\n\n\tPUGI_IMPL_FN int xml_text::as_int(int def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_int(value) : def;\n\t}\n\n\tPUGI_IMPL_FN unsigned int xml_text::as_uint(unsigned int def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_uint(value) : def;\n\t}\n\n\tPUGI_IMPL_FN double xml_text::as_double(double def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_double(value) : def;\n\t}\n\n\tPUGI_IMPL_FN float xml_text::as_float(float def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_float(value) : def;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::as_bool(bool def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_bool(value) : def;\n\t}\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN long long xml_text::as_llong(long long def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_llong(value) : def;\n\t}\n\n\tPUGI_IMPL_FN unsigned long long xml_text::as_ullong(unsigned long long def) const\n\t{\n\t\txml_node_struct* d = _data();\n\t\tif (!d) return def;\n\t\tconst char_t* value = d->value;\n\t\treturn value ? impl::get_value_ullong(value) : def;\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_text::set(const char_t* rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(const char_t* rhs, size_t size)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, size) : false;\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN bool xml_text::set(string_view_t rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()) : false;\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_text::set(int rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(unsigned int rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(long rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(unsigned long rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(float rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(float rhs, int precision)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(double rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(double rhs, int precision)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(bool rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;\n\t}\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN bool xml_text::set(long long rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xml_text::set(unsigned long long rhs)\n\t{\n\t\txml_node_struct* dn = _data_new();\n\n\t\treturn dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(const char_t* rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(int rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(unsigned int rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(long rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(double rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(float rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(bool rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(string_view_t rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n#endif\n\n#ifdef PUGIXML_HAS_LONG_LONG\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(long long rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long long rhs)\n\t{\n\t\tset(rhs);\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node xml_text::data() const\n\t{\n\t\treturn xml_node(_data());\n\t}\n\n#ifdef __BORLANDC__\n\tPUGI_IMPL_FN bool operator&&(const xml_text& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs && rhs;\n\t}\n\n\tPUGI_IMPL_FN bool operator||(const xml_text& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs || rhs;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_node_iterator::xml_node_iterator()\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)\n\t{\n\t}\n\n\tPUGI_IMPL_FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const\n\t{\n\t\treturn _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const\n\t{\n\t\treturn _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN xml_node& xml_node_iterator::operator*() const\n\t{\n\t\tassert(_wrap._root);\n\t\treturn _wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_node* xml_node_iterator::operator->() const\n\t{\n\t\tassert(_wrap._root);\n\t\treturn &_wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator++()\n\t{\n\t\tassert(_wrap._root);\n\t\t_wrap._root = _wrap._root->next_sibling;\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator++(int)\n\t{\n\t\txml_node_iterator temp = *this;\n\t\t++*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator--()\n\t{\n\t\t_wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator--(int)\n\t{\n\t\txml_node_iterator temp = *this;\n\t\t--*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator()\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)\n\t{\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const\n\t{\n\t\treturn _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const\n\t{\n\t\treturn _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute& xml_attribute_iterator::operator*() const\n\t{\n\t\tassert(_wrap._attr);\n\t\treturn _wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute* xml_attribute_iterator::operator->() const\n\t{\n\t\tassert(_wrap._attr);\n\t\treturn &_wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator++()\n\t{\n\t\tassert(_wrap._attr);\n\t\t_wrap._attr = _wrap._attr->next_attribute;\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator++(int)\n\t{\n\t\txml_attribute_iterator temp = *this;\n\t\t++*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator--()\n\t{\n\t\t_wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator--(int)\n\t{\n\t\txml_attribute_iterator temp = *this;\n\t\t--*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(): _name(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name)\n\t{\n\t}\n\n\tPUGI_IMPL_FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const\n\t{\n\t\treturn _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const\n\t{\n\t\treturn _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;\n\t}\n\n\tPUGI_IMPL_FN xml_node& xml_named_node_iterator::operator*() const\n\t{\n\t\tassert(_wrap._root);\n\t\treturn _wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_node* xml_named_node_iterator::operator->() const\n\t{\n\t\tassert(_wrap._root);\n\t\treturn &_wrap;\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator++()\n\t{\n\t\tassert(_wrap._root);\n\t\t_wrap = _wrap.next_sibling(_name);\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator++(int)\n\t{\n\t\txml_named_node_iterator temp = *this;\n\t\t++*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator--()\n\t{\n\t\tif (_wrap._root)\n\t\t\t_wrap = _wrap.previous_sibling(_name);\n\t\telse\n\t\t{\n\t\t\t_wrap = _parent.last_child();\n\n\t\t\tif (!impl::strequal(_wrap.name(), _name))\n\t\t\t\t_wrap = _wrap.previous_sibling(_name);\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\tPUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator--(int)\n\t{\n\t\txml_named_node_iterator temp = *this;\n\t\t--*this;\n\t\treturn temp;\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result::operator bool() const\n\t{\n\t\treturn status == status_ok;\n\t}\n\n\tPUGI_IMPL_FN const char* xml_parse_result::description() const\n\t{\n\t\tswitch (status)\n\t\t{\n\t\tcase status_ok: return \"No error\";\n\n\t\tcase status_file_not_found: return \"File was not found\";\n\t\tcase status_io_error: return \"Error reading from file/stream\";\n\t\tcase status_out_of_memory: return \"Could not allocate memory\";\n\t\tcase status_internal_error: return \"Internal error occurred\";\n\n\t\tcase status_unrecognized_tag: return \"Could not determine tag type\";\n\n\t\tcase status_bad_pi: return \"Error parsing document declaration/processing instruction\";\n\t\tcase status_bad_comment: return \"Error parsing comment\";\n\t\tcase status_bad_cdata: return \"Error parsing CDATA section\";\n\t\tcase status_bad_doctype: return \"Error parsing document type declaration\";\n\t\tcase status_bad_pcdata: return \"Error parsing PCDATA section\";\n\t\tcase status_bad_start_element: return \"Error parsing start element tag\";\n\t\tcase status_bad_attribute: return \"Error parsing element attribute\";\n\t\tcase status_bad_end_element: return \"Error parsing end element tag\";\n\t\tcase status_end_element_mismatch: return \"Start-end tags mismatch\";\n\n\t\tcase status_append_invalid_root: return \"Unable to append nodes: root is not an element or document\";\n\n\t\tcase status_no_document_element: return \"No document element found\";\n\n\t\tdefault: return \"Unknown error\";\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xml_document::xml_document(): _buffer(NULL)\n\t{\n\t\t_create();\n\t}\n\n\tPUGI_IMPL_FN xml_document::~xml_document()\n\t{\n\t\t_destroy();\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(NULL)\n\t{\n\t\t_create();\n\t\t_move(rhs);\n\t}\n\n\tPUGI_IMPL_FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT\n\t{\n\t\tif (this == &rhs) return *this;\n\n\t\t_destroy();\n\t\t_create();\n\t\t_move(rhs);\n\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN void xml_document::reset()\n\t{\n\t\t_destroy();\n\t\t_create();\n\t}\n\n\tPUGI_IMPL_FN void xml_document::reset(const xml_document& proto)\n\t{\n\t\treset();\n\n\t\timpl::node_copy_tree(_root, proto._root);\n\t}\n\n\tPUGI_IMPL_FN void xml_document::_create()\n\t{\n\t\tassert(!_root);\n\n\t#ifdef PUGIXML_COMPACT\n\t\t// space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit\n\t\tconst size_t page_offset = sizeof(void*);\n\t#else\n\t\tconst size_t page_offset = 0;\n\t#endif\n\n\t\t// initialize sentinel page\n\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));\n\n\t\t// prepare page structure\n\t\timpl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);\n\t\tassert(page);\n\n\t\tpage->busy_size = impl::xml_memory_page_size;\n\n\t\t// setup first page marker\n\t#ifdef PUGIXML_COMPACT\n\t\t// round-trip through void* to avoid 'cast increases required alignment of target type' warning\n\t\tpage->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));\n\t\t*page->compact_page_marker = sizeof(impl::xml_memory_page);\n\t#endif\n\n\t\t// allocate new root\n\t\t_root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);\n\t\t_root->prev_sibling_c = _root;\n\n\t\t// setup sentinel page\n\t\tpage->allocator = static_cast<impl::xml_document_struct*>(_root);\n\n\t\t// setup hash table pointer in allocator\n\t#ifdef PUGIXML_COMPACT\n\t\tpage->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash;\n\t#endif\n\n\t\t// verify the document allocation\n\t\tassert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));\n\t}\n\n\tPUGI_IMPL_FN void xml_document::_destroy()\n\t{\n\t\tassert(_root);\n\n\t\t// destroy static storage\n\t\tif (_buffer)\n\t\t{\n\t\t\timpl::xml_memory::deallocate(_buffer);\n\t\t\t_buffer = NULL;\n\t\t}\n\n\t\t// destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)\n\t\tfor (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)\n\t\t{\n\t\t\tif (extra->buffer) impl::xml_memory::deallocate(extra->buffer);\n\t\t}\n\n\t\t// destroy dynamic storage, leave sentinel page (it's in static memory)\n\t\timpl::xml_memory_page* root_page = PUGI_IMPL_GETPAGE(_root);\n\t\tassert(root_page && !root_page->prev);\n\t\tassert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));\n\n\t\tfor (impl::xml_memory_page* page = root_page->next; page; )\n\t\t{\n\t\t\timpl::xml_memory_page* next = page->next;\n\n\t\t\timpl::xml_allocator::deallocate_page(page);\n\n\t\t\tpage = next;\n\t\t}\n\n\t#ifdef PUGIXML_COMPACT\n\t\t// destroy hash table\n\t\tstatic_cast<impl::xml_document_struct*>(_root)->hash.clear();\n\t#endif\n\n\t\t_root = NULL;\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT\n\t{\n\t\timpl::xml_document_struct* doc = static_cast<impl::xml_document_struct*>(_root);\n\t\timpl::xml_document_struct* other = static_cast<impl::xml_document_struct*>(rhs._root);\n\n\t\t// save first child pointer for later; this needs hash access\n\t\txml_node_struct* other_first_child = other->first_child;\n\n\t#ifdef PUGIXML_COMPACT\n\t\t// reserve space for the hash table up front; this is the only operation that can fail\n\t\t// if it does, we have no choice but to throw (if we have exceptions)\n\t\tif (other_first_child)\n\t\t{\n\t\t\tsize_t other_children = 0;\n\t\t\tfor (xml_node_struct* node = other_first_child; node; node = node->next_sibling)\n\t\t\t\tother_children++;\n\n\t\t\t// in compact mode, each pointer assignment could result in a hash table request\n\t\t\t// during move, we have to relocate document first_child and parents of all children\n\t\t\t// normally there's just one child and its parent has a pointerless encoding but\n\t\t\t// we assume the worst here\n\t\t\tif (!other->_hash->reserve(other_children + 1))\n\t\t\t{\n\t\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\t\treturn;\n\t\t\t#else\n\t\t\t\tthrow std::bad_alloc();\n\t\t\t#endif\n\t\t\t}\n\t\t}\n\t#endif\n\n\t\t// move allocation state\n\t\t// note that other->_root may point to the embedded document page, in which case we should keep original (empty) state\n\t\tif (other->_root != PUGI_IMPL_GETPAGE(other))\n\t\t{\n\t\t\tdoc->_root = other->_root;\n\t\t\tdoc->_busy_size = other->_busy_size;\n\t\t}\n\n\t\t// move buffer state\n\t\tdoc->buffer = other->buffer;\n\t\tdoc->extra_buffers = other->extra_buffers;\n\t\t_buffer = rhs._buffer;\n\n\t#ifdef PUGIXML_COMPACT\n\t\t// move compact hash; note that the hash table can have pointers to other but they will be \"inactive\", similarly to nodes removed with remove_child\n\t\tdoc->hash = other->hash;\n\t\tdoc->_hash = &doc->hash;\n\n\t\t// make sure we don't access other hash up until the end when we reinitialize other document\n\t\tother->_hash = NULL;\n\t#endif\n\n\t\t// move page structure\n\t\timpl::xml_memory_page* doc_page = PUGI_IMPL_GETPAGE(doc);\n\t\tassert(doc_page && !doc_page->prev && !doc_page->next);\n\n\t\timpl::xml_memory_page* other_page = PUGI_IMPL_GETPAGE(other);\n\t\tassert(other_page && !other_page->prev);\n\n\t\t// relink pages since root page is embedded into xml_document\n\t\tif (impl::xml_memory_page* page = other_page->next)\n\t\t{\n\t\t\tassert(page->prev == other_page);\n\n\t\t\tpage->prev = doc_page;\n\n\t\t\tdoc_page->next = page;\n\t\t\tother_page->next = NULL;\n\t\t}\n\n\t\t// make sure pages point to the correct document state\n\t\tfor (impl::xml_memory_page* page = doc_page->next; page; page = page->next)\n\t\t{\n\t\t\tassert(page->allocator == other);\n\n\t\t\tpage->allocator = doc;\n\n\t\t#ifdef PUGIXML_COMPACT\n\t\t\t// this automatically migrates most children between documents and prevents ->parent assignment from allocating\n\t\t\tif (page->compact_shared_parent == other)\n\t\t\t\tpage->compact_shared_parent = doc;\n\t\t#endif\n\t\t}\n\n\t\t// move tree structure\n\t\tassert(!doc->first_child);\n\n\t\tdoc->first_child = other_first_child;\n\n\t\tfor (xml_node_struct* node = other_first_child; node; node = node->next_sibling)\n\t\t{\n\t\t#ifdef PUGIXML_COMPACT\n\t\t\t// most children will have migrated when we reassigned compact_shared_parent\n\t\t\tassert(node->parent == other || node->parent == doc);\n\n\t\t\tnode->parent = doc;\n\t\t#else\n\t\t\tassert(node->parent == other);\n\t\t\tnode->parent = doc;\n\t\t#endif\n\t\t}\n\n\t\t// reset other document\n\t\tnew (other) impl::xml_document_struct(PUGI_IMPL_GETPAGE(other));\n\t\trhs._buffer = NULL;\n\t}\n#endif\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream<char>& stream, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\treturn impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream<wchar_t>& stream, unsigned int options)\n\t{\n\t\treset();\n\n\t\treturn impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);\n\t}\n#endif\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)\n\t{\n\t\t// Force native encoding (skip autodetection)\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\txml_encoding encoding = encoding_wchar;\n\t#else\n\t\txml_encoding encoding = encoding_utf8;\n\t#endif\n\n\t\treturn load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)\n\t{\n\t\treturn load_string(contents, options);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\tusing impl::auto_deleter; // MSVC7 workaround\n\t\tauto_deleter<FILE> file(impl::open_file(path_, \"rb\"), impl::close_file);\n\n\t\treturn impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\tusing impl::auto_deleter; // MSVC7 workaround\n\t\tauto_deleter<FILE> file(impl::open_file_wide(path_, L\"rb\"), impl::close_file);\n\n\t\treturn impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\treturn impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\treturn impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)\n\t{\n\t\treset();\n\n\t\treturn impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);\n\t}\n\n\tPUGI_IMPL_FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const\n\t{\n\t\timpl::xml_buffered_writer buffered_writer(writer, encoding);\n\n\t\tif ((flags & format_write_bom) && buffered_writer.encoding != encoding_latin1)\n\t\t{\n\t\t\t// BOM always represents the codepoint U+FEFF, so just write it in native encoding\n\t\t#ifdef PUGIXML_WCHAR_MODE\n\t\t\tunsigned int bom = 0xfeff;\n\t\t\tbuffered_writer.write(static_cast<wchar_t>(bom));\n\t\t#else\n\t\t\tbuffered_writer.write('\\xef', '\\xbb', '\\xbf');\n\t\t#endif\n\t\t}\n\n\t\tif (!(flags & format_no_declaration) && !impl::has_declaration(_root))\n\t\t{\n\t\t\tbuffered_writer.write_string(PUGIXML_TEXT(\"<?xml version=\\\"1.0\\\"\"));\n\t\t\tif (buffered_writer.encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(\" encoding=\\\"ISO-8859-1\\\"\"));\n\t\t\tbuffered_writer.write('?', '>');\n\t\t\tif (!(flags & format_raw)) buffered_writer.write('\\n');\n\t\t}\n\n\t\timpl::node_output(buffered_writer, _root, indent, flags, 0);\n\n\t\tbuffered_writer.flush();\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN void xml_document::save(std::basic_ostream<char>& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const\n\t{\n\t\txml_writer_stream writer(stream);\n\n\t\tsave(writer, indent, flags, encoding);\n\t}\n\n\tPUGI_IMPL_FN void xml_document::save(std::basic_ostream<wchar_t>& stream, const char_t* indent, unsigned int flags) const\n\t{\n\t\txml_writer_stream writer(stream);\n\n\t\tsave(writer, indent, flags, encoding_wchar);\n\t}\n#endif\n\n\tPUGI_IMPL_FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const\n\t{\n\t\tusing impl::auto_deleter; // MSVC7 workaround\n\t\tauto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ? \"w\" : \"wb\"), impl::close_file);\n\n\t\treturn impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;\n\t}\n\n\tPUGI_IMPL_FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const\n\t{\n\t\tusing impl::auto_deleter; // MSVC7 workaround\n\t\tauto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L\"w\" : L\"wb\"), impl::close_file);\n\n\t\treturn impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;\n\t}\n\n\tPUGI_IMPL_FN xml_node xml_document::document_element() const\n\t{\n\t\tassert(_root);\n\n\t\tfor (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)\n\t\t\tif (PUGI_IMPL_NODETYPE(i) == node_element)\n\t\t\t\treturn xml_node(i);\n\n\t\treturn xml_node();\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)\n\t{\n\t\tassert(str);\n\n\t\treturn impl::as_utf8_impl(str, impl::strlength_wide(str));\n\t}\n\n\tPUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)\n\t{\n\t\treturn impl::as_utf8_impl(str.c_str(), str.size());\n\t}\n\n\tPUGI_IMPL_FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)\n\t{\n\t\tassert(str);\n\n\t\treturn impl::as_wide_impl(str, strlen(str));\n\t}\n\n\tPUGI_IMPL_FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)\n\t{\n\t\treturn impl::as_wide_impl(str.c_str(), str.size());\n\t}\n#endif\n\n\tPUGI_IMPL_FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)\n\t{\n\t\timpl::xml_memory::allocate = allocate;\n\t\timpl::xml_memory::deallocate = deallocate;\n\t}\n\n\tPUGI_IMPL_FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()\n\t{\n\t\treturn impl::xml_memory::allocate;\n\t}\n\n\tPUGI_IMPL_FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()\n\t{\n\t\treturn impl::xml_memory::deallocate;\n\t}\n}\n\n#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))\nnamespace std\n{\n\t// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n}\n#endif\n\n#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)\nnamespace std\n{\n\t// Workarounds for (non-standard) iterator category detection\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n\n\tPUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)\n\t{\n\t\treturn std::bidirectional_iterator_tag();\n\t}\n}\n#endif\n\n#ifndef PUGIXML_NO_XPATH\n// STL replacements\nPUGI_IMPL_NS_BEGIN\n\tstruct equal_to\n\t{\n\t\ttemplate <typename T> bool operator()(const T& lhs, const T& rhs) const\n\t\t{\n\t\t\treturn lhs == rhs;\n\t\t}\n\t};\n\n\tstruct not_equal_to\n\t{\n\t\ttemplate <typename T> bool operator()(const T& lhs, const T& rhs) const\n\t\t{\n\t\t\treturn lhs != rhs;\n\t\t}\n\t};\n\n\tstruct less\n\t{\n\t\ttemplate <typename T> bool operator()(const T& lhs, const T& rhs) const\n\t\t{\n\t\t\treturn lhs < rhs;\n\t\t}\n\t};\n\n\tstruct less_equal\n\t{\n\t\ttemplate <typename T> bool operator()(const T& lhs, const T& rhs) const\n\t\t{\n\t\t\treturn lhs <= rhs;\n\t\t}\n\t};\n\n\ttemplate <typename T> inline void swap(T& lhs, T& rhs)\n\t{\n\t\tT temp = lhs;\n\t\tlhs = rhs;\n\t\trhs = temp;\n\t}\n\n\ttemplate <typename I, typename Pred> PUGI_IMPL_FN I min_element(I begin, I end, const Pred& pred)\n\t{\n\t\tI result = begin;\n\n\t\tfor (I it = begin + 1; it != end; ++it)\n\t\t\tif (pred(*it, *result))\n\t\t\t\tresult = it;\n\n\t\treturn result;\n\t}\n\n\ttemplate <typename I> PUGI_IMPL_FN void reverse(I begin, I end)\n\t{\n\t\twhile (end - begin > 1)\n\t\t\tswap(*begin++, *--end);\n\t}\n\n\ttemplate <typename I> PUGI_IMPL_FN I unique(I begin, I end)\n\t{\n\t\t// fast skip head\n\t\twhile (end - begin > 1 && *begin != *(begin + 1))\n\t\t\tbegin++;\n\n\t\tif (begin == end)\n\t\t\treturn begin;\n\n\t\t// last written element\n\t\tI write = begin++;\n\n\t\t// merge unique elements\n\t\twhile (begin != end)\n\t\t{\n\t\t\tif (*begin != *write)\n\t\t\t\t*++write = *begin++;\n\t\t\telse\n\t\t\t\tbegin++;\n\t\t}\n\n\t\t// past-the-end (write points to live element)\n\t\treturn write + 1;\n\t}\n\n\ttemplate <typename T, typename Pred> PUGI_IMPL_FN void insertion_sort(T* begin, T* end, const Pred& pred)\n\t{\n\t\tif (begin == end)\n\t\t\treturn;\n\n\t\tfor (T* it = begin + 1; it != end; ++it)\n\t\t{\n\t\t\tT val = *it;\n\t\t\tT* hole = it;\n\n\t\t\t// move hole backwards\n\t\t\twhile (hole > begin && pred(val, *(hole - 1)))\n\t\t\t{\n\t\t\t\t*hole = *(hole - 1);\n\t\t\t\thole--;\n\t\t\t}\n\n\t\t\t// fill hole with element\n\t\t\t*hole = val;\n\t\t}\n\t}\n\n\ttemplate <typename I, typename Pred> inline I median3(I first, I middle, I last, const Pred& pred)\n\t{\n\t\tif (pred(*middle, *first))\n\t\t\tswap(middle, first);\n\t\tif (pred(*last, *middle))\n\t\t\tswap(last, middle);\n\t\tif (pred(*middle, *first))\n\t\t\tswap(middle, first);\n\n\t\treturn middle;\n\t}\n\n\ttemplate <typename T, typename Pred> PUGI_IMPL_FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)\n\t{\n\t\t// invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups)\n\t\tT* eq = begin;\n\t\tT* lt = begin;\n\t\tT* gt = end;\n\n\t\twhile (lt < gt)\n\t\t{\n\t\t\tif (pred(*lt, pivot))\n\t\t\t\tlt++;\n\t\t\telse if (*lt == pivot)\n\t\t\t\tswap(*eq++, *lt++);\n\t\t\telse\n\t\t\t\tswap(*lt, *--gt);\n\t\t}\n\n\t\t// we now have just 4 groups: = < >; move equal elements to the middle\n\t\tT* eqbeg = gt;\n\n\t\tfor (T* it = begin; it != eq; ++it)\n\t\t\tswap(*it, *--eqbeg);\n\n\t\t*out_eqbeg = eqbeg;\n\t\t*out_eqend = gt;\n\t}\n\n\ttemplate <typename I, typename Pred> PUGI_IMPL_FN void sort(I begin, I end, const Pred& pred)\n\t{\n\t\t// sort large chunks\n\t\twhile (end - begin > 16)\n\t\t{\n\t\t\t// find median element\n\t\t\tI middle = begin + (end - begin) / 2;\n\t\t\tI median = median3(begin, middle, end - 1, pred);\n\n\t\t\t// partition in three chunks (< = >)\n\t\t\tI eqbeg, eqend;\n\t\t\tpartition3(begin, end, *median, pred, &eqbeg, &eqend);\n\n\t\t\t// loop on larger half\n\t\t\tif (eqbeg - begin > end - eqend)\n\t\t\t{\n\t\t\t\tsort(eqend, end, pred);\n\t\t\t\tend = eqbeg;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsort(begin, eqbeg, pred);\n\t\t\t\tbegin = eqend;\n\t\t\t}\n\t\t}\n\n\t\t// insertion sort small chunk\n\t\tinsertion_sort(begin, end, pred);\n\t}\n\n\tPUGI_IMPL_FN bool hash_insert(const void** table, size_t size, const void* key)\n\t{\n\t\tassert(key);\n\n\t\tunsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));\n\n\t\t// MurmurHash3 32-bit finalizer\n\t\th ^= h >> 16;\n\t\th *= 0x85ebca6bu;\n\t\th ^= h >> 13;\n\t\th *= 0xc2b2ae35u;\n\t\th ^= h >> 16;\n\n\t\tsize_t hashmod = size - 1;\n\t\tsize_t bucket = h & hashmod;\n\n\t\tfor (size_t probe = 0; probe <= hashmod; ++probe)\n\t\t{\n\t\t\tif (table[bucket] == NULL)\n\t\t\t{\n\t\t\t\ttable[bucket] = key;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (table[bucket] == key)\n\t\t\t\treturn false;\n\n\t\t\t// hash collision, quadratic probing\n\t\t\tbucket = (bucket + probe + 1) & hashmod;\n\t\t}\n\n\t\tassert(false && \"Hash table is full\"); // unreachable\n\t\treturn false;\n\t}\nPUGI_IMPL_NS_END\n\n// Allocator used for AST and evaluation stacks\nPUGI_IMPL_NS_BEGIN\n\tstatic const size_t xpath_memory_page_size =\n\t#ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE\n\t\tPUGIXML_MEMORY_XPATH_PAGE_SIZE\n\t#else\n\t\t4096\n\t#endif\n\t\t;\n\n\tstatic const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);\n\n\tstruct xpath_memory_block\n\t{\n\t\txpath_memory_block* next;\n\t\tsize_t capacity;\n\n\t\tunion\n\t\t{\n\t\t\tchar data[xpath_memory_page_size];\n\t\t\tdouble alignment;\n\t\t};\n\t};\n\n\tstruct xpath_allocator\n\t{\n\t\txpath_memory_block* _root;\n\t\tsize_t _root_size;\n\t\tbool* _error;\n\n\t\txpath_allocator(xpath_memory_block* root, bool* error = NULL): _root(root), _root_size(0), _error(error)\n\t\t{\n\t\t}\n\n\t\tvoid* allocate(size_t size)\n\t\t{\n\t\t\t// round size up to block alignment boundary\n\t\t\tsize = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);\n\n\t\t\tif (_root_size + size <= _root->capacity)\n\t\t\t{\n\t\t\t\tvoid* buf = &_root->data[0] + _root_size;\n\t\t\t\t_root_size += size;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests\n\t\t\t\tsize_t block_capacity_base = sizeof(_root->data);\n\t\t\t\tsize_t block_capacity_req = size + block_capacity_base / 4;\n\t\t\t\tsize_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;\n\n\t\t\t\tsize_t block_size = block_capacity + offsetof(xpath_memory_block, data);\n\n\t\t\t\txpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));\n\t\t\t\tif (!block)\n\t\t\t\t{\n\t\t\t\t\tif (_error) *_error = true;\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\n\t\t\t\tblock->next = _root;\n\t\t\t\tblock->capacity = block_capacity;\n\n\t\t\t\t_root = block;\n\t\t\t\t_root_size = size;\n\n\t\t\t\treturn block->data;\n\t\t\t}\n\t\t}\n\n\t\tvoid* reallocate(void* ptr, size_t old_size, size_t new_size)\n\t\t{\n\t\t\t// round size up to block alignment boundary\n\t\t\told_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);\n\t\t\tnew_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);\n\n\t\t\t// we can only reallocate the last object\n\t\t\tassert(ptr == NULL || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);\n\n\t\t\t// try to reallocate the object inplace\n\t\t\tif (ptr && _root_size - old_size + new_size <= _root->capacity)\n\t\t\t{\n\t\t\t\t_root_size = _root_size - old_size + new_size;\n\t\t\t\treturn ptr;\n\t\t\t}\n\n\t\t\t// allocate a new block\n\t\t\tvoid* result = allocate(new_size);\n\t\t\tif (!result) return NULL;\n\n\t\t\t// we have a new block\n\t\t\tif (ptr)\n\t\t\t{\n\t\t\t\t// copy old data (we only support growing)\n\t\t\t\tassert(new_size >= old_size);\n\t\t\t\tmemcpy(result, ptr, old_size);\n\n\t\t\t\t// free the previous page if it had no other objects\n\t\t\t\tassert(_root->data == result);\n\t\t\t\tassert(_root->next);\n\n\t\t\t\tif (_root->next->data == ptr)\n\t\t\t\t{\n\t\t\t\t\t// deallocate the whole page, unless it was the first one\n\t\t\t\t\txpath_memory_block* next = _root->next->next;\n\n\t\t\t\t\tif (next)\n\t\t\t\t\t{\n\t\t\t\t\t\txml_memory::deallocate(_root->next);\n\t\t\t\t\t\t_root->next = next;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tvoid revert(const xpath_allocator& state)\n\t\t{\n\t\t\t// free all new pages\n\t\t\txpath_memory_block* cur = _root;\n\n\t\t\twhile (cur != state._root)\n\t\t\t{\n\t\t\t\txpath_memory_block* next = cur->next;\n\n\t\t\t\txml_memory::deallocate(cur);\n\n\t\t\t\tcur = next;\n\t\t\t}\n\n\t\t\t// restore state\n\t\t\t_root = state._root;\n\t\t\t_root_size = state._root_size;\n\t\t}\n\n\t\tvoid release()\n\t\t{\n\t\t\txpath_memory_block* cur = _root;\n\t\t\tassert(cur);\n\n\t\t\twhile (cur->next)\n\t\t\t{\n\t\t\t\txpath_memory_block* next = cur->next;\n\n\t\t\t\txml_memory::deallocate(cur);\n\n\t\t\t\tcur = next;\n\t\t\t}\n\t\t}\n\t};\n\n\tstruct xpath_allocator_capture\n\t{\n\t\txpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)\n\t\t{\n\t\t}\n\n\t\t~xpath_allocator_capture()\n\t\t{\n\t\t\t_target->revert(_state);\n\t\t}\n\n\t\txpath_allocator* _target;\n\t\txpath_allocator _state;\n\t};\n\n\tstruct xpath_stack\n\t{\n\t\txpath_allocator* result;\n\t\txpath_allocator* temp;\n\t};\n\n\tstruct xpath_stack_data\n\t{\n\t\txpath_memory_block blocks[2];\n\t\txpath_allocator result;\n\t\txpath_allocator temp;\n\t\txpath_stack stack;\n\t\tbool oom;\n\n\t\txpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false)\n\t\t{\n\t\t\tblocks[0].next = blocks[1].next = NULL;\n\t\t\tblocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);\n\n\t\t\tstack.result = &result;\n\t\t\tstack.temp = &temp;\n\t\t}\n\n\t\t~xpath_stack_data()\n\t\t{\n\t\t\tresult.release();\n\t\t\ttemp.release();\n\t\t}\n\t};\nPUGI_IMPL_NS_END\n\n// String class\nPUGI_IMPL_NS_BEGIN\n\tclass xpath_string\n\t{\n\t\tconst char_t* _buffer;\n\t\tbool _uses_heap;\n\t\tsize_t _length_heap;\n\n\t\tstatic char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)\n\t\t{\n\t\t\tchar_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!result) return NULL;\n\n\t\t\tmemcpy(result, string, length * sizeof(char_t));\n\t\t\tresult[length] = 0;\n\n\t\t\treturn result;\n\t\t}\n\n\t\txpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)\n\t\t{\n\t\t}\n\n\tpublic:\n\t\tstatic xpath_string from_const(const char_t* str)\n\t\t{\n\t\t\treturn xpath_string(str, false, 0);\n\t\t}\n\n\t\tstatic xpath_string from_heap_preallocated(const char_t* begin, const char_t* end)\n\t\t{\n\t\t\tassert(begin <= end && *end == 0);\n\n\t\t\treturn xpath_string(begin, true, static_cast<size_t>(end - begin));\n\t\t}\n\n\t\tstatic xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc)\n\t\t{\n\t\t\tassert(begin <= end);\n\n\t\t\tif (begin == end)\n\t\t\t\treturn xpath_string();\n\n\t\t\tsize_t length = static_cast<size_t>(end - begin);\n\t\t\tconst char_t* data = duplicate_string(begin, length, alloc);\n\n\t\t\treturn data ? xpath_string(data, true, length) : xpath_string();\n\t\t}\n\n\t\txpath_string(): _buffer(PUGIXML_TEXT(\"\")), _uses_heap(false), _length_heap(0)\n\t\t{\n\t\t}\n\n\t\tvoid append(const xpath_string& o, xpath_allocator* alloc)\n\t\t{\n\t\t\t// skip empty sources\n\t\t\tif (!*o._buffer) return;\n\n\t\t\t// fast append for constant empty target and constant source\n\t\t\tif (!*_buffer && !_uses_heap && !o._uses_heap)\n\t\t\t{\n\t\t\t\t_buffer = o._buffer;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// need to make heap copy\n\t\t\t\tsize_t target_length = length();\n\t\t\t\tsize_t source_length = o.length();\n\t\t\t\tsize_t result_length = target_length + source_length;\n\n\t\t\t\t// allocate new buffer\n\t\t\t\tchar_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : NULL, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));\n\t\t\t\tif (!result) return;\n\n\t\t\t\t// append first string to the new buffer in case there was no reallocation\n\t\t\t\tif (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));\n\n\t\t\t\t// append second string to the new buffer\n\t\t\t\tmemcpy(result + target_length, o._buffer, source_length * sizeof(char_t));\n\t\t\t\tresult[result_length] = 0;\n\n\t\t\t\t// finalize\n\t\t\t\t_buffer = result;\n\t\t\t\t_uses_heap = true;\n\t\t\t\t_length_heap = result_length;\n\t\t\t}\n\t\t}\n\n\t\tconst char_t* c_str() const\n\t\t{\n\t\t\treturn _buffer;\n\t\t}\n\n\t\tsize_t length() const\n\t\t{\n\t\t\treturn _uses_heap ? _length_heap : strlength(_buffer);\n\t\t}\n\n\t\tchar_t* data(xpath_allocator* alloc)\n\t\t{\n\t\t\t// make private heap copy\n\t\t\tif (!_uses_heap)\n\t\t\t{\n\t\t\t\tsize_t length_ = strlength(_buffer);\n\t\t\t\tconst char_t* data_ = duplicate_string(_buffer, length_, alloc);\n\n\t\t\t\tif (!data_) return NULL;\n\n\t\t\t\t_buffer = data_;\n\t\t\t\t_uses_heap = true;\n\t\t\t\t_length_heap = length_;\n\t\t\t}\n\n\t\t\treturn const_cast<char_t*>(_buffer);\n\t\t}\n\n\t\tbool empty() const\n\t\t{\n\t\t\treturn *_buffer == 0;\n\t\t}\n\n\t\tbool operator==(const xpath_string& o) const\n\t\t{\n\t\t\treturn strequal(_buffer, o._buffer);\n\t\t}\n\n\t\tbool operator!=(const xpath_string& o) const\n\t\t{\n\t\t\treturn !strequal(_buffer, o._buffer);\n\t\t}\n\n\t\tbool uses_heap() const\n\t\t{\n\t\t\treturn _uses_heap;\n\t\t}\n\t};\nPUGI_IMPL_NS_END\n\nPUGI_IMPL_NS_BEGIN\n\tPUGI_IMPL_FN bool starts_with(const char_t* string, const char_t* pattern)\n\t{\n\t\twhile (*pattern && *string == *pattern)\n\t\t{\n\t\t\tstring++;\n\t\t\tpattern++;\n\t\t}\n\n\t\treturn *pattern == 0;\n\t}\n\n\tPUGI_IMPL_FN const char_t* find_char(const char_t* s, char_t c)\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcschr(s, c);\n\t#else\n\t\treturn strchr(s, c);\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN const char_t* find_substring(const char_t* s, const char_t* p)\n\t{\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\t// MSVC6 wcsstr bug workaround (if s is empty it always returns 0)\n\t\treturn (*p == 0) ? s : wcsstr(s, p);\n\t#else\n\t\treturn strstr(s, p);\n\t#endif\n\t}\n\n\t// Converts symbol to lower case, if it is an ASCII one\n\tPUGI_IMPL_FN char_t tolower_ascii(char_t ch)\n\t{\n\t\treturn static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;\n\t}\n\n\tPUGI_IMPL_FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)\n\t{\n\t\tif (na.attribute())\n\t\t\treturn xpath_string::from_const(na.attribute().value());\n\t\telse\n\t\t{\n\t\t\txml_node n = na.node();\n\n\t\t\tswitch (n.type())\n\t\t\t{\n\t\t\tcase node_pcdata:\n\t\t\tcase node_cdata:\n\t\t\tcase node_comment:\n\t\t\tcase node_pi:\n\t\t\t\treturn xpath_string::from_const(n.value());\n\n\t\t\tcase node_document:\n\t\t\tcase node_element:\n\t\t\t{\n\t\t\t\txpath_string result;\n\n\t\t\t\t// element nodes can have value if parse_embed_pcdata was used\n\t\t\t\tif (n.value()[0])\n\t\t\t\t\tresult.append(xpath_string::from_const(n.value()), alloc);\n\n\t\t\t\txml_node cur = n.first_child();\n\n\t\t\t\twhile (cur && cur != n)\n\t\t\t\t{\n\t\t\t\t\tif (cur.type() == node_pcdata || cur.type() == node_cdata)\n\t\t\t\t\t\tresult.append(xpath_string::from_const(cur.value()), alloc);\n\n\t\t\t\t\tif (cur.first_child())\n\t\t\t\t\t\tcur = cur.first_child();\n\t\t\t\t\telse if (cur.next_sibling())\n\t\t\t\t\t\tcur = cur.next_sibling();\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (!cur.next_sibling() && cur != n)\n\t\t\t\t\t\t\tcur = cur.parent();\n\n\t\t\t\t\t\tif (cur != n) cur = cur.next_sibling();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn xpath_string();\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)\n\t{\n\t\tassert(ln->parent == rn->parent);\n\n\t\t// there is no common ancestor (the shared parent is null), nodes are from different documents\n\t\tif (!ln->parent) return ln < rn;\n\n\t\t// determine sibling order\n\t\txml_node_struct* ls = ln;\n\t\txml_node_struct* rs = rn;\n\n\t\twhile (ls && rs)\n\t\t{\n\t\t\tif (ls == rn) return true;\n\t\t\tif (rs == ln) return false;\n\n\t\t\tls = ls->next_sibling;\n\t\t\trs = rs->next_sibling;\n\t\t}\n\n\t\t// if rn sibling chain ended ln must be before rn\n\t\treturn !rs;\n\t}\n\n\tPUGI_IMPL_FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)\n\t{\n\t\t// find common ancestor at the same depth, if any\n\t\txml_node_struct* lp = ln;\n\t\txml_node_struct* rp = rn;\n\n\t\twhile (lp && rp && lp->parent != rp->parent)\n\t\t{\n\t\t\tlp = lp->parent;\n\t\t\trp = rp->parent;\n\t\t}\n\n\t\t// parents are the same!\n\t\tif (lp && rp) return node_is_before_sibling(lp, rp);\n\n\t\t// nodes are at different depths, need to normalize heights\n\t\tbool left_higher = !lp;\n\n\t\twhile (lp)\n\t\t{\n\t\t\tlp = lp->parent;\n\t\t\tln = ln->parent;\n\t\t}\n\n\t\twhile (rp)\n\t\t{\n\t\t\trp = rp->parent;\n\t\t\trn = rn->parent;\n\t\t}\n\n\t\t// one node is the ancestor of the other\n\t\tif (ln == rn) return left_higher;\n\n\t\t// find common ancestor... again\n\t\twhile (ln->parent != rn->parent)\n\t\t{\n\t\t\tln = ln->parent;\n\t\t\trn = rn->parent;\n\t\t}\n\n\t\treturn node_is_before_sibling(ln, rn);\n\t}\n\n\tPUGI_IMPL_FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)\n\t{\n\t\twhile (node && node != parent) node = node->parent;\n\n\t\treturn parent && node == parent;\n\t}\n\n\tPUGI_IMPL_FN const void* document_buffer_order(const xpath_node& xnode)\n\t{\n\t\txml_node_struct* node = xnode.node().internal_object();\n\n\t\tif (node)\n\t\t{\n\t\t\tif ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)\n\t\t\t{\n\t\t\t\tif (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name;\n\t\t\t\tif (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value;\n\t\t\t}\n\n\t\t\treturn NULL;\n\t\t}\n\n\t\txml_attribute_struct* attr = xnode.attribute().internal_object();\n\n\t\tif (attr)\n\t\t{\n\t\t\tif ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)\n\t\t\t{\n\t\t\t\tif ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name;\n\t\t\t\tif ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value;\n\t\t\t}\n\n\t\t\treturn NULL;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tstruct document_order_comparator\n\t{\n\t\tbool operator()(const xpath_node& lhs, const xpath_node& rhs) const\n\t\t{\n\t\t\t// optimized document order based check\n\t\t\tconst void* lo = document_buffer_order(lhs);\n\t\t\tconst void* ro = document_buffer_order(rhs);\n\n\t\t\tif (lo && ro) return lo < ro;\n\n\t\t\t// slow comparison\n\t\t\txml_node ln = lhs.node(), rn = rhs.node();\n\n\t\t\t// compare attributes\n\t\t\tif (lhs.attribute() && rhs.attribute())\n\t\t\t{\n\t\t\t\t// shared parent\n\t\t\t\tif (lhs.parent() == rhs.parent())\n\t\t\t\t{\n\t\t\t\t\t// determine sibling order\n\t\t\t\t\tfor (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())\n\t\t\t\t\t\tif (a == rhs.attribute())\n\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// compare attribute parents\n\t\t\t\tln = lhs.parent();\n\t\t\t\trn = rhs.parent();\n\t\t\t}\n\t\t\telse if (lhs.attribute())\n\t\t\t{\n\t\t\t\t// attributes go after the parent element\n\t\t\t\tif (lhs.parent() == rhs.node()) return false;\n\n\t\t\t\tln = lhs.parent();\n\t\t\t}\n\t\t\telse if (rhs.attribute())\n\t\t\t{\n\t\t\t\t// attributes go after the parent element\n\t\t\t\tif (rhs.parent() == lhs.node()) return true;\n\n\t\t\t\trn = rhs.parent();\n\t\t\t}\n\n\t\t\tif (ln == rn) return false;\n\n\t\t\tif (!ln || !rn) return ln < rn;\n\n\t\t\treturn node_is_before(ln.internal_object(), rn.internal_object());\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN double gen_nan()\n\t{\n\t#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))\n\t\tPUGI_IMPL_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));\n\t\ttypedef uint32_t UI; // BCC5 workaround\n\t\tunion { float f; UI i; } u;\n\t\tu.i = 0x7fc00000;\n\t\treturn double(u.f);\n\t#else\n\t\t// fallback\n\t\tconst volatile double zero = 0.0;\n\t\treturn zero / zero;\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN bool is_nan(double value)\n\t{\n\t#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__)\n\t\treturn !!_isnan(value);\n\t#elif defined(fpclassify) && defined(FP_NAN)\n\t\treturn fpclassify(value) == FP_NAN;\n\t#else\n\t\t// fallback\n\t\tconst volatile double v = value;\n\t\treturn v != v;\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN const char_t* convert_number_to_string_special(double value)\n\t{\n\t#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__)\n\t\tif (_finite(value)) return (value == 0) ? PUGIXML_TEXT(\"0\") : 0;\n\t\tif (_isnan(value)) return PUGIXML_TEXT(\"NaN\");\n\t\treturn value > 0 ? PUGIXML_TEXT(\"Infinity\") : PUGIXML_TEXT(\"-Infinity\");\n\t#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)\n\t\tswitch (fpclassify(value))\n\t\t{\n\t\tcase FP_NAN:\n\t\t\treturn PUGIXML_TEXT(\"NaN\");\n\n\t\tcase FP_INFINITE:\n\t\t\treturn value > 0 ? PUGIXML_TEXT(\"Infinity\") : PUGIXML_TEXT(\"-Infinity\");\n\n\t\tcase FP_ZERO:\n\t\t\treturn PUGIXML_TEXT(\"0\");\n\n\t\tdefault:\n\t\t\treturn 0;\n\t\t}\n\t#else\n\t\t// fallback\n\t\tconst volatile double v = value;\n\n\t\tif (v == 0) return PUGIXML_TEXT(\"0\");\n\t\tif (v != v) return PUGIXML_TEXT(\"NaN\");\n\t\tif (v * 2 == v) return value > 0 ? PUGIXML_TEXT(\"Infinity\") : PUGIXML_TEXT(\"-Infinity\");\n\t\treturn NULL;\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN bool convert_number_to_boolean(double value)\n\t{\n\t\treturn (value != 0 && !is_nan(value));\n\t}\n\n\tPUGI_IMPL_FN void truncate_zeros(char* begin, char* end)\n\t{\n\t\twhile (begin != end && end[-1] == '0') end--;\n\n\t\t*end = 0;\n\t}\n\n\t// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent\n#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400\n\tPUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)\n\t{\n\t\t// get base values\n\t\tint sign, exponent;\n\t\t_ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign);\n\n\t\t// truncate redundant zeros\n\t\ttruncate_zeros(buffer, buffer + strlen(buffer));\n\n\t\t// fill results\n\t\t*out_mantissa = buffer;\n\t\t*out_exponent = exponent;\n\t}\n#else\n\tPUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)\n\t{\n\t\t// get a scientific notation value with IEEE DBL_DIG decimals\n\t\tPUGI_IMPL_SNPRINTF(buffer, \"%.*e\", DBL_DIG, value);\n\n\t\t// get the exponent (possibly negative)\n\t\tchar* exponent_string = strchr(buffer, 'e');\n\t\tassert(exponent_string);\n\n\t\tint exponent = atoi(exponent_string + 1);\n\n\t\t// extract mantissa string: skip sign\n\t\tchar* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;\n\t\tassert(mantissa[0] != '0' && (mantissa[1] == '.' || mantissa[1] == ','));\n\n\t\t// divide mantissa by 10 to eliminate integer part\n\t\tmantissa[1] = mantissa[0];\n\t\tmantissa++;\n\t\texponent++;\n\n\t\t// remove extra mantissa digits and zero-terminate mantissa\n\t\ttruncate_zeros(mantissa, exponent_string);\n\n\t\t// fill results\n\t\t*out_mantissa = mantissa;\n\t\t*out_exponent = exponent;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)\n\t{\n\t\t// try special number conversion\n\t\tconst char_t* special = convert_number_to_string_special(value);\n\t\tif (special) return xpath_string::from_const(special);\n\n\t\t// get mantissa + exponent form\n\t\tchar mantissa_buffer[32];\n\n\t\tchar* mantissa;\n\t\tint exponent;\n\t\tconvert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent);\n\n\t\t// allocate a buffer of suitable length for the number\n\t\tsize_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;\n\t\tchar_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));\n\t\tif (!result) return xpath_string();\n\n\t\t// make the number!\n\t\tchar_t* s = result;\n\n\t\t// sign\n\t\tif (value < 0) *s++ = '-';\n\n\t\t// integer part\n\t\tif (exponent <= 0)\n\t\t{\n\t\t\t*s++ = '0';\n\t\t}\n\t\telse\n\t\t{\n\t\t\twhile (exponent > 0)\n\t\t\t{\n\t\t\t\tassert(*mantissa == 0 || static_cast<unsigned int>(*mantissa - '0') <= 9);\n\t\t\t\t*s++ = *mantissa ? *mantissa++ : '0';\n\t\t\t\texponent--;\n\t\t\t}\n\t\t}\n\n\t\t// fractional part\n\t\tif (*mantissa)\n\t\t{\n\t\t\t// decimal point\n\t\t\t*s++ = '.';\n\n\t\t\t// extra zeroes from negative exponent\n\t\t\twhile (exponent < 0)\n\t\t\t{\n\t\t\t\t*s++ = '0';\n\t\t\t\texponent++;\n\t\t\t}\n\n\t\t\t// extra mantissa digits\n\t\t\twhile (*mantissa)\n\t\t\t{\n\t\t\t\tassert(static_cast<unsigned int>(*mantissa - '0') <= 9);\n\t\t\t\t*s++ = *mantissa++;\n\t\t\t}\n\t\t}\n\n\t\t// zero-terminate\n\t\tassert(s < result + result_size);\n\t\t*s = 0;\n\n\t\treturn xpath_string::from_heap_preallocated(result, s);\n\t}\n\n\tPUGI_IMPL_FN bool check_string_to_number_format(const char_t* string)\n\t{\n\t\t// parse leading whitespace\n\t\twhile (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string;\n\n\t\t// parse sign\n\t\tif (*string == '-') ++string;\n\n\t\tif (!*string) return false;\n\n\t\t// if there is no integer part, there should be a decimal part with at least one digit\n\t\tif (!PUGI_IMPL_IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI_IMPL_IS_CHARTYPEX(string[1], ctx_digit))) return false;\n\n\t\t// parse integer part\n\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string;\n\n\t\t// parse decimal part\n\t\tif (*string == '.')\n\t\t{\n\t\t\t++string;\n\n\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string;\n\t\t}\n\n\t\t// parse trailing whitespace\n\t\twhile (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string;\n\n\t\treturn *string == 0;\n\t}\n\n\tPUGI_IMPL_FN double convert_string_to_number(const char_t* string)\n\t{\n\t\t// check string format\n\t\tif (!check_string_to_number_format(string)) return gen_nan();\n\n\t\t// parse string\n\t#ifdef PUGIXML_WCHAR_MODE\n\t\treturn wcstod(string, NULL);\n\t#else\n\t\treturn strtod(string, NULL);\n\t#endif\n\t}\n\n\tPUGI_IMPL_FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)\n\t{\n\t\tsize_t length = static_cast<size_t>(end - begin);\n\t\tchar_t* scratch = buffer;\n\n\t\tif (length >= sizeof(buffer) / sizeof(buffer[0]))\n\t\t{\n\t\t\t// need to make dummy on-heap copy\n\t\t\tscratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!scratch) return false;\n\t\t}\n\n\t\t// copy string to zero-terminated buffer and perform conversion\n\t\tmemcpy(scratch, begin, length * sizeof(char_t));\n\t\tscratch[length] = 0;\n\n\t\t*out_result = convert_string_to_number(scratch);\n\n\t\t// free dummy buffer\n\t\tif (scratch != buffer) xml_memory::deallocate(scratch);\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN double round_nearest(double value)\n\t{\n\t\treturn floor(value + 0.5);\n\t}\n\n\tPUGI_IMPL_FN double round_nearest_nzero(double value)\n\t{\n\t\t// same as round_nearest, but returns -0 for [-0.5, -0]\n\t\t// ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)\n\t\treturn (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);\n\t}\n\n\tPUGI_IMPL_FN const char_t* qualified_name(const xpath_node& node)\n\t{\n\t\treturn node.attribute() ? node.attribute().name() : node.node().name();\n\t}\n\n\tPUGI_IMPL_FN const char_t* local_name(const xpath_node& node)\n\t{\n\t\tconst char_t* name = qualified_name(node);\n\t\tconst char_t* p = find_char(name, ':');\n\n\t\treturn p ? p + 1 : name;\n\t}\n\n\tstruct namespace_uri_predicate\n\t{\n\t\tconst char_t* prefix;\n\t\tsize_t prefix_length;\n\n\t\tnamespace_uri_predicate(const char_t* name)\n\t\t{\n\t\t\tconst char_t* pos = find_char(name, ':');\n\n\t\t\tprefix = pos ? name : NULL;\n\t\t\tprefix_length = pos ? static_cast<size_t>(pos - name) : 0;\n\t\t}\n\n\t\tbool operator()(xml_attribute a) const\n\t\t{\n\t\t\tconst char_t* name = a.name();\n\n\t\t\tif (!starts_with(name, PUGIXML_TEXT(\"xmlns\"))) return false;\n\n\t\t\treturn prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN const char_t* namespace_uri(xml_node node)\n\t{\n\t\tnamespace_uri_predicate pred = node.name();\n\n\t\txml_node p = node;\n\n\t\twhile (p)\n\t\t{\n\t\t\txml_attribute a = p.find_attribute(pred);\n\n\t\t\tif (a) return a.value();\n\n\t\t\tp = p.parent();\n\t\t}\n\n\t\treturn PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)\n\t{\n\t\tnamespace_uri_predicate pred = attr.name();\n\n\t\t// Default namespace does not apply to attributes\n\t\tif (!pred.prefix) return PUGIXML_TEXT(\"\");\n\n\t\txml_node p = parent;\n\n\t\twhile (p)\n\t\t{\n\t\t\txml_attribute a = p.find_attribute(pred);\n\n\t\t\tif (a) return a.value();\n\n\t\t\tp = p.parent();\n\t\t}\n\n\t\treturn PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const char_t* namespace_uri(const xpath_node& node)\n\t{\n\t\treturn node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());\n\t}\n\n\tPUGI_IMPL_FN char_t* normalize_space(char_t* buffer)\n\t{\n\t\tchar_t* write = buffer;\n\n\t\tfor (char_t* it = buffer; *it; )\n\t\t{\n\t\t\tchar_t ch = *it++;\n\n\t\t\tif (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))\n\t\t\t{\n\t\t\t\t// replace whitespace sequence with single space\n\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*it, ct_space)) it++;\n\n\t\t\t\t// avoid leading spaces\n\t\t\t\tif (write != buffer) *write++ = ' ';\n\t\t\t}\n\t\t\telse *write++ = ch;\n\t\t}\n\n\t\t// remove trailing space\n\t\tif (write != buffer && PUGI_IMPL_IS_CHARTYPE(write[-1], ct_space)) write--;\n\n\t\t// zero-terminate\n\t\t*write = 0;\n\n\t\treturn write;\n\t}\n\n\tPUGI_IMPL_FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)\n\t{\n\t\tchar_t* write = buffer;\n\n\t\twhile (*buffer)\n\t\t{\n\t\t\tPUGI_IMPL_DMC_VOLATILE char_t ch = *buffer++;\n\n\t\t\tconst char_t* pos = find_char(from, ch);\n\n\t\t\tif (!pos)\n\t\t\t\t*write++ = ch; // do not process\n\t\t\telse if (static_cast<size_t>(pos - from) < to_length)\n\t\t\t\t*write++ = to[pos - from]; // replace\n\t\t}\n\n\t\t// zero-terminate\n\t\t*write = 0;\n\n\t\treturn write;\n\t}\n\n\tPUGI_IMPL_FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)\n\t{\n\t\tunsigned char table[128] = {0};\n\n\t\twhile (*from)\n\t\t{\n\t\t\tunsigned int fc = static_cast<unsigned int>(*from);\n\t\t\tunsigned int tc = static_cast<unsigned int>(*to);\n\n\t\t\tif (fc >= 128 || tc >= 128)\n\t\t\t\treturn NULL;\n\n\t\t\t// code=128 means \"skip character\"\n\t\t\tif (!table[fc])\n\t\t\t\ttable[fc] = static_cast<unsigned char>(tc ? tc : 128);\n\n\t\t\tfrom++;\n\t\t\tif (tc) to++;\n\t\t}\n\n\t\tfor (int i = 0; i < 128; ++i)\n\t\t\tif (!table[i])\n\t\t\t\ttable[i] = static_cast<unsigned char>(i);\n\n\t\tvoid* result = alloc->allocate(sizeof(table));\n\t\tif (!result) return NULL;\n\n\t\tmemcpy(result, table, sizeof(table));\n\n\t\treturn static_cast<unsigned char*>(result);\n\t}\n\n\tPUGI_IMPL_FN char_t* translate_table(char_t* buffer, const unsigned char* table)\n\t{\n\t\tchar_t* write = buffer;\n\n\t\twhile (*buffer)\n\t\t{\n\t\t\tchar_t ch = *buffer++;\n\t\t\tunsigned int index = static_cast<unsigned int>(ch);\n\n\t\t\tif (index < 128)\n\t\t\t{\n\t\t\t\tunsigned char code = table[index];\n\n\t\t\t\t// code=128 means \"skip character\" (table size is 128 so 128 can be a special value)\n\t\t\t\t// this code skips these characters without extra branches\n\t\t\t\t*write = static_cast<char_t>(code);\n\t\t\t\twrite += 1 - (code >> 7);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*write++ = ch;\n\t\t\t}\n\t\t}\n\n\t\t// zero-terminate\n\t\t*write = 0;\n\n\t\treturn write;\n\t}\n\n\tinline bool is_xpath_attribute(const char_t* name)\n\t{\n\t\treturn !(starts_with(name, PUGIXML_TEXT(\"xmlns\")) && (name[5] == 0 || name[5] == ':'));\n\t}\n\n\tstruct xpath_variable_boolean: xpath_variable\n\t{\n\t\txpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)\n\t\t{\n\t\t}\n\n\t\tbool value;\n\t\tchar_t name[1];\n\t};\n\n\tstruct xpath_variable_number: xpath_variable\n\t{\n\t\txpath_variable_number(): xpath_variable(xpath_type_number), value(0)\n\t\t{\n\t\t}\n\n\t\tdouble value;\n\t\tchar_t name[1];\n\t};\n\n\tstruct xpath_variable_string: xpath_variable\n\t{\n\t\txpath_variable_string(): xpath_variable(xpath_type_string), value(NULL)\n\t\t{\n\t\t}\n\n\t\t~xpath_variable_string()\n\t\t{\n\t\t\tif (value) xml_memory::deallocate(value);\n\t\t}\n\n\t\tchar_t* value;\n\t\tchar_t name[1];\n\t};\n\n\tstruct xpath_variable_node_set: xpath_variable\n\t{\n\t\txpath_variable_node_set(): xpath_variable(xpath_type_node_set)\n\t\t{\n\t\t}\n\n\t\txpath_node_set value;\n\t\tchar_t name[1];\n\t};\n\n\tstatic const xpath_node_set dummy_node_set;\n\n\tPUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str)\n\t{\n\t\t// Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)\n\t\tunsigned int result = 0;\n\n\t\twhile (*str)\n\t\t{\n\t\t\tresult += static_cast<unsigned int>(*str++);\n\t\t\tresult += result << 10;\n\t\t\tresult ^= result >> 6;\n\t\t}\n\n\t\tresult += result << 3;\n\t\tresult ^= result >> 11;\n\t\tresult += result << 15;\n\n\t\treturn result;\n\t}\n\n\ttemplate <typename T> PUGI_IMPL_FN T* new_xpath_variable(const char_t* name)\n\t{\n\t\tsize_t length = strlength(name);\n\t\tif (length == 0) return NULL; // empty variable names are invalid\n\n\t\t// $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters\n\t\tvoid* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));\n\t\tif (!memory) return NULL;\n\n\t\tT* result = new (memory) T();\n\n\t\tmemcpy(result->name, name, (length + 1) * sizeof(char_t));\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)\n\t{\n\t\tswitch (type)\n\t\t{\n\t\tcase xpath_type_node_set:\n\t\t\treturn new_xpath_variable<xpath_variable_node_set>(name);\n\n\t\tcase xpath_type_number:\n\t\t\treturn new_xpath_variable<xpath_variable_number>(name);\n\n\t\tcase xpath_type_string:\n\t\t\treturn new_xpath_variable<xpath_variable_string>(name);\n\n\t\tcase xpath_type_boolean:\n\t\t\treturn new_xpath_variable<xpath_variable_boolean>(name);\n\n\t\tdefault:\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\ttemplate <typename T> PUGI_IMPL_FN void delete_xpath_variable(T* var)\n\t{\n\t\tvar->~T();\n\t\txml_memory::deallocate(var);\n\t}\n\n\tPUGI_IMPL_FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)\n\t{\n\t\tswitch (type)\n\t\t{\n\t\tcase xpath_type_node_set:\n\t\t\tdelete_xpath_variable(static_cast<xpath_variable_node_set*>(var));\n\t\t\tbreak;\n\n\t\tcase xpath_type_number:\n\t\t\tdelete_xpath_variable(static_cast<xpath_variable_number*>(var));\n\t\t\tbreak;\n\n\t\tcase xpath_type_string:\n\t\t\tdelete_xpath_variable(static_cast<xpath_variable_string*>(var));\n\t\t\tbreak;\n\n\t\tcase xpath_type_boolean:\n\t\t\tdelete_xpath_variable(static_cast<xpath_variable_boolean*>(var));\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tassert(false && \"Invalid variable type\"); // unreachable\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)\n\t{\n\t\tswitch (rhs->type())\n\t\t{\n\t\tcase xpath_type_node_set:\n\t\t\treturn lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);\n\n\t\tcase xpath_type_number:\n\t\t\treturn lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);\n\n\t\tcase xpath_type_string:\n\t\t\treturn lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);\n\n\t\tcase xpath_type_boolean:\n\t\t\treturn lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);\n\n\t\tdefault:\n\t\t\tassert(false && \"Invalid variable type\"); // unreachable\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result)\n\t{\n\t\tsize_t length = static_cast<size_t>(end - begin);\n\t\tchar_t* scratch = buffer;\n\n\t\tif (length >= sizeof(buffer) / sizeof(buffer[0]))\n\t\t{\n\t\t\t// need to make dummy on-heap copy\n\t\t\tscratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!scratch) return false;\n\t\t}\n\n\t\t// copy string to zero-terminated buffer and perform lookup\n\t\tmemcpy(scratch, begin, length * sizeof(char_t));\n\t\tscratch[length] = 0;\n\n\t\t*out_result = set->get(scratch);\n\n\t\t// free dummy buffer\n\t\tif (scratch != buffer) xml_memory::deallocate(scratch);\n\n\t\treturn true;\n\t}\nPUGI_IMPL_NS_END\n\n// Internal node set class\nPUGI_IMPL_NS_BEGIN\n\tPUGI_IMPL_FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)\n\t{\n\t\tif (end - begin < 2)\n\t\t\treturn xpath_node_set::type_sorted;\n\n\t\tdocument_order_comparator cmp;\n\n\t\tbool first = cmp(begin[0], begin[1]);\n\n\t\tfor (const xpath_node* it = begin + 1; it + 1 < end; ++it)\n\t\t\tif (cmp(it[0], it[1]) != first)\n\t\t\t\treturn xpath_node_set::type_unsorted;\n\n\t\treturn first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)\n\t{\n\t\txpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;\n\n\t\tif (type == xpath_node_set::type_unsorted)\n\t\t{\n\t\t\txpath_node_set::type_t sorted = xpath_get_order(begin, end);\n\n\t\t\tif (sorted == xpath_node_set::type_unsorted)\n\t\t\t{\n\t\t\t\tsort(begin, end, document_order_comparator());\n\n\t\t\t\ttype = xpath_node_set::type_sorted;\n\t\t\t}\n\t\t\telse\n\t\t\t\ttype = sorted;\n\t\t}\n\n\t\tif (type != order) reverse(begin, end);\n\n\t\treturn order;\n\t}\n\n\tPUGI_IMPL_FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)\n\t{\n\t\tif (begin == end) return xpath_node();\n\n\t\tswitch (type)\n\t\t{\n\t\tcase xpath_node_set::type_sorted:\n\t\t\treturn *begin;\n\n\t\tcase xpath_node_set::type_sorted_reverse:\n\t\t\treturn *(end - 1);\n\n\t\tcase xpath_node_set::type_unsorted:\n\t\t\treturn *min_element(begin, end, document_order_comparator());\n\n\t\tdefault:\n\t\t\tassert(false && \"Invalid node set type\"); // unreachable\n\t\t\treturn xpath_node();\n\t\t}\n\t}\n\n\tclass xpath_node_set_raw\n\t{\n\t\txpath_node_set::type_t _type;\n\n\t\txpath_node* _begin;\n\t\txpath_node* _end;\n\t\txpath_node* _eos;\n\n\tpublic:\n\t\txpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(NULL), _end(NULL), _eos(NULL)\n\t\t{\n\t\t}\n\n\t\txpath_node* begin() const\n\t\t{\n\t\t\treturn _begin;\n\t\t}\n\n\t\txpath_node* end() const\n\t\t{\n\t\t\treturn _end;\n\t\t}\n\n\t\tbool empty() const\n\t\t{\n\t\t\treturn _begin == _end;\n\t\t}\n\n\t\tsize_t size() const\n\t\t{\n\t\t\treturn static_cast<size_t>(_end - _begin);\n\t\t}\n\n\t\txpath_node first() const\n\t\t{\n\t\t\treturn xpath_first(_begin, _end, _type);\n\t\t}\n\n\t\tvoid push_back_grow(const xpath_node& node, xpath_allocator* alloc);\n\n\t\tvoid push_back(const xpath_node& node, xpath_allocator* alloc)\n\t\t{\n\t\t\tif (_end != _eos)\n\t\t\t\t*_end++ = node;\n\t\t\telse\n\t\t\t\tpush_back_grow(node, alloc);\n\t\t}\n\n\t\tvoid append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)\n\t\t{\n\t\t\tif (begin_ == end_) return;\n\n\t\t\tsize_t size_ = static_cast<size_t>(_end - _begin);\n\t\t\tsize_t capacity = static_cast<size_t>(_eos - _begin);\n\t\t\tsize_t count = static_cast<size_t>(end_ - begin_);\n\n\t\t\tif (size_ + count > capacity)\n\t\t\t{\n\t\t\t\t// reallocate the old array or allocate a new one\n\t\t\t\txpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));\n\t\t\t\tif (!data) return;\n\n\t\t\t\t// finalize\n\t\t\t\t_begin = data;\n\t\t\t\t_end = data + size_;\n\t\t\t\t_eos = data + size_ + count;\n\t\t\t}\n\n\t\t\tmemcpy(_end, begin_, count * sizeof(xpath_node));\n\t\t\t_end += count;\n\t\t}\n\n\t\tvoid sort_do()\n\t\t{\n\t\t\t_type = xpath_sort(_begin, _end, _type, false);\n\t\t}\n\n\t\tvoid truncate(xpath_node* pos)\n\t\t{\n\t\t\tassert(_begin <= pos && pos <= _end);\n\n\t\t\t_end = pos;\n\t\t}\n\n\t\tvoid remove_duplicates(xpath_allocator* alloc)\n\t\t{\n\t\t\tif (_type == xpath_node_set::type_unsorted && _end - _begin > 2)\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(alloc);\n\n\t\t\t\tsize_t size_ = static_cast<size_t>(_end - _begin);\n\n\t\t\t\tsize_t hash_size = 1;\n\t\t\t\twhile (hash_size < size_ + size_ / 2) hash_size *= 2;\n\n\t\t\t\tconst void** hash_data = static_cast<const void**>(alloc->allocate(hash_size * sizeof(void**)));\n\t\t\t\tif (!hash_data) return;\n\n\t\t\t\tmemset(hash_data, 0, hash_size * sizeof(const void**));\n\n\t\t\t\txpath_node* write = _begin;\n\n\t\t\t\tfor (xpath_node* it = _begin; it != _end; ++it)\n\t\t\t\t{\n\t\t\t\t\tconst void* attr = it->attribute().internal_object();\n\t\t\t\t\tconst void* node = it->node().internal_object();\n\t\t\t\t\tconst void* key = attr ? attr : node;\n\n\t\t\t\t\tif (key && hash_insert(hash_data, hash_size, key))\n\t\t\t\t\t{\n\t\t\t\t\t\t*write++ = *it;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t_end = write;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_end = unique(_begin, _end);\n\t\t\t}\n\t\t}\n\n\t\txpath_node_set::type_t type() const\n\t\t{\n\t\t\treturn _type;\n\t\t}\n\n\t\tvoid set_type(xpath_node_set::type_t value)\n\t\t{\n\t\t\t_type = value;\n\t\t}\n\t};\n\n\tPUGI_IMPL_FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc)\n\t{\n\t\tsize_t capacity = static_cast<size_t>(_eos - _begin);\n\n\t\t// get new capacity (1.5x rule)\n\t\tsize_t new_capacity = capacity + capacity / 2 + 1;\n\n\t\t// reallocate the old array or allocate a new one\n\t\txpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));\n\t\tif (!data) return;\n\n\t\t// finalize\n\t\t_begin = data;\n\t\t_end = data + capacity;\n\t\t_eos = data + new_capacity;\n\n\t\t// push\n\t\t*_end++ = node;\n\t}\nPUGI_IMPL_NS_END\n\nPUGI_IMPL_NS_BEGIN\n\tstruct xpath_context\n\t{\n\t\txpath_node n;\n\t\tsize_t position, size;\n\n\t\txpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)\n\t\t{\n\t\t}\n\t};\n\n\tenum lexeme_t\n\t{\n\t\tlex_none = 0,\n\t\tlex_equal,\n\t\tlex_not_equal,\n\t\tlex_less,\n\t\tlex_greater,\n\t\tlex_less_or_equal,\n\t\tlex_greater_or_equal,\n\t\tlex_plus,\n\t\tlex_minus,\n\t\tlex_multiply,\n\t\tlex_union,\n\t\tlex_var_ref,\n\t\tlex_open_brace,\n\t\tlex_close_brace,\n\t\tlex_quoted_string,\n\t\tlex_number,\n\t\tlex_slash,\n\t\tlex_double_slash,\n\t\tlex_open_square_brace,\n\t\tlex_close_square_brace,\n\t\tlex_string,\n\t\tlex_comma,\n\t\tlex_axis_attribute,\n\t\tlex_dot,\n\t\tlex_double_dot,\n\t\tlex_double_colon,\n\t\tlex_eof\n\t};\n\n\tstruct xpath_lexer_string\n\t{\n\t\tconst char_t* begin;\n\t\tconst char_t* end;\n\n\t\txpath_lexer_string(): begin(NULL), end(NULL)\n\t\t{\n\t\t}\n\n\t\tbool operator==(const char_t* other) const\n\t\t{\n\t\t\tsize_t length = static_cast<size_t>(end - begin);\n\n\t\t\treturn strequalrange(other, begin, length);\n\t\t}\n\t};\n\n\tclass xpath_lexer\n\t{\n\t\tconst char_t* _cur;\n\t\tconst char_t* _cur_lexeme_pos;\n\t\txpath_lexer_string _cur_lexeme_contents;\n\n\t\tlexeme_t _cur_lexeme;\n\n\tpublic:\n\t\texplicit xpath_lexer(const char_t* query): _cur(query)\n\t\t{\n\t\t\tnext();\n\t\t}\n\n\t\tconst char_t* state() const\n\t\t{\n\t\t\treturn _cur;\n\t\t}\n\n\t\tvoid next()\n\t\t{\n\t\t\tconst char_t* cur = _cur;\n\n\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*cur, ct_space)) ++cur;\n\n\t\t\t// save lexeme position for error reporting\n\t\t\t_cur_lexeme_pos = cur;\n\n\t\t\tswitch (*cur)\n\t\t\t{\n\t\t\tcase 0:\n\t\t\t\t_cur_lexeme = lex_eof;\n\t\t\t\tbreak;\n\n\t\t\tcase '>':\n\t\t\t\tif (*(cur+1) == '=')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_greater_or_equal;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcur += 1;\n\t\t\t\t\t_cur_lexeme = lex_greater;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '<':\n\t\t\t\tif (*(cur+1) == '=')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_less_or_equal;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcur += 1;\n\t\t\t\t\t_cur_lexeme = lex_less;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '!':\n\t\t\t\tif (*(cur+1) == '=')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_not_equal;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme = lex_none;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '=':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_equal;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '+':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_plus;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '-':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_minus;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '*':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_multiply;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '|':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_union;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '$':\n\t\t\t\tcur += 1;\n\n\t\t\t\tif (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol))\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme_contents.begin = cur;\n\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;\n\n\t\t\t\t\tif (cur[0] == ':' && PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // qname\n\t\t\t\t\t{\n\t\t\t\t\t\tcur++; // :\n\n\t\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;\n\t\t\t\t\t}\n\n\t\t\t\t\t_cur_lexeme_contents.end = cur;\n\n\t\t\t\t\t_cur_lexeme = lex_var_ref;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme = lex_none;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase '(':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_open_brace;\n\n\t\t\t\tbreak;\n\n\t\t\tcase ')':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_close_brace;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '[':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_open_square_brace;\n\n\t\t\t\tbreak;\n\n\t\t\tcase ']':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_close_square_brace;\n\n\t\t\t\tbreak;\n\n\t\t\tcase ',':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_comma;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '/':\n\t\t\t\tif (*(cur+1) == '/')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_double_slash;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcur += 1;\n\t\t\t\t\t_cur_lexeme = lex_slash;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '.':\n\t\t\t\tif (*(cur+1) == '.')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_double_dot;\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPEX(*(cur+1), ctx_digit))\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme_contents.begin = cur; // .\n\n\t\t\t\t\t++cur;\n\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;\n\n\t\t\t\t\t_cur_lexeme_contents.end = cur;\n\n\t\t\t\t\t_cur_lexeme = lex_number;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcur += 1;\n\t\t\t\t\t_cur_lexeme = lex_dot;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '@':\n\t\t\t\tcur += 1;\n\t\t\t\t_cur_lexeme = lex_axis_attribute;\n\n\t\t\t\tbreak;\n\n\t\t\tcase '\"':\n\t\t\tcase '\\'':\n\t\t\t{\n\t\t\t\tchar_t terminator = *cur;\n\n\t\t\t\t++cur;\n\n\t\t\t\t_cur_lexeme_contents.begin = cur;\n\t\t\t\twhile (*cur && *cur != terminator) cur++;\n\t\t\t\t_cur_lexeme_contents.end = cur;\n\n\t\t\t\tif (!*cur)\n\t\t\t\t\t_cur_lexeme = lex_none;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcur += 1;\n\t\t\t\t\t_cur_lexeme = lex_quoted_string;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase ':':\n\t\t\t\tif (*(cur+1) == ':')\n\t\t\t\t{\n\t\t\t\t\tcur += 2;\n\t\t\t\t\t_cur_lexeme = lex_double_colon;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme = lex_none;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tif (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit))\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme_contents.begin = cur;\n\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;\n\n\t\t\t\t\tif (*cur == '.')\n\t\t\t\t\t{\n\t\t\t\t\t\tcur++;\n\n\t\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;\n\t\t\t\t\t}\n\n\t\t\t\t\t_cur_lexeme_contents.end = cur;\n\n\t\t\t\t\t_cur_lexeme = lex_number;\n\t\t\t\t}\n\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol))\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme_contents.begin = cur;\n\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;\n\n\t\t\t\t\tif (cur[0] == ':')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cur[1] == '*') // namespace test ncname:*\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur += 2; // :*\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur++; // :\n\n\t\t\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t_cur_lexeme_contents.end = cur;\n\n\t\t\t\t\t_cur_lexeme = lex_string;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_cur_lexeme = lex_none;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_cur = cur;\n\t\t}\n\n\t\tlexeme_t current() const\n\t\t{\n\t\t\treturn _cur_lexeme;\n\t\t}\n\n\t\tconst char_t* current_pos() const\n\t\t{\n\t\t\treturn _cur_lexeme_pos;\n\t\t}\n\n\t\tconst xpath_lexer_string& contents() const\n\t\t{\n\t\t\tassert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);\n\n\t\t\treturn _cur_lexeme_contents;\n\t\t}\n\t};\n\n\tenum ast_type_t\n\t{\n\t\tast_unknown,\n\t\tast_op_or,\t\t\t\t\t\t// left or right\n\t\tast_op_and,\t\t\t\t\t\t// left and right\n\t\tast_op_equal,\t\t\t\t\t// left = right\n\t\tast_op_not_equal,\t\t\t\t// left != right\n\t\tast_op_less,\t\t\t\t\t// left < right\n\t\tast_op_greater,\t\t\t\t\t// left > right\n\t\tast_op_less_or_equal,\t\t\t// left <= right\n\t\tast_op_greater_or_equal,\t\t// left >= right\n\t\tast_op_add,\t\t\t\t\t\t// left + right\n\t\tast_op_subtract,\t\t\t\t// left - right\n\t\tast_op_multiply,\t\t\t\t// left * right\n\t\tast_op_divide,\t\t\t\t\t// left / right\n\t\tast_op_mod,\t\t\t\t\t\t// left % right\n\t\tast_op_negate,\t\t\t\t\t// left - right\n\t\tast_op_union,\t\t\t\t\t// left | right\n\t\tast_predicate,\t\t\t\t\t// apply predicate to set; next points to next predicate\n\t\tast_filter,\t\t\t\t\t\t// select * from left where right\n\t\tast_string_constant,\t\t\t// string constant\n\t\tast_number_constant,\t\t\t// number constant\n\t\tast_variable,\t\t\t\t\t// variable\n\t\tast_func_last,\t\t\t\t\t// last()\n\t\tast_func_position,\t\t\t\t// position()\n\t\tast_func_count,\t\t\t\t\t// count(left)\n\t\tast_func_id,\t\t\t\t\t// id(left)\n\t\tast_func_local_name_0,\t\t\t// local-name()\n\t\tast_func_local_name_1,\t\t\t// local-name(left)\n\t\tast_func_namespace_uri_0,\t\t// namespace-uri()\n\t\tast_func_namespace_uri_1,\t\t// namespace-uri(left)\n\t\tast_func_name_0,\t\t\t\t// name()\n\t\tast_func_name_1,\t\t\t\t// name(left)\n\t\tast_func_string_0,\t\t\t\t// string()\n\t\tast_func_string_1,\t\t\t\t// string(left)\n\t\tast_func_concat,\t\t\t\t// concat(left, right, siblings)\n\t\tast_func_starts_with,\t\t\t// starts_with(left, right)\n\t\tast_func_contains,\t\t\t\t// contains(left, right)\n\t\tast_func_substring_before,\t\t// substring-before(left, right)\n\t\tast_func_substring_after,\t\t// substring-after(left, right)\n\t\tast_func_substring_2,\t\t\t// substring(left, right)\n\t\tast_func_substring_3,\t\t\t// substring(left, right, third)\n\t\tast_func_string_length_0,\t\t// string-length()\n\t\tast_func_string_length_1,\t\t// string-length(left)\n\t\tast_func_normalize_space_0,\t\t// normalize-space()\n\t\tast_func_normalize_space_1,\t\t// normalize-space(left)\n\t\tast_func_translate,\t\t\t\t// translate(left, right, third)\n\t\tast_func_boolean,\t\t\t\t// boolean(left)\n\t\tast_func_not,\t\t\t\t\t// not(left)\n\t\tast_func_true,\t\t\t\t\t// true()\n\t\tast_func_false,\t\t\t\t\t// false()\n\t\tast_func_lang,\t\t\t\t\t// lang(left)\n\t\tast_func_number_0,\t\t\t\t// number()\n\t\tast_func_number_1,\t\t\t\t// number(left)\n\t\tast_func_sum,\t\t\t\t\t// sum(left)\n\t\tast_func_floor,\t\t\t\t\t// floor(left)\n\t\tast_func_ceiling,\t\t\t\t// ceiling(left)\n\t\tast_func_round,\t\t\t\t\t// round(left)\n\t\tast_step,\t\t\t\t\t\t// process set left with step\n\t\tast_step_root,\t\t\t\t\t// select root node\n\n\t\tast_opt_translate_table,\t\t// translate(left, right, third) where right/third are constants\n\t\tast_opt_compare_attribute\t\t// @name = 'string'\n\t};\n\n\tenum axis_t\n\t{\n\t\taxis_ancestor,\n\t\taxis_ancestor_or_self,\n\t\taxis_attribute,\n\t\taxis_child,\n\t\taxis_descendant,\n\t\taxis_descendant_or_self,\n\t\taxis_following,\n\t\taxis_following_sibling,\n\t\taxis_namespace,\n\t\taxis_parent,\n\t\taxis_preceding,\n\t\taxis_preceding_sibling,\n\t\taxis_self\n\t};\n\n\tenum nodetest_t\n\t{\n\t\tnodetest_none,\n\t\tnodetest_name,\n\t\tnodetest_type_node,\n\t\tnodetest_type_comment,\n\t\tnodetest_type_pi,\n\t\tnodetest_type_text,\n\t\tnodetest_pi,\n\t\tnodetest_all,\n\t\tnodetest_all_in_namespace\n\t};\n\n\tenum predicate_t\n\t{\n\t\tpredicate_default,\n\t\tpredicate_posinv,\n\t\tpredicate_constant,\n\t\tpredicate_constant_one\n\t};\n\n\tenum nodeset_eval_t\n\t{\n\t\tnodeset_eval_all,\n\t\tnodeset_eval_any,\n\t\tnodeset_eval_first\n\t};\n\n\ttemplate <axis_t N> struct axis_to_type\n\t{\n\t\tstatic const axis_t axis;\n\t};\n\n\ttemplate <axis_t N> const axis_t axis_to_type<N>::axis = N;\n\n\tclass xpath_ast_node\n\t{\n\tprivate:\n\t\t// node type\n\t\tchar _type;\n\t\tchar _rettype;\n\n\t\t// for ast_step\n\t\tchar _axis;\n\n\t\t// for ast_step/ast_predicate/ast_filter\n\t\tchar _test;\n\n\t\t// tree node structure\n\t\txpath_ast_node* _left;\n\t\txpath_ast_node* _right;\n\t\txpath_ast_node* _next;\n\n\t\tunion\n\t\t{\n\t\t\t// value for ast_string_constant\n\t\t\tconst char_t* string;\n\t\t\t// value for ast_number_constant\n\t\t\tdouble number;\n\t\t\t// variable for ast_variable\n\t\t\txpath_variable* variable;\n\t\t\t// node test for ast_step (node name/namespace/node type/pi target)\n\t\t\tconst char_t* nodetest;\n\t\t\t// table for ast_opt_translate_table\n\t\t\tconst unsigned char* table;\n\t\t} _data;\n\n\t\txpath_ast_node(const xpath_ast_node&);\n\t\txpath_ast_node& operator=(const xpath_ast_node&);\n\n\t\ttemplate <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)\n\t\t{\n\t\t\txpath_value_type lt = lhs->rettype(), rt = rhs->rettype();\n\n\t\t\tif (lt != xpath_type_node_set && rt != xpath_type_node_set)\n\t\t\t{\n\t\t\t\tif (lt == xpath_type_boolean || rt == xpath_type_boolean)\n\t\t\t\t\treturn comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));\n\t\t\t\telse if (lt == xpath_type_number || rt == xpath_type_number)\n\t\t\t\t\treturn comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));\n\t\t\t\telse if (lt == xpath_type_string || rt == xpath_type_string)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\t\txpath_string ls = lhs->eval_string(c, stack);\n\t\t\t\t\txpath_string rs = rhs->eval_string(c, stack);\n\n\t\t\t\t\treturn comp(ls, rs);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (lt == xpath_type_node_set && rt == xpath_type_node_set)\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);\n\t\t\t\txpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\tfor (const xpath_node* li = ls.begin(); li != ls.end(); ++li)\n\t\t\t\t\tfor (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)\n\t\t\t\t\t{\n\t\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\t\tif (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lt == xpath_type_node_set)\n\t\t\t\t{\n\t\t\t\t\tswap(lhs, rhs);\n\t\t\t\t\tswap(lt, rt);\n\t\t\t\t}\n\n\t\t\t\tif (lt == xpath_type_boolean)\n\t\t\t\t\treturn comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));\n\t\t\t\telse if (lt == xpath_type_number)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\t\tdouble l = lhs->eval_number(c, stack);\n\t\t\t\t\txpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\t\tfor (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)\n\t\t\t\t\t{\n\t\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\t\tif (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse if (lt == xpath_type_string)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\t\txpath_string l = lhs->eval_string(c, stack);\n\t\t\t\t\txpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\t\tfor (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)\n\t\t\t\t\t{\n\t\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\t\tif (comp(l, string_value(*ri, stack.result)))\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassert(false && \"Wrong types\"); // unreachable\n\t\t\treturn false;\n\t\t}\n\n\t\tstatic bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)\n\t\t{\n\t\t\treturn type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;\n\t\t}\n\n\t\ttemplate <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)\n\t\t{\n\t\t\txpath_value_type lt = lhs->rettype(), rt = rhs->rettype();\n\n\t\t\tif (lt != xpath_type_node_set && rt != xpath_type_node_set)\n\t\t\t\treturn comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));\n\t\t\telse if (lt == xpath_type_node_set && rt == xpath_type_node_set)\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);\n\t\t\t\txpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\tfor (const xpath_node* li = ls.begin(); li != ls.end(); ++li)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\tdouble l = convert_string_to_number(string_value(*li, stack.result).c_str());\n\n\t\t\t\t\tfor (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)\n\t\t\t\t\t{\n\t\t\t\t\t\txpath_allocator_capture crii(stack.result);\n\n\t\t\t\t\t\tif (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if (lt != xpath_type_node_set && rt == xpath_type_node_set)\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\tdouble l = lhs->eval_number(c, stack);\n\t\t\t\txpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\tfor (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\tif (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if (lt == xpath_type_node_set && rt != xpath_type_node_set)\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);\n\t\t\t\tdouble r = rhs->eval_number(c, stack);\n\n\t\t\t\tfor (const xpath_node* li = ls.begin(); li != ls.end(); ++li)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\tif (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert(false && \"Wrong types\"); // unreachable\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tstatic void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)\n\t\t{\n\t\t\tassert(ns.size() >= first);\n\t\t\tassert(expr->rettype() != xpath_type_number);\n\n\t\t\tsize_t i = 1;\n\t\t\tsize_t size = ns.size() - first;\n\n\t\t\txpath_node* last = ns.begin() + first;\n\n\t\t\t// remove_if... or well, sort of\n\t\t\tfor (xpath_node* it = last; it != ns.end(); ++it, ++i)\n\t\t\t{\n\t\t\t\txpath_context c(*it, i, size);\n\n\t\t\t\tif (expr->eval_boolean(c, stack))\n\t\t\t\t{\n\t\t\t\t\t*last++ = *it;\n\n\t\t\t\t\tif (once) break;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tns.truncate(last);\n\t\t}\n\n\t\tstatic void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)\n\t\t{\n\t\t\tassert(ns.size() >= first);\n\t\t\tassert(expr->rettype() == xpath_type_number);\n\n\t\t\tsize_t i = 1;\n\t\t\tsize_t size = ns.size() - first;\n\n\t\t\txpath_node* last = ns.begin() + first;\n\n\t\t\t// remove_if... or well, sort of\n\t\t\tfor (xpath_node* it = last; it != ns.end(); ++it, ++i)\n\t\t\t{\n\t\t\t\txpath_context c(*it, i, size);\n\n\t\t\t\tif (expr->eval_number(c, stack) == static_cast<double>(i))\n\t\t\t\t{\n\t\t\t\t\t*last++ = *it;\n\n\t\t\t\t\tif (once) break;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tns.truncate(last);\n\t\t}\n\n\t\tstatic void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)\n\t\t{\n\t\t\tassert(ns.size() >= first);\n\t\t\tassert(expr->rettype() == xpath_type_number);\n\n\t\t\tsize_t size = ns.size() - first;\n\n\t\t\txpath_node* last = ns.begin() + first;\n\n\t\t\txpath_node cn;\n\t\t\txpath_context c(cn, 1, size);\n\n\t\t\tdouble er = expr->eval_number(c, stack);\n\n\t\t\tif (er >= 1.0 && er <= static_cast<double>(size))\n\t\t\t{\n\t\t\t\tsize_t eri = static_cast<size_t>(er);\n\n\t\t\t\tif (er == static_cast<double>(eri))\n\t\t\t\t{\n\t\t\t\t\txpath_node r = last[eri - 1];\n\n\t\t\t\t\t*last++ = r;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tns.truncate(last);\n\t\t}\n\n\t\tvoid apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once)\n\t\t{\n\t\t\tif (ns.size() == first) return;\n\n\t\t\tassert(_type == ast_filter || _type == ast_predicate);\n\n\t\t\tif (_test == predicate_constant || _test == predicate_constant_one)\n\t\t\t\tapply_predicate_number_const(ns, first, _right, stack);\n\t\t\telse if (_right->rettype() == xpath_type_number)\n\t\t\t\tapply_predicate_number(ns, first, _right, stack, once);\n\t\t\telse\n\t\t\t\tapply_predicate_boolean(ns, first, _right, stack, once);\n\t\t}\n\n\t\tvoid apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)\n\t\t{\n\t\t\tif (ns.size() == first) return;\n\n\t\t\tbool last_once = eval_once(ns.type(), eval);\n\n\t\t\tfor (xpath_ast_node* pred = _right; pred; pred = pred->_next)\n\t\t\t\tpred->apply_predicate(ns, first, stack, !pred->_next && last_once);\n\t\t}\n\n\t\tbool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)\n\t\t{\n\t\t\tassert(a);\n\n\t\t\tconst char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(\"\");\n\n\t\t\tswitch (_test)\n\t\t\t{\n\t\t\tcase nodetest_name:\n\t\t\t\tif (strequal(name, _data.nodetest) && is_xpath_attribute(name))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_type_node:\n\t\t\tcase nodetest_all:\n\t\t\t\tif (is_xpath_attribute(name))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_all_in_namespace:\n\t\t\t\tif (starts_with(name, _data.nodetest) && is_xpath_attribute(name))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tbool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)\n\t\t{\n\t\t\tassert(n);\n\n\t\t\txml_node_type type = PUGI_IMPL_NODETYPE(n);\n\n\t\t\tswitch (_test)\n\t\t\t{\n\t\t\tcase nodetest_name:\n\t\t\t\tif (type == node_element && n->name && strequal(n->name, _data.nodetest))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_type_node:\n\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\treturn true;\n\n\t\t\tcase nodetest_type_comment:\n\t\t\t\tif (type == node_comment)\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_type_text:\n\t\t\t\tif (type == node_pcdata || type == node_cdata)\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_type_pi:\n\t\t\t\tif (type == node_pi)\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_pi:\n\t\t\t\tif (type == node_pi && n->name && strequal(n->name, _data.nodetest))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_all:\n\t\t\t\tif (type == node_element)\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase nodetest_all_in_namespace:\n\t\t\t\tif (type == node_element && n->name && starts_with(n->name, _data.nodetest))\n\t\t\t\t{\n\t\t\t\t\tns.push_back(xml_node(n), alloc);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Unknown axis\"); // unreachable\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\ttemplate <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)\n\t\t{\n\t\t\tconst axis_t axis = T::axis;\n\n\t\t\tswitch (axis)\n\t\t\t{\n\t\t\tcase axis_attribute:\n\t\t\t{\n\t\t\t\tfor (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)\n\t\t\t\t\tif (step_push(ns, a, n, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_child:\n\t\t\t{\n\t\t\t\tfor (xml_node_struct* c = n->first_child; c; c = c->next_sibling)\n\t\t\t\t\tif (step_push(ns, c, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_descendant:\n\t\t\tcase axis_descendant_or_self:\n\t\t\t{\n\t\t\t\tif (axis == axis_descendant_or_self)\n\t\t\t\t\tif (step_push(ns, n, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\txml_node_struct* cur = n->first_child;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tif (cur->first_child)\n\t\t\t\t\t\tcur = cur->first_child;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (!cur->next_sibling)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\t\t\tif (cur == n) return;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcur = cur->next_sibling;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_following_sibling:\n\t\t\t{\n\t\t\t\tfor (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)\n\t\t\t\t\tif (step_push(ns, c, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_preceding_sibling:\n\t\t\t{\n\t\t\t\tfor (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)\n\t\t\t\t\tif (step_push(ns, c, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_following:\n\t\t\t{\n\t\t\t\txml_node_struct* cur = n;\n\n\t\t\t\t// exit from this node so that we don't include descendants\n\t\t\t\twhile (!cur->next_sibling)\n\t\t\t\t{\n\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\tif (!cur) return;\n\t\t\t\t}\n\n\t\t\t\tcur = cur->next_sibling;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tif (cur->first_child)\n\t\t\t\t\t\tcur = cur->first_child;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (!cur->next_sibling)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\t\t\tif (!cur) return;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcur = cur->next_sibling;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_preceding:\n\t\t\t{\n\t\t\t\txml_node_struct* cur = n;\n\n\t\t\t\t// exit from this node so that we don't include descendants\n\t\t\t\twhile (!cur->prev_sibling_c->next_sibling)\n\t\t\t\t{\n\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\tif (!cur) return;\n\t\t\t\t}\n\n\t\t\t\tcur = cur->prev_sibling_c;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (cur->first_child)\n\t\t\t\t\t\tcur = cur->first_child->prev_sibling_c;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// leaf node, can't be ancestor\n\t\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\twhile (!cur->prev_sibling_c->next_sibling)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\t\t\tif (!cur) return;\n\n\t\t\t\t\t\t\tif (!node_is_ancestor(cur, n))\n\t\t\t\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcur = cur->prev_sibling_c;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_ancestor:\n\t\t\tcase axis_ancestor_or_self:\n\t\t\t{\n\t\t\t\tif (axis == axis_ancestor_or_self)\n\t\t\t\t\tif (step_push(ns, n, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\txml_node_struct* cur = n->parent;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tcur = cur->parent;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_self:\n\t\t\t{\n\t\t\t\tstep_push(ns, n, alloc);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_parent:\n\t\t\t{\n\t\t\t\tif (n->parent)\n\t\t\t\t\tstep_push(ns, n->parent, alloc);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Unimplemented axis\"); // unreachable\n\t\t\t}\n\t\t}\n\n\t\ttemplate <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v)\n\t\t{\n\t\t\tconst axis_t axis = T::axis;\n\n\t\t\tswitch (axis)\n\t\t\t{\n\t\t\tcase axis_ancestor:\n\t\t\tcase axis_ancestor_or_self:\n\t\t\t{\n\t\t\t\tif (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test\n\t\t\t\t\tif (step_push(ns, a, p, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\txml_node_struct* cur = p;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tcur = cur->parent;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_descendant_or_self:\n\t\t\tcase axis_self:\n\t\t\t{\n\t\t\t\tif (_test == nodetest_type_node) // reject attributes based on principal node type test\n\t\t\t\t\tstep_push(ns, a, p, alloc);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_following:\n\t\t\t{\n\t\t\t\txml_node_struct* cur = p;\n\n\t\t\t\twhile (cur)\n\t\t\t\t{\n\t\t\t\t\tif (cur->first_child)\n\t\t\t\t\t\tcur = cur->first_child;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (!cur->next_sibling)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcur = cur->parent;\n\n\t\t\t\t\t\t\tif (!cur) return;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcur = cur->next_sibling;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (step_push(ns, cur, alloc) & once)\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_parent:\n\t\t\t{\n\t\t\t\tstep_push(ns, p, alloc);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase axis_preceding:\n\t\t\t{\n\t\t\t\t// preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding\n\t\t\t\tstep_fill(ns, p, alloc, once, v);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Unimplemented axis\"); // unreachable\n\t\t\t}\n\t\t}\n\n\t\ttemplate <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)\n\t\t{\n\t\t\tconst axis_t axis = T::axis;\n\t\t\tconst bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);\n\n\t\t\tif (xn.node())\n\t\t\t\tstep_fill(ns, xn.node().internal_object(), alloc, once, v);\n\t\t\telse if (axis_has_attributes && xn.attribute() && xn.parent())\n\t\t\t\tstep_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);\n\t\t}\n\n\t\ttemplate <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)\n\t\t{\n\t\t\tconst axis_t axis = T::axis;\n\t\t\tconst bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);\n\t\t\tconst xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;\n\n\t\t\tbool once =\n\t\t\t\t(axis == axis_attribute && _test == nodetest_name) ||\n\t\t\t\t(!_right && eval_once(axis_type, eval)) ||\n\t\t\t    // coverity[mixed_enums]\n\t\t\t\t(_right && !_right->_next && _right->_test == predicate_constant_one);\n\n\t\t\txpath_node_set_raw ns;\n\t\t\tns.set_type(axis_type);\n\n\t\t\tif (_left)\n\t\t\t{\n\t\t\t\txpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\t// self axis preserves the original order\n\t\t\t\tif (axis == axis_self) ns.set_type(s.type());\n\n\t\t\t\tfor (const xpath_node* it = s.begin(); it != s.end(); ++it)\n\t\t\t\t{\n\t\t\t\t\tsize_t size = ns.size();\n\n\t\t\t\t\t// in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes\n\t\t\t\t\tif (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);\n\n\t\t\t\t\tstep_fill(ns, *it, stack.result, once, v);\n\t\t\t\t\tif (_right) apply_predicates(ns, size, stack, eval);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstep_fill(ns, c.n, stack.result, once, v);\n\t\t\t\tif (_right) apply_predicates(ns, 0, stack, eval);\n\t\t\t}\n\n\t\t\t// child, attribute and self axes always generate unique set of nodes\n\t\t\t// for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice\n\t\t\tif (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)\n\t\t\t\tns.remove_duplicates(stack.temp);\n\n\t\t\treturn ns;\n\t\t}\n\n\tpublic:\n\t\txpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):\n\t\t\t_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL)\n\t\t{\n\t\t\tassert(type == ast_string_constant);\n\t\t\t_data.string = value;\n\t\t}\n\n\t\txpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):\n\t\t\t_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL)\n\t\t{\n\t\t\tassert(type == ast_number_constant);\n\t\t\t_data.number = value;\n\t\t}\n\n\t\txpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):\n\t\t\t_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(NULL), _right(NULL), _next(NULL)\n\t\t{\n\t\t\tassert(type == ast_variable);\n\t\t\t_data.variable = value;\n\t\t}\n\n\t\txpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = NULL, xpath_ast_node* right = NULL):\n\t\t\t_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(NULL)\n\t\t{\n\t\t}\n\n\t\txpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):\n\t\t\t_type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(NULL), _next(NULL)\n\t\t{\n\t\t\tassert(type == ast_step);\n\t\t\t_data.nodetest = contents;\n\t\t}\n\n\t\txpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test):\n\t\t\t_type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(NULL)\n\t\t{\n\t\t\tassert(type == ast_filter || type == ast_predicate);\n\t\t}\n\n\t\tvoid set_next(xpath_ast_node* value)\n\t\t{\n\t\t\t_next = value;\n\t\t}\n\n\t\tvoid set_right(xpath_ast_node* value)\n\t\t{\n\t\t\t_right = value;\n\t\t}\n\n\t\tbool eval_boolean(const xpath_context& c, const xpath_stack& stack)\n\t\t{\n\t\t\tswitch (_type)\n\t\t\t{\n\t\t\tcase ast_op_or:\n\t\t\t\treturn _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);\n\n\t\t\tcase ast_op_and:\n\t\t\t\treturn _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);\n\n\t\t\tcase ast_op_equal:\n\t\t\t\treturn compare_eq(_left, _right, c, stack, equal_to());\n\n\t\t\tcase ast_op_not_equal:\n\t\t\t\treturn compare_eq(_left, _right, c, stack, not_equal_to());\n\n\t\t\tcase ast_op_less:\n\t\t\t\treturn compare_rel(_left, _right, c, stack, less());\n\n\t\t\tcase ast_op_greater:\n\t\t\t\treturn compare_rel(_right, _left, c, stack, less());\n\n\t\t\tcase ast_op_less_or_equal:\n\t\t\t\treturn compare_rel(_left, _right, c, stack, less_equal());\n\n\t\t\tcase ast_op_greater_or_equal:\n\t\t\t\treturn compare_rel(_right, _left, c, stack, less_equal());\n\n\t\t\tcase ast_func_starts_with:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_string lr = _left->eval_string(c, stack);\n\t\t\t\txpath_string rr = _right->eval_string(c, stack);\n\n\t\t\t\treturn starts_with(lr.c_str(), rr.c_str());\n\t\t\t}\n\n\t\t\tcase ast_func_contains:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_string lr = _left->eval_string(c, stack);\n\t\t\t\txpath_string rr = _right->eval_string(c, stack);\n\n\t\t\t\treturn find_substring(lr.c_str(), rr.c_str()) != NULL;\n\t\t\t}\n\n\t\t\tcase ast_func_boolean:\n\t\t\t\treturn _left->eval_boolean(c, stack);\n\n\t\t\tcase ast_func_not:\n\t\t\t\treturn !_left->eval_boolean(c, stack);\n\n\t\t\tcase ast_func_true:\n\t\t\t\treturn true;\n\n\t\t\tcase ast_func_false:\n\t\t\t\treturn false;\n\n\t\t\tcase ast_func_lang:\n\t\t\t{\n\t\t\t\tif (c.n.attribute()) return false;\n\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_string lang = _left->eval_string(c, stack);\n\n\t\t\t\tfor (xml_node n = c.n.node(); n; n = n.parent())\n\t\t\t\t{\n\t\t\t\t\txml_attribute a = n.attribute(PUGIXML_TEXT(\"xml:lang\"));\n\n\t\t\t\t\tif (a)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst char_t* value = a.value();\n\n\t\t\t\t\t\t// strnicmp / strncasecmp is not portable\n\t\t\t\t\t\tfor (const char_t* lit = lang.c_str(); *lit; ++lit)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (tolower_ascii(*lit) != tolower_ascii(*value)) return false;\n\t\t\t\t\t\t\t++value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn *value == 0 || *value == '-';\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tcase ast_opt_compare_attribute:\n\t\t\t{\n\t\t\t\tconst char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();\n\n\t\t\t\txml_attribute attr = c.n.node().attribute(_left->_data.nodetest);\n\n\t\t\t\treturn attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());\n\t\t\t}\n\n\t\t\tcase ast_variable:\n\t\t\t{\n\t\t\t\tassert(_rettype == _data.variable->type());\n\n\t\t\t\tif (_rettype == xpath_type_boolean)\n\t\t\t\t\treturn _data.variable->get_boolean();\n\n\t\t\t\t// variable needs to be converted to the correct type, this is handled by the fallthrough block below\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\t;\n\t\t\t}\n\n\t\t\t// none of the ast types that return the value directly matched, we need to perform type conversion\n\t\t\tswitch (_rettype)\n\t\t\t{\n\t\t\tcase xpath_type_number:\n\t\t\t\treturn convert_number_to_boolean(eval_number(c, stack));\n\n\t\t\tcase xpath_type_string:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn !eval_string(c, stack).empty();\n\t\t\t}\n\n\t\t\tcase xpath_type_node_set:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn !eval_node_set(c, stack, nodeset_eval_any).empty();\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Wrong expression for return type boolean\"); // unreachable\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tdouble eval_number(const xpath_context& c, const xpath_stack& stack)\n\t\t{\n\t\t\tswitch (_type)\n\t\t\t{\n\t\t\tcase ast_op_add:\n\t\t\t\treturn _left->eval_number(c, stack) + _right->eval_number(c, stack);\n\n\t\t\tcase ast_op_subtract:\n\t\t\t\treturn _left->eval_number(c, stack) - _right->eval_number(c, stack);\n\n\t\t\tcase ast_op_multiply:\n\t\t\t\treturn _left->eval_number(c, stack) * _right->eval_number(c, stack);\n\n\t\t\tcase ast_op_divide:\n\t\t\t\treturn _left->eval_number(c, stack) / _right->eval_number(c, stack);\n\n\t\t\tcase ast_op_mod:\n\t\t\t\treturn fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));\n\n\t\t\tcase ast_op_negate:\n\t\t\t\treturn -_left->eval_number(c, stack);\n\n\t\t\tcase ast_number_constant:\n\t\t\t\treturn _data.number;\n\n\t\t\tcase ast_func_last:\n\t\t\t\treturn static_cast<double>(c.size);\n\n\t\t\tcase ast_func_position:\n\t\t\t\treturn static_cast<double>(c.position);\n\n\t\t\tcase ast_func_count:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());\n\t\t\t}\n\n\t\t\tcase ast_func_string_length_0:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn static_cast<double>(string_value(c.n, stack.result).length());\n\t\t\t}\n\n\t\t\tcase ast_func_string_length_1:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn static_cast<double>(_left->eval_string(c, stack).length());\n\t\t\t}\n\n\t\t\tcase ast_func_number_0:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn convert_string_to_number(string_value(c.n, stack.result).c_str());\n\t\t\t}\n\n\t\t\tcase ast_func_number_1:\n\t\t\t\treturn _left->eval_number(c, stack);\n\n\t\t\tcase ast_func_sum:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\tdouble r = 0;\n\n\t\t\t\txpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all);\n\n\t\t\t\tfor (const xpath_node* it = ns.begin(); it != ns.end(); ++it)\n\t\t\t\t{\n\t\t\t\t\txpath_allocator_capture cri(stack.result);\n\n\t\t\t\t\tr += convert_string_to_number(string_value(*it, stack.result).c_str());\n\t\t\t\t}\n\n\t\t\t\treturn r;\n\t\t\t}\n\n\t\t\tcase ast_func_floor:\n\t\t\t{\n\t\t\t\tdouble r = _left->eval_number(c, stack);\n\n\t\t\t\treturn r == r ? floor(r) : r;\n\t\t\t}\n\n\t\t\tcase ast_func_ceiling:\n\t\t\t{\n\t\t\t\tdouble r = _left->eval_number(c, stack);\n\n\t\t\t\treturn r == r ? ceil(r) : r;\n\t\t\t}\n\n\t\t\tcase ast_func_round:\n\t\t\t\treturn round_nearest_nzero(_left->eval_number(c, stack));\n\n\t\t\tcase ast_variable:\n\t\t\t{\n\t\t\t\tassert(_rettype == _data.variable->type());\n\n\t\t\t\tif (_rettype == xpath_type_number)\n\t\t\t\t\treturn _data.variable->get_number();\n\n\t\t\t\t// variable needs to be converted to the correct type, this is handled by the fallthrough block below\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\t;\n\t\t\t}\n\n\t\t\t// none of the ast types that return the value directly matched, we need to perform type conversion\n\t\t\tswitch (_rettype)\n\t\t\t{\n\t\t\tcase xpath_type_boolean:\n\t\t\t\treturn eval_boolean(c, stack) ? 1 : 0;\n\n\t\t\tcase xpath_type_string:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn convert_string_to_number(eval_string(c, stack).c_str());\n\t\t\t}\n\n\t\t\tcase xpath_type_node_set:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\treturn convert_string_to_number(eval_string(c, stack).c_str());\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Wrong expression for return type number\"); // unreachable\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\txpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack)\n\t\t{\n\t\t\tassert(_type == ast_func_concat);\n\n\t\t\txpath_allocator_capture ct(stack.temp);\n\n\t\t\t// count the string number\n\t\t\tsize_t count = 1;\n\t\t\tfor (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;\n\n\t\t\t// allocate a buffer for temporary string objects\n\t\t\txpath_string* buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));\n\t\t\tif (!buffer) return xpath_string();\n\n\t\t\t// evaluate all strings to temporary stack\n\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\tbuffer[0] = _left->eval_string(c, swapped_stack);\n\n\t\t\tsize_t pos = 1;\n\t\t\tfor (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);\n\t\t\tassert(pos == count);\n\n\t\t\t// get total length\n\t\t\tsize_t length = 0;\n\t\t\tfor (size_t i = 0; i < count; ++i) length += buffer[i].length();\n\n\t\t\t// create final string\n\t\t\tchar_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!result) return xpath_string();\n\n\t\t\tchar_t* ri = result;\n\n\t\t\tfor (size_t j = 0; j < count; ++j)\n\t\t\t\tfor (const char_t* bi = buffer[j].c_str(); *bi; ++bi)\n\t\t\t\t\t*ri++ = *bi;\n\n\t\t\t*ri = 0;\n\n\t\t\treturn xpath_string::from_heap_preallocated(result, ri);\n\t\t}\n\n\t\txpath_string eval_string(const xpath_context& c, const xpath_stack& stack)\n\t\t{\n\t\t\tswitch (_type)\n\t\t\t{\n\t\t\tcase ast_string_constant:\n\t\t\t\treturn xpath_string::from_const(_data.string);\n\n\t\t\tcase ast_func_local_name_0:\n\t\t\t{\n\t\t\t\txpath_node na = c.n;\n\n\t\t\t\treturn xpath_string::from_const(local_name(na));\n\t\t\t}\n\n\t\t\tcase ast_func_local_name_1:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);\n\t\t\t\txpath_node na = ns.first();\n\n\t\t\t\treturn xpath_string::from_const(local_name(na));\n\t\t\t}\n\n\t\t\tcase ast_func_name_0:\n\t\t\t{\n\t\t\t\txpath_node na = c.n;\n\n\t\t\t\treturn xpath_string::from_const(qualified_name(na));\n\t\t\t}\n\n\t\t\tcase ast_func_name_1:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);\n\t\t\t\txpath_node na = ns.first();\n\n\t\t\t\treturn xpath_string::from_const(qualified_name(na));\n\t\t\t}\n\n\t\t\tcase ast_func_namespace_uri_0:\n\t\t\t{\n\t\t\t\txpath_node na = c.n;\n\n\t\t\t\treturn xpath_string::from_const(namespace_uri(na));\n\t\t\t}\n\n\t\t\tcase ast_func_namespace_uri_1:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.result);\n\n\t\t\t\txpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);\n\t\t\t\txpath_node na = ns.first();\n\n\t\t\t\treturn xpath_string::from_const(namespace_uri(na));\n\t\t\t}\n\n\t\t\tcase ast_func_string_0:\n\t\t\t\treturn string_value(c.n, stack.result);\n\n\t\t\tcase ast_func_string_1:\n\t\t\t\treturn _left->eval_string(c, stack);\n\n\t\t\tcase ast_func_concat:\n\t\t\t\treturn eval_string_concat(c, stack);\n\n\t\t\tcase ast_func_substring_before:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_string s = _left->eval_string(c, swapped_stack);\n\t\t\t\txpath_string p = _right->eval_string(c, swapped_stack);\n\n\t\t\t\tconst char_t* pos = find_substring(s.c_str(), p.c_str());\n\n\t\t\t\treturn pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();\n\t\t\t}\n\n\t\t\tcase ast_func_substring_after:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_string s = _left->eval_string(c, swapped_stack);\n\t\t\t\txpath_string p = _right->eval_string(c, swapped_stack);\n\n\t\t\t\tconst char_t* pos = find_substring(s.c_str(), p.c_str());\n\t\t\t\tif (!pos) return xpath_string();\n\n\t\t\t\tconst char_t* rbegin = pos + p.length();\n\t\t\t\tconst char_t* rend = s.c_str() + s.length();\n\n\t\t\t\treturn s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);\n\t\t\t}\n\n\t\t\tcase ast_func_substring_2:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_string s = _left->eval_string(c, swapped_stack);\n\t\t\t\tsize_t s_length = s.length();\n\n\t\t\t\tdouble first = round_nearest(_right->eval_number(c, stack));\n\n\t\t\t\tif (is_nan(first)) return xpath_string(); // NaN\n\t\t\t\telse if (first >= static_cast<double>(s_length + 1)) return xpath_string();\n\n\t\t\t\tsize_t pos = first < 1 ? 1 : static_cast<size_t>(first);\n\t\t\t\tassert(1 <= pos && pos <= s_length + 1);\n\n\t\t\t\tconst char_t* rbegin = s.c_str() + (pos - 1);\n\t\t\t\tconst char_t* rend = s.c_str() + s.length();\n\n\t\t\t\treturn s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);\n\t\t\t}\n\n\t\t\tcase ast_func_substring_3:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_string s = _left->eval_string(c, swapped_stack);\n\t\t\t\tsize_t s_length = s.length();\n\n\t\t\t\tdouble first = round_nearest(_right->eval_number(c, stack));\n\t\t\t\tdouble last = first + round_nearest(_right->_next->eval_number(c, stack));\n\n\t\t\t\tif (is_nan(first) || is_nan(last)) return xpath_string();\n\t\t\t\telse if (first >= static_cast<double>(s_length + 1)) return xpath_string();\n\t\t\t\telse if (first >= last) return xpath_string();\n\t\t\t\telse if (last < 1) return xpath_string();\n\n\t\t\t\tsize_t pos = first < 1 ? 1 : static_cast<size_t>(first);\n\t\t\t\tsize_t end = last >= static_cast<double>(s_length + 1) ? s_length + 1 : static_cast<size_t>(last);\n\n\t\t\t\tassert(1 <= pos && pos <= end && end <= s_length + 1);\n\t\t\t\tconst char_t* rbegin = s.c_str() + (pos - 1);\n\t\t\t\tconst char_t* rend = s.c_str() + (end - 1);\n\n\t\t\t\treturn (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);\n\t\t\t}\n\n\t\t\tcase ast_func_normalize_space_0:\n\t\t\t{\n\t\t\t\txpath_string s = string_value(c.n, stack.result);\n\n\t\t\t\tchar_t* begin = s.data(stack.result);\n\t\t\t\tif (!begin) return xpath_string();\n\n\t\t\t\tchar_t* end = normalize_space(begin);\n\n\t\t\t\treturn xpath_string::from_heap_preallocated(begin, end);\n\t\t\t}\n\n\t\t\tcase ast_func_normalize_space_1:\n\t\t\t{\n\t\t\t\txpath_string s = _left->eval_string(c, stack);\n\n\t\t\t\tchar_t* begin = s.data(stack.result);\n\t\t\t\tif (!begin) return xpath_string();\n\n\t\t\t\tchar_t* end = normalize_space(begin);\n\n\t\t\t\treturn xpath_string::from_heap_preallocated(begin, end);\n\t\t\t}\n\n\t\t\tcase ast_func_translate:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_string s = _left->eval_string(c, stack);\n\t\t\t\txpath_string from = _right->eval_string(c, swapped_stack);\n\t\t\t\txpath_string to = _right->_next->eval_string(c, swapped_stack);\n\n\t\t\t\tchar_t* begin = s.data(stack.result);\n\t\t\t\tif (!begin) return xpath_string();\n\n\t\t\t\tchar_t* end = translate(begin, from.c_str(), to.c_str(), to.length());\n\n\t\t\t\treturn xpath_string::from_heap_preallocated(begin, end);\n\t\t\t}\n\n\t\t\tcase ast_opt_translate_table:\n\t\t\t{\n\t\t\t\txpath_string s = _left->eval_string(c, stack);\n\n\t\t\t\tchar_t* begin = s.data(stack.result);\n\t\t\t\tif (!begin) return xpath_string();\n\n\t\t\t\tchar_t* end = translate_table(begin, _data.table);\n\n\t\t\t\treturn xpath_string::from_heap_preallocated(begin, end);\n\t\t\t}\n\n\t\t\tcase ast_variable:\n\t\t\t{\n\t\t\t\tassert(_rettype == _data.variable->type());\n\n\t\t\t\tif (_rettype == xpath_type_string)\n\t\t\t\t\treturn xpath_string::from_const(_data.variable->get_string());\n\n\t\t\t\t// variable needs to be converted to the correct type, this is handled by the fallthrough block below\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\t;\n\t\t\t}\n\n\t\t\t// none of the ast types that return the value directly matched, we need to perform type conversion\n\t\t\tswitch (_rettype)\n\t\t\t{\n\t\t\tcase xpath_type_boolean:\n\t\t\t\treturn xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT(\"true\") : PUGIXML_TEXT(\"false\"));\n\n\t\t\tcase xpath_type_number:\n\t\t\t\treturn convert_number_to_string(eval_number(c, stack), stack.result);\n\n\t\t\tcase xpath_type_node_set:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first);\n\t\t\t\treturn ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tassert(false && \"Wrong expression for return type string\"); // unreachable\n\t\t\t\treturn xpath_string();\n\t\t\t}\n\t\t}\n\n\t\txpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval)\n\t\t{\n\t\t\tswitch (_type)\n\t\t\t{\n\t\t\tcase ast_op_union:\n\t\t\t{\n\t\t\t\txpath_allocator_capture cr(stack.temp);\n\n\t\t\t\txpath_stack swapped_stack = {stack.temp, stack.result};\n\n\t\t\t\txpath_node_set_raw ls = _left->eval_node_set(c, stack, eval);\n\t\t\t\txpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval);\n\n\t\t\t\t// we can optimize merging two sorted sets, but this is a very rare operation, so don't bother\n\t\t\t\tls.set_type(xpath_node_set::type_unsorted);\n\n\t\t\t\tls.append(rs.begin(), rs.end(), stack.result);\n\t\t\t\tls.remove_duplicates(stack.temp);\n\n\t\t\t\treturn ls;\n\t\t\t}\n\n\t\t\tcase ast_filter:\n\t\t\t{\n\t\t\t\txpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all);\n\n\t\t\t\t// either expression is a number or it contains position() call; sort by document order\n\t\t\t\tif (_test != predicate_posinv) set.sort_do();\n\n\t\t\t\tbool once = eval_once(set.type(), eval);\n\n\t\t\t\tapply_predicate(set, 0, stack, once);\n\n\t\t\t\treturn set;\n\t\t\t}\n\n\t\t\tcase ast_func_id:\n\t\t\t\treturn xpath_node_set_raw();\n\n\t\t\tcase ast_step:\n\t\t\t{\n\t\t\t\tswitch (_axis)\n\t\t\t\t{\n\t\t\t\tcase axis_ancestor:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_ancestor>());\n\n\t\t\t\tcase axis_ancestor_or_self:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());\n\n\t\t\t\tcase axis_attribute:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_attribute>());\n\n\t\t\t\tcase axis_child:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_child>());\n\n\t\t\t\tcase axis_descendant:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_descendant>());\n\n\t\t\t\tcase axis_descendant_or_self:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());\n\n\t\t\t\tcase axis_following:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_following>());\n\n\t\t\t\tcase axis_following_sibling:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_following_sibling>());\n\n\t\t\t\tcase axis_namespace:\n\t\t\t\t\t// namespaced axis is not supported\n\t\t\t\t\treturn xpath_node_set_raw();\n\n\t\t\t\tcase axis_parent:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_parent>());\n\n\t\t\t\tcase axis_preceding:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_preceding>());\n\n\t\t\t\tcase axis_preceding_sibling:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());\n\n\t\t\t\tcase axis_self:\n\t\t\t\t\treturn step_do(c, stack, eval, axis_to_type<axis_self>());\n\n\t\t\t\tdefault:\n\t\t\t\t\tassert(false && \"Unknown axis\"); // unreachable\n\t\t\t\t\treturn xpath_node_set_raw();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcase ast_step_root:\n\t\t\t{\n\t\t\t\tassert(!_right); // root step can't have any predicates\n\n\t\t\t\txpath_node_set_raw ns;\n\n\t\t\t\tns.set_type(xpath_node_set::type_sorted);\n\n\t\t\t\tif (c.n.node()) ns.push_back(c.n.node().root(), stack.result);\n\t\t\t\telse if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);\n\n\t\t\t\treturn ns;\n\t\t\t}\n\n\t\t\tcase ast_variable:\n\t\t\t{\n\t\t\t\tassert(_rettype == _data.variable->type());\n\n\t\t\t\tif (_rettype == xpath_type_node_set)\n\t\t\t\t{\n\t\t\t\t\tconst xpath_node_set& s = _data.variable->get_node_set();\n\n\t\t\t\t\txpath_node_set_raw ns;\n\n\t\t\t\t\tns.set_type(s.type());\n\t\t\t\t\tns.append(s.begin(), s.end(), stack.result);\n\n\t\t\t\t\treturn ns;\n\t\t\t\t}\n\n\t\t\t\t// variable needs to be converted to the correct type, this is handled by the fallthrough block below\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\t;\n\t\t\t}\n\n\t\t\t// none of the ast types that return the value directly matched, but conversions to node set are invalid\n\t\t\tassert(false && \"Wrong expression for return type node set\"); // unreachable\n\t\t\treturn xpath_node_set_raw();\n\t\t}\n\n\t\tvoid optimize(xpath_allocator* alloc)\n\t\t{\n\t\t\tif (_left)\n\t\t\t\t_left->optimize(alloc);\n\n\t\t\tif (_right)\n\t\t\t\t_right->optimize(alloc);\n\n\t\t\tif (_next)\n\t\t\t\t_next->optimize(alloc);\n\n\t\t\t// coverity[var_deref_model]\n\t\t\toptimize_self(alloc);\n\t\t}\n\n\t\tvoid optimize_self(xpath_allocator* alloc)\n\t\t{\n\t\t\t// Rewrite [position()=expr] with [expr]\n\t\t\t// Note that this step has to go before classification to recognize [position()=1]\n\t\t\tif ((_type == ast_filter || _type == ast_predicate) &&\n\t\t\t\t_right && // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)\n\t\t\t\t_right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)\n\t\t\t{\n\t\t\t\t_right = _right->_right;\n\t\t\t}\n\n\t\t\t// Classify filter/predicate ops to perform various optimizations during evaluation\n\t\t\tif ((_type == ast_filter || _type == ast_predicate) && _right) // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)\n\t\t\t{\n\t\t\t\tassert(_test == predicate_default);\n\n\t\t\t\tif (_right->_type == ast_number_constant && _right->_data.number == 1.0)\n\t\t\t\t\t_test = predicate_constant_one;\n\t\t\t\telse if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))\n\t\t\t\t\t_test = predicate_constant;\n\t\t\t\telse if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())\n\t\t\t\t\t_test = predicate_posinv;\n\t\t\t}\n\n\t\t\t// Rewrite descendant-or-self::node()/child::foo with descendant::foo\n\t\t\t// The former is a full form of //foo, the latter is much faster since it executes the node test immediately\n\t\t\t// Do a similar kind of rewrite for self/descendant/descendant-or-self axes\n\t\t\t// Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1])\n\t\t\tif (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) &&\n\t\t\t\t_left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right &&\n\t\t\t\tis_posinv_step())\n\t\t\t{\n\t\t\t\tif (_axis == axis_child || _axis == axis_descendant)\n\t\t\t\t\t_axis = axis_descendant;\n\t\t\t\telse\n\t\t\t\t\t_axis = axis_descendant_or_self;\n\n\t\t\t\t_left = _left->_left;\n\t\t\t}\n\n\t\t\t// Use optimized lookup table implementation for translate() with constant arguments\n\t\t\tif (_type == ast_func_translate &&\n\t\t\t\t_right && // workaround for clang static analyzer (_right is never null for ast_func_translate)\n\t\t\t\t_right->_type == ast_string_constant && _right->_next->_type == ast_string_constant)\n\t\t\t{\n\t\t\t\tunsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);\n\n\t\t\t\tif (table)\n\t\t\t\t{\n\t\t\t\t\t_type = ast_opt_translate_table;\n\t\t\t\t\t_data.table = table;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Use optimized path for @attr = 'value' or @attr = $value\n\t\t\tif (_type == ast_op_equal &&\n\t\t\t\t_left && _right && // workaround for clang static analyzer and Coverity (_left and _right are never null for ast_op_equal)\n                // coverity[mixed_enums]\n\t\t\t\t_left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right &&\n\t\t\t\t(_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string)))\n\t\t\t{\n\t\t\t\t_type = ast_opt_compare_attribute;\n\t\t\t}\n\t\t}\n\n\t\tbool is_posinv_expr() const\n\t\t{\n\t\t\tswitch (_type)\n\t\t\t{\n\t\t\tcase ast_func_position:\n\t\t\tcase ast_func_last:\n\t\t\t\treturn false;\n\n\t\t\tcase ast_string_constant:\n\t\t\tcase ast_number_constant:\n\t\t\tcase ast_variable:\n\t\t\t\treturn true;\n\n\t\t\tcase ast_step:\n\t\t\tcase ast_step_root:\n\t\t\t\treturn true;\n\n\t\t\tcase ast_predicate:\n\t\t\tcase ast_filter:\n\t\t\t\treturn true;\n\n\t\t\tdefault:\n\t\t\t\tif (_left && !_left->is_posinv_expr()) return false;\n\n\t\t\t\tfor (xpath_ast_node* n = _right; n; n = n->_next)\n\t\t\t\t\tif (!n->is_posinv_expr()) return false;\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tbool is_posinv_step() const\n\t\t{\n\t\t\tassert(_type == ast_step);\n\n\t\t\tfor (xpath_ast_node* n = _right; n; n = n->_next)\n\t\t\t{\n\t\t\t\tassert(n->_type == ast_predicate);\n\n\t\t\t\tif (n->_test != predicate_posinv)\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\txpath_value_type rettype() const\n\t\t{\n\t\t\treturn static_cast<xpath_value_type>(_rettype);\n\t\t}\n\t};\n\n\tstatic const size_t xpath_ast_depth_limit =\n\t#ifdef PUGIXML_XPATH_DEPTH_LIMIT\n\t\tPUGIXML_XPATH_DEPTH_LIMIT\n\t#else\n\t\t1024\n\t#endif\n\t\t;\n\n\tstruct xpath_parser\n\t{\n\t\txpath_allocator* _alloc;\n\t\txpath_lexer _lexer;\n\n\t\tconst char_t* _query;\n\t\txpath_variable_set* _variables;\n\n\t\txpath_parse_result* _result;\n\n\t\tchar_t _scratch[32];\n\n\t\tsize_t _depth;\n\n\t\txpath_ast_node* error(const char* message)\n\t\t{\n\t\t\t_result->error = message;\n\t\t\t_result->offset = _lexer.current_pos() - _query;\n\n\t\t\treturn NULL;\n\t\t}\n\n\t\txpath_ast_node* error_oom()\n\t\t{\n\t\t\tassert(_alloc->_error);\n\t\t\t*_alloc->_error = true;\n\n\t\t\treturn NULL;\n\t\t}\n\n\t\txpath_ast_node* error_rec()\n\t\t{\n\t\t\treturn error(\"Exceeded maximum allowed query depth\");\n\t\t}\n\n\t\tvoid* alloc_node()\n\t\t{\n\t\t\treturn _alloc->allocate(sizeof(xpath_ast_node));\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL;\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL;\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, rettype, value) : NULL;\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = NULL, xpath_ast_node* right = NULL)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, rettype, left, right) : NULL;\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : NULL;\n\t\t}\n\n\t\txpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test)\n\t\t{\n\t\t\tvoid* memory = alloc_node();\n\t\t\treturn memory ? new (memory) xpath_ast_node(type, left, right, test) : NULL;\n\t\t}\n\n\t\tconst char_t* alloc_string(const xpath_lexer_string& value)\n\t\t{\n\t\t\tif (!value.begin)\n\t\t\t\treturn PUGIXML_TEXT(\"\");\n\n\t\t\tsize_t length = static_cast<size_t>(value.end - value.begin);\n\n\t\t\tchar_t* c = static_cast<char_t*>(_alloc->allocate((length + 1) * sizeof(char_t)));\n\t\t\tif (!c) return NULL;\n\n\t\t\tmemcpy(c, value.begin, length * sizeof(char_t));\n\t\t\tc[length] = 0;\n\n\t\t\treturn c;\n\t\t}\n\n\t\txpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2])\n\t\t{\n\t\t\tswitch (name.begin[0])\n\t\t\t{\n\t\t\tcase 'b':\n\t\t\t\tif (name == PUGIXML_TEXT(\"boolean\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_boolean, xpath_type_boolean, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'c':\n\t\t\t\tif (name == PUGIXML_TEXT(\"count\") && argc == 1)\n\t\t\t\t{\n\t\t\t\t\tif (args[0]->rettype() != xpath_type_node_set) return error(\"Function has to be applied to node set\");\n\t\t\t\t\treturn alloc_node(ast_func_count, xpath_type_number, args[0]);\n\t\t\t\t}\n\t\t\t\telse if (name == PUGIXML_TEXT(\"contains\") && argc == 2)\n\t\t\t\t\treturn alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"concat\") && argc >= 2)\n\t\t\t\t\treturn alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"ceiling\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_ceiling, xpath_type_number, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'f':\n\t\t\t\tif (name == PUGIXML_TEXT(\"false\") && argc == 0)\n\t\t\t\t\treturn alloc_node(ast_func_false, xpath_type_boolean);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"floor\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_floor, xpath_type_number, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'i':\n\t\t\t\tif (name == PUGIXML_TEXT(\"id\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_id, xpath_type_node_set, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'l':\n\t\t\t\tif (name == PUGIXML_TEXT(\"last\") && argc == 0)\n\t\t\t\t\treturn alloc_node(ast_func_last, xpath_type_number);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"lang\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_lang, xpath_type_boolean, args[0]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"local-name\") && argc <= 1)\n\t\t\t\t{\n\t\t\t\t\tif (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error(\"Function has to be applied to node set\");\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'n':\n\t\t\t\tif (name == PUGIXML_TEXT(\"name\") && argc <= 1)\n\t\t\t\t{\n\t\t\t\t\tif (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error(\"Function has to be applied to node set\");\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]);\n\t\t\t\t}\n\t\t\t\telse if (name == PUGIXML_TEXT(\"namespace-uri\") && argc <= 1)\n\t\t\t\t{\n\t\t\t\t\tif (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error(\"Function has to be applied to node set\");\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]);\n\t\t\t\t}\n\t\t\t\telse if (name == PUGIXML_TEXT(\"normalize-space\") && argc <= 1)\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"not\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_not, xpath_type_boolean, args[0]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"number\") && argc <= 1)\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'p':\n\t\t\t\tif (name == PUGIXML_TEXT(\"position\") && argc == 0)\n\t\t\t\t\treturn alloc_node(ast_func_position, xpath_type_number);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'r':\n\t\t\t\tif (name == PUGIXML_TEXT(\"round\") && argc == 1)\n\t\t\t\t\treturn alloc_node(ast_func_round, xpath_type_number, args[0]);\n\n\t\t\t\tbreak;\n\n\t\t\tcase 's':\n\t\t\t\tif (name == PUGIXML_TEXT(\"string\") && argc <= 1)\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"string-length\") && argc <= 1)\n\t\t\t\t\treturn alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"starts-with\") && argc == 2)\n\t\t\t\t\treturn alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"substring-before\") && argc == 2)\n\t\t\t\t\treturn alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"substring-after\") && argc == 2)\n\t\t\t\t\treturn alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"substring\") && (argc == 2 || argc == 3))\n\t\t\t\t\treturn alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"sum\") && argc == 1)\n\t\t\t\t{\n\t\t\t\t\tif (args[0]->rettype() != xpath_type_node_set) return error(\"Function has to be applied to node set\");\n\t\t\t\t\treturn alloc_node(ast_func_sum, xpath_type_number, args[0]);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 't':\n\t\t\t\tif (name == PUGIXML_TEXT(\"translate\") && argc == 3)\n\t\t\t\t\treturn alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]);\n\t\t\t\telse if (name == PUGIXML_TEXT(\"true\") && argc == 0)\n\t\t\t\t\treturn alloc_node(ast_func_true, xpath_type_boolean);\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn error(\"Unrecognized function or wrong parameter count\");\n\t\t}\n\n\t\taxis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)\n\t\t{\n\t\t\tspecified = true;\n\n\t\t\tswitch (name.begin[0])\n\t\t\t{\n\t\t\tcase 'a':\n\t\t\t\tif (name == PUGIXML_TEXT(\"ancestor\"))\n\t\t\t\t\treturn axis_ancestor;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"ancestor-or-self\"))\n\t\t\t\t\treturn axis_ancestor_or_self;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"attribute\"))\n\t\t\t\t\treturn axis_attribute;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'c':\n\t\t\t\tif (name == PUGIXML_TEXT(\"child\"))\n\t\t\t\t\treturn axis_child;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'd':\n\t\t\t\tif (name == PUGIXML_TEXT(\"descendant\"))\n\t\t\t\t\treturn axis_descendant;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"descendant-or-self\"))\n\t\t\t\t\treturn axis_descendant_or_self;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'f':\n\t\t\t\tif (name == PUGIXML_TEXT(\"following\"))\n\t\t\t\t\treturn axis_following;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"following-sibling\"))\n\t\t\t\t\treturn axis_following_sibling;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'n':\n\t\t\t\tif (name == PUGIXML_TEXT(\"namespace\"))\n\t\t\t\t\treturn axis_namespace;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'p':\n\t\t\t\tif (name == PUGIXML_TEXT(\"parent\"))\n\t\t\t\t\treturn axis_parent;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"preceding\"))\n\t\t\t\t\treturn axis_preceding;\n\t\t\t\telse if (name == PUGIXML_TEXT(\"preceding-sibling\"))\n\t\t\t\t\treturn axis_preceding_sibling;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 's':\n\t\t\t\tif (name == PUGIXML_TEXT(\"self\"))\n\t\t\t\t\treturn axis_self;\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tspecified = false;\n\t\t\treturn axis_child;\n\t\t}\n\n\t\tnodetest_t parse_node_test_type(const xpath_lexer_string& name)\n\t\t{\n\t\t\tswitch (name.begin[0])\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tif (name == PUGIXML_TEXT(\"comment\"))\n\t\t\t\t\treturn nodetest_type_comment;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'n':\n\t\t\t\tif (name == PUGIXML_TEXT(\"node\"))\n\t\t\t\t\treturn nodetest_type_node;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'p':\n\t\t\t\tif (name == PUGIXML_TEXT(\"processing-instruction\"))\n\t\t\t\t\treturn nodetest_type_pi;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 't':\n\t\t\t\tif (name == PUGIXML_TEXT(\"text\"))\n\t\t\t\t\treturn nodetest_type_text;\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn nodetest_none;\n\t\t}\n\n\t\t// PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall\n\t\txpath_ast_node* parse_primary_expression()\n\t\t{\n\t\t\tswitch (_lexer.current())\n\t\t\t{\n\t\t\tcase lex_var_ref:\n\t\t\t{\n\t\t\t\txpath_lexer_string name = _lexer.contents();\n\n\t\t\t\tif (!_variables)\n\t\t\t\t\treturn error(\"Unknown variable: variable set is not provided\");\n\n\t\t\t\txpath_variable* var = NULL;\n\t\t\t\tif (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))\n\t\t\t\t\treturn error_oom();\n\n\t\t\t\tif (!var)\n\t\t\t\t\treturn error(\"Unknown variable: variable set does not contain the given name\");\n\n\t\t\t\t_lexer.next();\n\n\t\t\t\treturn alloc_node(ast_variable, var->type(), var);\n\t\t\t}\n\n\t\t\tcase lex_open_brace:\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\txpath_ast_node* n = parse_expression();\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\tif (_lexer.current() != lex_close_brace)\n\t\t\t\t\treturn error(\"Expected ')' to match an opening '('\");\n\n\t\t\t\t_lexer.next();\n\n\t\t\t\treturn n;\n\t\t\t}\n\n\t\t\tcase lex_quoted_string:\n\t\t\t{\n\t\t\t\tconst char_t* value = alloc_string(_lexer.contents());\n\t\t\t\tif (!value) return NULL;\n\n\t\t\t\t_lexer.next();\n\n\t\t\t\treturn alloc_node(ast_string_constant, xpath_type_string, value);\n\t\t\t}\n\n\t\t\tcase lex_number:\n\t\t\t{\n\t\t\t\tdouble value = 0;\n\n\t\t\t\tif (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value))\n\t\t\t\t\treturn error_oom();\n\n\t\t\t\t_lexer.next();\n\n\t\t\t\treturn alloc_node(ast_number_constant, xpath_type_number, value);\n\t\t\t}\n\n\t\t\tcase lex_string:\n\t\t\t{\n\t\t\t\txpath_ast_node* args[2] = {NULL};\n\t\t\t\tsize_t argc = 0;\n\n\t\t\t\txpath_lexer_string function = _lexer.contents();\n\t\t\t\t_lexer.next();\n\n\t\t\t\txpath_ast_node* last_arg = NULL;\n\n\t\t\t\tif (_lexer.current() != lex_open_brace)\n\t\t\t\t\treturn error(\"Unrecognized function call\");\n\t\t\t\t_lexer.next();\n\n\t\t\t\tsize_t old_depth = _depth;\n\n\t\t\t\twhile (_lexer.current() != lex_close_brace)\n\t\t\t\t{\n\t\t\t\t\tif (argc > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (_lexer.current() != lex_comma)\n\t\t\t\t\t\t\treturn error(\"No comma between function arguments\");\n\t\t\t\t\t\t_lexer.next();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\t\t\treturn error_rec();\n\n\t\t\t\t\txpath_ast_node* n = parse_expression();\n\t\t\t\t\tif (!n) return NULL;\n\n\t\t\t\t\tif (argc < 2) args[argc] = n;\n\t\t\t\t\telse last_arg->set_next(n);\n\n\t\t\t\t\targc++;\n\t\t\t\t\tlast_arg = n;\n\t\t\t\t}\n\n\t\t\t\t_lexer.next();\n\n\t\t\t\t_depth = old_depth;\n\n\t\t\t\treturn parse_function(function, argc, args);\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn error(\"Unrecognizable primary expression\");\n\t\t\t}\n\t\t}\n\n\t\t// FilterExpr ::= PrimaryExpr | FilterExpr Predicate\n\t\t// Predicate ::= '[' PredicateExpr ']'\n\t\t// PredicateExpr ::= Expr\n\t\txpath_ast_node* parse_filter_expression()\n\t\t{\n\t\t\txpath_ast_node* n = parse_primary_expression();\n\t\t\tif (!n) return NULL;\n\n\t\t\tsize_t old_depth = _depth;\n\n\t\t\twhile (_lexer.current() == lex_open_square_brace)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\t\treturn error_rec();\n\n\t\t\t\tif (n->rettype() != xpath_type_node_set)\n\t\t\t\t\treturn error(\"Predicate has to be applied to node set\");\n\n\t\t\t\txpath_ast_node* expr = parse_expression();\n\t\t\t\tif (!expr) return NULL;\n\n\t\t\t\tn = alloc_node(ast_filter, n, expr, predicate_default);\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\tif (_lexer.current() != lex_close_square_brace)\n\t\t\t\t\treturn error(\"Expected ']' to match an opening '['\");\n\n\t\t\t\t_lexer.next();\n\t\t\t}\n\n\t\t\t_depth = old_depth;\n\n\t\t\treturn n;\n\t\t}\n\n\t\t// Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep\n\t\t// AxisSpecifier ::= AxisName '::' | '@'?\n\t\t// NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'\n\t\t// NameTest ::= '*' | NCName ':' '*' | QName\n\t\t// AbbreviatedStep ::= '.' | '..'\n\t\txpath_ast_node* parse_step(xpath_ast_node* set)\n\t\t{\n\t\t\tif (set && set->rettype() != xpath_type_node_set)\n\t\t\t\treturn error(\"Step has to be applied to node set\");\n\n\t\t\tbool axis_specified = false;\n\t\t\taxis_t axis = axis_child; // implied child axis\n\n\t\t\tif (_lexer.current() == lex_axis_attribute)\n\t\t\t{\n\t\t\t\taxis = axis_attribute;\n\t\t\t\taxis_specified = true;\n\n\t\t\t\t_lexer.next();\n\t\t\t}\n\t\t\telse if (_lexer.current() == lex_dot)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (_lexer.current() == lex_open_square_brace)\n\t\t\t\t\treturn error(\"Predicates are not allowed after an abbreviated step\");\n\n\t\t\t\treturn alloc_node(ast_step, set, axis_self, nodetest_type_node, NULL);\n\t\t\t}\n\t\t\telse if (_lexer.current() == lex_double_dot)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (_lexer.current() == lex_open_square_brace)\n\t\t\t\t\treturn error(\"Predicates are not allowed after an abbreviated step\");\n\n\t\t\t\treturn alloc_node(ast_step, set, axis_parent, nodetest_type_node, NULL);\n\t\t\t}\n\n\t\t\tnodetest_t nt_type = nodetest_none;\n\t\t\txpath_lexer_string nt_name;\n\n\t\t\tif (_lexer.current() == lex_string)\n\t\t\t{\n\t\t\t\t// node name test\n\t\t\t\tnt_name = _lexer.contents();\n\t\t\t\t_lexer.next();\n\n\t\t\t\t// was it an axis name?\n\t\t\t\tif (_lexer.current() == lex_double_colon)\n\t\t\t\t{\n\t\t\t\t\t// parse axis name\n\t\t\t\t\tif (axis_specified)\n\t\t\t\t\t\treturn error(\"Two axis specifiers in one step\");\n\n\t\t\t\t\taxis = parse_axis_name(nt_name, axis_specified);\n\n\t\t\t\t\tif (!axis_specified)\n\t\t\t\t\t\treturn error(\"Unknown axis\");\n\n\t\t\t\t\t// read actual node test\n\t\t\t\t\t_lexer.next();\n\n\t\t\t\t\tif (_lexer.current() == lex_multiply)\n\t\t\t\t\t{\n\t\t\t\t\t\tnt_type = nodetest_all;\n\t\t\t\t\t\tnt_name = xpath_lexer_string();\n\t\t\t\t\t\t_lexer.next();\n\t\t\t\t\t}\n\t\t\t\t\telse if (_lexer.current() == lex_string)\n\t\t\t\t\t{\n\t\t\t\t\t\tnt_name = _lexer.contents();\n\t\t\t\t\t\t_lexer.next();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\treturn error(\"Unrecognized node test\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (nt_type == nodetest_none)\n\t\t\t\t{\n\t\t\t\t\t// node type test or processing-instruction\n\t\t\t\t\tif (_lexer.current() == lex_open_brace)\n\t\t\t\t\t{\n\t\t\t\t\t\t_lexer.next();\n\n\t\t\t\t\t\tif (_lexer.current() == lex_close_brace)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_lexer.next();\n\n\t\t\t\t\t\t\tnt_type = parse_node_test_type(nt_name);\n\n\t\t\t\t\t\t\tif (nt_type == nodetest_none)\n\t\t\t\t\t\t\t\treturn error(\"Unrecognized node type\");\n\n\t\t\t\t\t\t\tnt_name = xpath_lexer_string();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (nt_name == PUGIXML_TEXT(\"processing-instruction\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (_lexer.current() != lex_quoted_string)\n\t\t\t\t\t\t\t\treturn error(\"Only literals are allowed as arguments to processing-instruction()\");\n\n\t\t\t\t\t\t\tnt_type = nodetest_pi;\n\t\t\t\t\t\t\tnt_name = _lexer.contents();\n\t\t\t\t\t\t\t_lexer.next();\n\n\t\t\t\t\t\t\tif (_lexer.current() != lex_close_brace)\n\t\t\t\t\t\t\t\treturn error(\"Unmatched brace near processing-instruction()\");\n\t\t\t\t\t\t\t_lexer.next();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn error(\"Unmatched brace near node type test\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// QName or NCName:*\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnt_name.end--; // erase *\n\n\t\t\t\t\t\t\tnt_type = nodetest_all_in_namespace;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnt_type = nodetest_name;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (_lexer.current() == lex_multiply)\n\t\t\t{\n\t\t\t\tnt_type = nodetest_all;\n\t\t\t\t_lexer.next();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn error(\"Unrecognized node test\");\n\t\t\t}\n\n\t\t\tconst char_t* nt_name_copy = alloc_string(nt_name);\n\t\t\tif (!nt_name_copy) return NULL;\n\n\t\t\txpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy);\n\t\t\tif (!n) return NULL;\n\n\t\t\tsize_t old_depth = _depth;\n\n\t\t\txpath_ast_node* last = NULL;\n\n\t\t\twhile (_lexer.current() == lex_open_square_brace)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\t\treturn error_rec();\n\n\t\t\t\txpath_ast_node* expr = parse_expression();\n\t\t\t\tif (!expr) return NULL;\n\n\t\t\t\txpath_ast_node* pred = alloc_node(ast_predicate, NULL, expr, predicate_default);\n\t\t\t\tif (!pred) return NULL;\n\n\t\t\t\tif (_lexer.current() != lex_close_square_brace)\n\t\t\t\t\treturn error(\"Expected ']' to match an opening '['\");\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (last) last->set_next(pred);\n\t\t\t\telse n->set_right(pred);\n\n\t\t\t\tlast = pred;\n\t\t\t}\n\n\t\t\t_depth = old_depth;\n\n\t\t\treturn n;\n\t\t}\n\n\t\t// RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step\n\t\txpath_ast_node* parse_relative_location_path(xpath_ast_node* set)\n\t\t{\n\t\t\txpath_ast_node* n = parse_step(set);\n\t\t\tif (!n) return NULL;\n\n\t\t\tsize_t old_depth = _depth;\n\n\t\t\twhile (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)\n\t\t\t{\n\t\t\t\tlexeme_t l = _lexer.current();\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (l == lex_double_slash)\n\t\t\t\t{\n\t\t\t\t\tn = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL);\n\t\t\t\t\tif (!n) return NULL;\n\n\t\t\t\t\t++_depth;\n\t\t\t\t}\n\n\t\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\t\treturn error_rec();\n\n\t\t\t\tn = parse_step(n);\n\t\t\t\tif (!n) return NULL;\n\t\t\t}\n\n\t\t\t_depth = old_depth;\n\n\t\t\treturn n;\n\t\t}\n\n\t\t// LocationPath ::= RelativeLocationPath | AbsoluteLocationPath\n\t\t// AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath\n\t\txpath_ast_node* parse_location_path()\n\t\t{\n\t\t\tif (_lexer.current() == lex_slash)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\txpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\t// relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path\n\t\t\t\tlexeme_t l = _lexer.current();\n\n\t\t\t\tif (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)\n\t\t\t\t\treturn parse_relative_location_path(n);\n\t\t\t\telse\n\t\t\t\t\treturn n;\n\t\t\t}\n\t\t\telse if (_lexer.current() == lex_double_slash)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\txpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\tn = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL);\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\treturn parse_relative_location_path(n);\n\t\t\t}\n\n\t\t\t// else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1\n\t\t\treturn parse_relative_location_path(NULL);\n\t\t}\n\n\t\t// PathExpr ::= LocationPath\n\t\t//\t\t\t\t| FilterExpr\n\t\t//\t\t\t\t| FilterExpr '/' RelativeLocationPath\n\t\t//\t\t\t\t| FilterExpr '//' RelativeLocationPath\n\t\t// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr\n\t\t// UnaryExpr ::= UnionExpr | '-' UnaryExpr\n\t\txpath_ast_node* parse_path_or_unary_expression()\n\t\t{\n\t\t\t// Clarification.\n\t\t\t// PathExpr begins with either LocationPath or FilterExpr.\n\t\t\t// FilterExpr begins with PrimaryExpr\n\t\t\t// PrimaryExpr begins with '$' in case of it being a variable reference,\n\t\t\t// '(' in case of it being an expression, string literal, number constant or\n\t\t\t// function call.\n\t\t\tif (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||\n\t\t\t\t_lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||\n\t\t\t\t_lexer.current() == lex_string)\n\t\t\t{\n\t\t\t\tif (_lexer.current() == lex_string)\n\t\t\t\t{\n\t\t\t\t\t// This is either a function call, or not - if not, we shall proceed with location path\n\t\t\t\t\tconst char_t* state = _lexer.state();\n\n\t\t\t\t\twhile (PUGI_IMPL_IS_CHARTYPE(*state, ct_space)) ++state;\n\n\t\t\t\t\tif (*state != '(')\n\t\t\t\t\t\treturn parse_location_path();\n\n\t\t\t\t\t// This looks like a function call; however this still can be a node-test. Check it.\n\t\t\t\t\tif (parse_node_test_type(_lexer.contents()) != nodetest_none)\n\t\t\t\t\t\treturn parse_location_path();\n\t\t\t\t}\n\n\t\t\t\txpath_ast_node* n = parse_filter_expression();\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\tif (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)\n\t\t\t\t{\n\t\t\t\t\tlexeme_t l = _lexer.current();\n\t\t\t\t\t_lexer.next();\n\n\t\t\t\t\tif (l == lex_double_slash)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (n->rettype() != xpath_type_node_set)\n\t\t\t\t\t\t\treturn error(\"Step has to be applied to node set\");\n\n\t\t\t\t\t\tn = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, NULL);\n\t\t\t\t\t\tif (!n) return NULL;\n\t\t\t\t\t}\n\n\t\t\t\t\t// select from location path\n\t\t\t\t\treturn parse_relative_location_path(n);\n\t\t\t\t}\n\n\t\t\t\treturn n;\n\t\t\t}\n\t\t\telse if (_lexer.current() == lex_minus)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\t// precedence 7+ - only parses union expressions\n\t\t\t\txpath_ast_node* n = parse_expression(7);\n\t\t\t\tif (!n) return NULL;\n\n\t\t\t\treturn alloc_node(ast_op_negate, xpath_type_number, n);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn parse_location_path();\n\t\t\t}\n\t\t}\n\n\t\tstruct binary_op_t\n\t\t{\n\t\t\tast_type_t asttype;\n\t\t\txpath_value_type rettype;\n\t\t\tint precedence;\n\n\t\t\tbinary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0)\n\t\t\t{\n\t\t\t}\n\n\t\t\tbinary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)\n\t\t\t{\n\t\t\t}\n\n\t\t\tstatic binary_op_t parse(xpath_lexer& lexer)\n\t\t\t{\n\t\t\t\tswitch (lexer.current())\n\t\t\t\t{\n\t\t\t\tcase lex_string:\n\t\t\t\t\tif (lexer.contents() == PUGIXML_TEXT(\"or\"))\n\t\t\t\t\t\treturn binary_op_t(ast_op_or, xpath_type_boolean, 1);\n\t\t\t\t\telse if (lexer.contents() == PUGIXML_TEXT(\"and\"))\n\t\t\t\t\t\treturn binary_op_t(ast_op_and, xpath_type_boolean, 2);\n\t\t\t\t\telse if (lexer.contents() == PUGIXML_TEXT(\"div\"))\n\t\t\t\t\t\treturn binary_op_t(ast_op_divide, xpath_type_number, 6);\n\t\t\t\t\telse if (lexer.contents() == PUGIXML_TEXT(\"mod\"))\n\t\t\t\t\t\treturn binary_op_t(ast_op_mod, xpath_type_number, 6);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn binary_op_t();\n\n\t\t\t\tcase lex_equal:\n\t\t\t\t\treturn binary_op_t(ast_op_equal, xpath_type_boolean, 3);\n\n\t\t\t\tcase lex_not_equal:\n\t\t\t\t\treturn binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);\n\n\t\t\t\tcase lex_less:\n\t\t\t\t\treturn binary_op_t(ast_op_less, xpath_type_boolean, 4);\n\n\t\t\t\tcase lex_greater:\n\t\t\t\t\treturn binary_op_t(ast_op_greater, xpath_type_boolean, 4);\n\n\t\t\t\tcase lex_less_or_equal:\n\t\t\t\t\treturn binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);\n\n\t\t\t\tcase lex_greater_or_equal:\n\t\t\t\t\treturn binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);\n\n\t\t\t\tcase lex_plus:\n\t\t\t\t\treturn binary_op_t(ast_op_add, xpath_type_number, 5);\n\n\t\t\t\tcase lex_minus:\n\t\t\t\t\treturn binary_op_t(ast_op_subtract, xpath_type_number, 5);\n\n\t\t\t\tcase lex_multiply:\n\t\t\t\t\treturn binary_op_t(ast_op_multiply, xpath_type_number, 6);\n\n\t\t\t\tcase lex_union:\n\t\t\t\t\treturn binary_op_t(ast_op_union, xpath_type_node_set, 7);\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn binary_op_t();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\txpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit)\n\t\t{\n\t\t\tbinary_op_t op = binary_op_t::parse(_lexer);\n\n\t\t\twhile (op.asttype != ast_unknown && op.precedence >= limit)\n\t\t\t{\n\t\t\t\t_lexer.next();\n\n\t\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\t\treturn error_rec();\n\n\t\t\t\txpath_ast_node* rhs = parse_path_or_unary_expression();\n\t\t\t\tif (!rhs) return NULL;\n\n\t\t\t\tbinary_op_t nextop = binary_op_t::parse(_lexer);\n\n\t\t\t\twhile (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)\n\t\t\t\t{\n\t\t\t\t\trhs = parse_expression_rec(rhs, nextop.precedence);\n\t\t\t\t\tif (!rhs) return NULL;\n\n\t\t\t\t\tnextop = binary_op_t::parse(_lexer);\n\t\t\t\t}\n\n\t\t\t\tif (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))\n\t\t\t\t\treturn error(\"Union operator has to be applied to node sets\");\n\n\t\t\t\tlhs = alloc_node(op.asttype, op.rettype, lhs, rhs);\n\t\t\t\tif (!lhs) return NULL;\n\n\t\t\t\top = binary_op_t::parse(_lexer);\n\t\t\t}\n\n\t\t\treturn lhs;\n\t\t}\n\n\t\t// Expr ::= OrExpr\n\t\t// OrExpr ::= AndExpr | OrExpr 'or' AndExpr\n\t\t// AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr\n\t\t// EqualityExpr ::= RelationalExpr\n\t\t//\t\t\t\t\t| EqualityExpr '=' RelationalExpr\n\t\t//\t\t\t\t\t| EqualityExpr '!=' RelationalExpr\n\t\t// RelationalExpr ::= AdditiveExpr\n\t\t//\t\t\t\t\t  | RelationalExpr '<' AdditiveExpr\n\t\t//\t\t\t\t\t  | RelationalExpr '>' AdditiveExpr\n\t\t//\t\t\t\t\t  | RelationalExpr '<=' AdditiveExpr\n\t\t//\t\t\t\t\t  | RelationalExpr '>=' AdditiveExpr\n\t\t// AdditiveExpr ::= MultiplicativeExpr\n\t\t//\t\t\t\t\t| AdditiveExpr '+' MultiplicativeExpr\n\t\t//\t\t\t\t\t| AdditiveExpr '-' MultiplicativeExpr\n\t\t// MultiplicativeExpr ::= UnaryExpr\n\t\t//\t\t\t\t\t\t  | MultiplicativeExpr '*' UnaryExpr\n\t\t//\t\t\t\t\t\t  | MultiplicativeExpr 'div' UnaryExpr\n\t\t//\t\t\t\t\t\t  | MultiplicativeExpr 'mod' UnaryExpr\n\t\txpath_ast_node* parse_expression(int limit = 0)\n\t\t{\n\t\t\tsize_t old_depth = _depth;\n\n\t\t\tif (++_depth > xpath_ast_depth_limit)\n\t\t\t\treturn error_rec();\n\n\t\t\txpath_ast_node* n = parse_path_or_unary_expression();\n\t\t\tif (!n) return NULL;\n\n\t\t\tn = parse_expression_rec(n, limit);\n\n\t\t\t_depth = old_depth;\n\n\t\t\treturn n;\n\t\t}\n\n\t\txpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result), _depth(0)\n\t\t{\n\t\t}\n\n\t\txpath_ast_node* parse()\n\t\t{\n\t\t\txpath_ast_node* n = parse_expression();\n\t\t\tif (!n) return NULL;\n\n\t\t\tassert(_depth == 0);\n\n\t\t\t// check if there are unparsed tokens left\n\t\t\tif (_lexer.current() != lex_eof)\n\t\t\t\treturn error(\"Incorrect query\");\n\n\t\t\treturn n;\n\t\t}\n\n\t\tstatic xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)\n\t\t{\n\t\t\txpath_parser parser(query, variables, alloc, result);\n\n\t\t\treturn parser.parse();\n\t\t}\n\t};\n\n\tstruct xpath_query_impl\n\t{\n\t\tstatic xpath_query_impl* create()\n\t\t{\n\t\t\tvoid* memory = xml_memory::allocate(sizeof(xpath_query_impl));\n\t\t\tif (!memory) return NULL;\n\n\t\t\treturn new (memory) xpath_query_impl();\n\t\t}\n\n\t\tstatic void destroy(xpath_query_impl* impl)\n\t\t{\n\t\t\t// free all allocated pages\n\t\t\timpl->alloc.release();\n\n\t\t\t// free allocator memory (with the first page)\n\t\t\txml_memory::deallocate(impl);\n\t\t}\n\n\t\txpath_query_impl(): root(NULL), alloc(&block, &oom), oom(false)\n\t\t{\n\t\t\tblock.next = NULL;\n\t\t\tblock.capacity = sizeof(block.data);\n\t\t}\n\n\t\txpath_ast_node* root;\n\t\txpath_allocator alloc;\n\t\txpath_memory_block block;\n\t\tbool oom;\n\t};\n\n\tPUGI_IMPL_FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)\n\t{\n\t\tif (!impl) return NULL;\n\n\t\tif (impl->root->rettype() != xpath_type_node_set)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn 0;\n\t\t#else\n\t\t\txpath_parse_result res;\n\t\t\tres.error = \"Expression does not evaluate to node set\";\n\n\t\t\tthrow xpath_exception(res);\n\t\t#endif\n\t\t}\n\n\t\treturn impl->root;\n\t}\nPUGI_IMPL_NS_END\n\nnamespace pugi\n{\n#ifndef PUGIXML_NO_EXCEPTIONS\n\tPUGI_IMPL_FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)\n\t{\n\t\tassert(_result.error);\n\t}\n\n\tPUGI_IMPL_FN const char* xpath_exception::what() const PUGIXML_NOEXCEPT\n\t{\n\t\treturn _result.error;\n\t}\n\n\tPUGI_IMPL_FN const xpath_parse_result& xpath_exception::result() const\n\t{\n\t\treturn _result;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xpath_node::xpath_node()\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_node::xpath_node(const xml_node& node_): _node(node_)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xml_node xpath_node::node() const\n\t{\n\t\treturn _attribute ? xml_node() : _node;\n\t}\n\n\tPUGI_IMPL_FN xml_attribute xpath_node::attribute() const\n\t{\n\t\treturn _attribute;\n\t}\n\n\tPUGI_IMPL_FN xml_node xpath_node::parent() const\n\t{\n\t\treturn _attribute ? _node : _node.parent();\n\t}\n\n\tPUGI_IMPL_FN static void unspecified_bool_xpath_node(xpath_node***)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_node::operator xpath_node::unspecified_bool_type() const\n\t{\n\t\treturn (_node || _attribute) ? unspecified_bool_xpath_node : NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_node::operator!() const\n\t{\n\t\treturn !(_node || _attribute);\n\t}\n\n\tPUGI_IMPL_FN bool xpath_node::operator==(const xpath_node& n) const\n\t{\n\t\treturn _node == n._node && _attribute == n._attribute;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_node::operator!=(const xpath_node& n) const\n\t{\n\t\treturn _node != n._node || _attribute != n._attribute;\n\t}\n\n#ifdef __BORLANDC__\n\tPUGI_IMPL_FN bool operator&&(const xpath_node& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs && rhs;\n\t}\n\n\tPUGI_IMPL_FN bool operator||(const xpath_node& lhs, bool rhs)\n\t{\n\t\treturn (bool)lhs || rhs;\n\t}\n#endif\n\n\tPUGI_IMPL_FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)\n\t{\n\t\tassert(begin_ <= end_);\n\n\t\tsize_t size_ = static_cast<size_t>(end_ - begin_);\n\n\t\t// use internal buffer for 0 or 1 elements, heap buffer otherwise\n\t\txpath_node* storage = (size_ <= 1) ? _storage : static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));\n\n\t\tif (!storage)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn;\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\t// deallocate old buffer\n\t\tif (_begin != _storage)\n\t\t\timpl::xml_memory::deallocate(_begin);\n\n\t\t// size check is necessary because for begin_ = end_ = nullptr, memcpy is UB\n\t\tif (size_)\n\t\t\tmemcpy(storage, begin_, size_ * sizeof(xpath_node));\n\n\t\t_begin = storage;\n\t\t_end = storage + size_;\n\t\t_type = type_;\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\t_type = rhs._type;\n\t\t_storage[0] = rhs._storage[0];\n\t\t_begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin;\n\t\t_end = _begin + (rhs._end - rhs._begin);\n\n\t\trhs._type = type_unsorted;\n\t\trhs._begin = rhs._storage;\n\t\trhs._end = rhs._storage;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)\n\t{\n\t\t_assign(begin_, end_, type_);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::~xpath_node_set()\n\t{\n\t\tif (_begin != _storage)\n\t\t\timpl::xml_memory::deallocate(_begin);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)\n\t{\n\t\t_assign(ns._begin, ns._end, ns._type);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)\n\t{\n\t\tif (this == &ns) return *this;\n\n\t\t_assign(ns._begin, ns._end, ns._type);\n\n\t\treturn *this;\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)\n\t{\n\t\t_move(rhs);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\tif (this == &rhs) return *this;\n\n\t\tif (_begin != _storage)\n\t\t\timpl::xml_memory::deallocate(_begin);\n\n\t\t_move(rhs);\n\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xpath_node_set::type_t xpath_node_set::type() const\n\t{\n\t\treturn _type;\n\t}\n\n\tPUGI_IMPL_FN size_t xpath_node_set::size() const\n\t{\n\t\treturn _end - _begin;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_node_set::empty() const\n\t{\n\t\treturn _begin == _end;\n\t}\n\n\tPUGI_IMPL_FN const xpath_node& xpath_node_set::operator[](size_t index) const\n\t{\n\t\tassert(index < size());\n\t\treturn _begin[index];\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::begin() const\n\t{\n\t\treturn _begin;\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::end() const\n\t{\n\t\treturn _end;\n\t}\n\n\tPUGI_IMPL_FN void xpath_node_set::sort(bool reverse)\n\t{\n\t\t_type = impl::xpath_sort(_begin, _end, _type, reverse);\n\t}\n\n\tPUGI_IMPL_FN xpath_node xpath_node_set::first() const\n\t{\n\t\treturn impl::xpath_first(_begin, _end, _type);\n\t}\n\n\tPUGI_IMPL_FN xpath_parse_result::xpath_parse_result(): error(\"Internal error\"), offset(0)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_parse_result::operator bool() const\n\t{\n\t\treturn error == NULL;\n\t}\n\n\tPUGI_IMPL_FN const char* xpath_parse_result::description() const\n\t{\n\t\treturn error ? error : \"No error\";\n\t}\n\n\tPUGI_IMPL_FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN const char_t* xpath_variable::name() const\n\t{\n\t\tswitch (_type)\n\t\t{\n\t\tcase xpath_type_node_set:\n\t\t\treturn static_cast<const impl::xpath_variable_node_set*>(this)->name;\n\n\t\tcase xpath_type_number:\n\t\t\treturn static_cast<const impl::xpath_variable_number*>(this)->name;\n\n\t\tcase xpath_type_string:\n\t\t\treturn static_cast<const impl::xpath_variable_string*>(this)->name;\n\n\t\tcase xpath_type_boolean:\n\t\t\treturn static_cast<const impl::xpath_variable_boolean*>(this)->name;\n\n\t\tdefault:\n\t\t\tassert(false && \"Invalid variable type\"); // unreachable\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xpath_value_type xpath_variable::type() const\n\t{\n\t\treturn _type;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable::get_boolean() const\n\t{\n\t\treturn (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;\n\t}\n\n\tPUGI_IMPL_FN double xpath_variable::get_number() const\n\t{\n\t\treturn (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();\n\t}\n\n\tPUGI_IMPL_FN const char_t* xpath_variable::get_string() const\n\t{\n\t\tconst char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : NULL;\n\t\treturn value ? value : PUGIXML_TEXT(\"\");\n\t}\n\n\tPUGI_IMPL_FN const xpath_node_set& xpath_variable::get_node_set() const\n\t{\n\t\treturn (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable::set(bool value)\n\t{\n\t\tif (_type != xpath_type_boolean) return false;\n\n\t\tstatic_cast<impl::xpath_variable_boolean*>(this)->value = value;\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable::set(double value)\n\t{\n\t\tif (_type != xpath_type_number) return false;\n\n\t\tstatic_cast<impl::xpath_variable_number*>(this)->value = value;\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable::set(const char_t* value)\n\t{\n\t\tif (_type != xpath_type_string) return false;\n\n\t\timpl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);\n\n\t\t// duplicate string\n\t\tsize_t size = (impl::strlength(value) + 1) * sizeof(char_t);\n\n\t\tchar_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));\n\t\tif (!copy) return false;\n\n\t\tmemcpy(copy, value, size);\n\n\t\t// replace old string\n\t\tif (var->value) impl::xml_memory::deallocate(var->value);\n\t\tvar->value = copy;\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable::set(const xpath_node_set& value)\n\t{\n\t\tif (_type != xpath_type_node_set) return false;\n\n\t\tstatic_cast<impl::xpath_variable_node_set*>(this)->value = value;\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN xpath_variable_set::xpath_variable_set()\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t\t_data[i] = NULL;\n\t}\n\n\tPUGI_IMPL_FN xpath_variable_set::~xpath_variable_set()\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t\t_destroy(_data[i]);\n\t}\n\n\tPUGI_IMPL_FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t\t_data[i] = NULL;\n\n\t\t_assign(rhs);\n\t}\n\n\tPUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)\n\t{\n\t\tif (this == &rhs) return *this;\n\n\t\t_assign(rhs);\n\n\t\treturn *this;\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t{\n\t\t\t_data[i] = rhs._data[i];\n\t\t\trhs._data[i] = NULL;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t{\n\t\t\t_destroy(_data[i]);\n\n\t\t\t_data[i] = rhs._data[i];\n\t\t\trhs._data[i] = NULL;\n\t\t}\n\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)\n\t{\n\t\txpath_variable_set temp;\n\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t\tif (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))\n\t\t\t\treturn;\n\n\t\t_swap(temp);\n\t}\n\n\tPUGI_IMPL_FN void xpath_variable_set::_swap(xpath_variable_set& rhs)\n\t{\n\t\tfor (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)\n\t\t{\n\t\t\txpath_variable* chain = _data[i];\n\n\t\t\t_data[i] = rhs._data[i];\n\t\t\trhs._data[i] = chain;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xpath_variable* xpath_variable_set::_find(const char_t* name) const\n\t{\n\t\tconst size_t hash_size = sizeof(_data) / sizeof(_data[0]);\n\t\tsize_t hash = impl::hash_string(name) % hash_size;\n\n\t\t// look for existing variable\n\t\tfor (xpath_variable* var = _data[hash]; var; var = var->_next)\n\t\t\tif (impl::strequal(var->name(), name))\n\t\t\t\treturn var;\n\n\t\treturn NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)\n\t{\n\t\txpath_variable* last = NULL;\n\n\t\twhile (var)\n\t\t{\n\t\t\t// allocate storage for new variable\n\t\t\txpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());\n\t\t\tif (!nvar) return false;\n\n\t\t\t// link the variable to the result immediately to handle failures gracefully\n\t\t\tif (last)\n\t\t\t\tlast->_next = nvar;\n\t\t\telse\n\t\t\t\t*out_result = nvar;\n\n\t\t\tlast = nvar;\n\n\t\t\t// copy the value; this can fail due to out-of-memory conditions\n\t\t\tif (!impl::copy_xpath_variable(nvar, var)) return false;\n\n\t\t\tvar = var->_next;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tPUGI_IMPL_FN void xpath_variable_set::_destroy(xpath_variable* var)\n\t{\n\t\twhile (var)\n\t\t{\n\t\t\txpath_variable* next = var->_next;\n\n\t\t\timpl::delete_xpath_variable(var->_type, var);\n\n\t\t\tvar = next;\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)\n\t{\n\t\tconst size_t hash_size = sizeof(_data) / sizeof(_data[0]);\n\t\tsize_t hash = impl::hash_string(name) % hash_size;\n\n\t\t// look for existing variable\n\t\tfor (xpath_variable* var = _data[hash]; var; var = var->_next)\n\t\t\tif (impl::strequal(var->name(), name))\n\t\t\t\treturn var->type() == type ? var : NULL;\n\n\t\t// add new variable\n\t\txpath_variable* result = impl::new_xpath_variable(type, name);\n\n\t\tif (result)\n\t\t{\n\t\t\tresult->_next = _data[hash];\n\n\t\t\t_data[hash] = result;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, bool value)\n\t{\n\t\txpath_variable* var = add(name, xpath_type_boolean);\n\t\treturn var ? var->set(value) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, double value)\n\t{\n\t\txpath_variable* var = add(name, xpath_type_number);\n\t\treturn var ? var->set(value) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const char_t* value)\n\t{\n\t\txpath_variable* var = add(name, xpath_type_string);\n\t\treturn var ? var->set(value) : false;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)\n\t{\n\t\txpath_variable* var = add(name, xpath_type_node_set);\n\t\treturn var ? var->set(value) : false;\n\t}\n\n\tPUGI_IMPL_FN xpath_variable* xpath_variable_set::get(const char_t* name)\n\t{\n\t\treturn _find(name);\n\t}\n\n\tPUGI_IMPL_FN const xpath_variable* xpath_variable_set::get(const char_t* name) const\n\t{\n\t\treturn _find(name);\n\t}\n\n\tPUGI_IMPL_FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(NULL)\n\t{\n\t\timpl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();\n\n\t\tif (!qimpl)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\t_result.error = \"Out of memory\";\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\t\telse\n\t\t{\n\t\t\tusing impl::auto_deleter; // MSVC7 workaround\n\t\t\tauto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);\n\n\t\t\tqimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);\n\n\t\t\tif (qimpl->root)\n\t\t\t{\n\t\t\t\tqimpl->root->optimize(&qimpl->alloc);\n\n\t\t\t\t_impl = impl.release();\n\t\t\t\t_result.error = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\t\tif (qimpl->oom) _result.error = \"Out of memory\";\n\t\t\t#else\n\t\t\t\tif (qimpl->oom) throw std::bad_alloc();\n\t\t\t\tthrow xpath_exception(_result);\n\t\t\t#endif\n\t\t\t}\n\t\t}\n\t}\n\n\tPUGI_IMPL_FN xpath_query::xpath_query(): _impl(NULL)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_query::~xpath_query()\n\t{\n\t\tif (_impl)\n\t\t\timpl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));\n\t}\n\n#ifdef PUGIXML_HAS_MOVE\n\tPUGI_IMPL_FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\t_impl = rhs._impl;\n\t\t_result = rhs._result;\n\t\trhs._impl = NULL;\n\t\trhs._result = xpath_parse_result();\n\t}\n\n\tPUGI_IMPL_FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT\n\t{\n\t\tif (this == &rhs) return *this;\n\n\t\tif (_impl)\n\t\t\timpl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));\n\n\t\t_impl = rhs._impl;\n\t\t_result = rhs._result;\n\t\trhs._impl = NULL;\n\t\trhs._result = xpath_parse_result();\n\n\t\treturn *this;\n\t}\n#endif\n\n\tPUGI_IMPL_FN xpath_value_type xpath_query::return_type() const\n\t{\n\t\tif (!_impl) return xpath_type_none;\n\n\t\treturn static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();\n\t}\n\n\tPUGI_IMPL_FN bool xpath_query::evaluate_boolean(const xpath_node& n) const\n\t{\n\t\tif (!_impl) return false;\n\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\tbool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn false;\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\treturn r;\n\t}\n\n\tPUGI_IMPL_FN double xpath_query::evaluate_number(const xpath_node& n) const\n\t{\n\t\tif (!_impl) return impl::gen_nan();\n\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\tdouble r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn impl::gen_nan();\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\treturn r;\n\t}\n\n#ifndef PUGIXML_NO_STL\n\tPUGI_IMPL_FN string_t xpath_query::evaluate_string(const xpath_node& n) const\n\t{\n\t\tif (!_impl) return string_t();\n\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\timpl::xpath_string r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack);\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn string_t();\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\treturn string_t(r.c_str(), r.length());\n\t}\n#endif\n\n\tPUGI_IMPL_FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const\n\t{\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\timpl::xpath_string r = _impl ? static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string();\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\tr = impl::xpath_string();\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\tsize_t full_size = r.length() + 1;\n\n\t\tif (capacity > 0)\n\t\t{\n\t\t\tsize_t size = (full_size < capacity) ? full_size : capacity;\n\t\t\tassert(size > 0);\n\n\t\t\tmemcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));\n\t\t\tbuffer[size - 1] = 0;\n\t\t}\n\n\t\treturn full_size;\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const\n\t{\n\t\timpl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));\n\t\tif (!root) return xpath_node_set();\n\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\timpl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn xpath_node_set();\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\treturn xpath_node_set(r.begin(), r.end(), r.type());\n\t}\n\n\tPUGI_IMPL_FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const\n\t{\n\t\timpl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));\n\t\tif (!root) return xpath_node();\n\n\t\timpl::xpath_context c(n, 1, 1);\n\t\timpl::xpath_stack_data sd;\n\n\t\timpl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);\n\n\t\tif (sd.oom)\n\t\t{\n\t\t#ifdef PUGIXML_NO_EXCEPTIONS\n\t\t\treturn xpath_node();\n\t\t#else\n\t\t\tthrow std::bad_alloc();\n\t\t#endif\n\t\t}\n\n\t\treturn r.first();\n\t}\n\n\tPUGI_IMPL_FN const xpath_parse_result& xpath_query::result() const\n\t{\n\t\treturn _result;\n\t}\n\n\tPUGI_IMPL_FN static void unspecified_bool_xpath_query(xpath_query***)\n\t{\n\t}\n\n\tPUGI_IMPL_FN xpath_query::operator xpath_query::unspecified_bool_type() const\n\t{\n\t\treturn _impl ? unspecified_bool_xpath_query : NULL;\n\t}\n\n\tPUGI_IMPL_FN bool xpath_query::operator!() const\n\t{\n\t\treturn !_impl;\n\t}\n\n\tPUGI_IMPL_FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const\n\t{\n\t\txpath_query q(query, variables);\n\t\treturn q.evaluate_node(*this);\n\t}\n\n\tPUGI_IMPL_FN xpath_node xml_node::select_node(const xpath_query& query) const\n\t{\n\t\treturn query.evaluate_node(*this);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const\n\t{\n\t\txpath_query q(query, variables);\n\t\treturn q.evaluate_node_set(*this);\n\t}\n\n\tPUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const\n\t{\n\t\treturn query.evaluate_node_set(*this);\n\t}\n\n\tPUGI_IMPL_FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const\n\t{\n\t\txpath_query q(query, variables);\n\t\treturn q.evaluate_node(*this);\n\t}\n\n\tPUGI_IMPL_FN xpath_node xml_node::select_single_node(const xpath_query& query) const\n\t{\n\t\treturn query.evaluate_node(*this);\n\t}\n}\n\n#endif\n\n#ifdef __BORLANDC__\n#\tpragma option pop\n#endif\n\n#if defined(_MSC_VER) && defined(__c2__)\n#\tpragma clang diagnostic pop\n#endif\n\n#if defined(__clang__)\n#\tpragma clang diagnostic pop\n#endif\n\n// Intel C++ does not properly keep warning state for function templates,\n// so popping warning state at the end of translation unit leads to warnings in the middle.\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)\n#\tpragma warning(pop)\n#endif\n\n// Undefine all local macros (makes sure we're not leaking macros in header-only mode)\n#undef PUGI_IMPL_NO_INLINE\n#undef PUGI_IMPL_UNLIKELY\n#undef PUGI_IMPL_STATIC_ASSERT\n#undef PUGI_IMPL_DMC_VOLATILE\n#undef PUGI_IMPL_UNSIGNED_OVERFLOW\n#undef PUGI_IMPL_MSVC_CRT_VERSION\n#undef PUGI_IMPL_SNPRINTF\n#undef PUGI_IMPL_NS_BEGIN\n#undef PUGI_IMPL_NS_END\n#undef PUGI_IMPL_FN\n#undef PUGI_IMPL_FN_NO_INLINE\n#undef PUGI_IMPL_GETHEADER_IMPL\n#undef PUGI_IMPL_GETPAGE_IMPL\n#undef PUGI_IMPL_GETPAGE\n#undef PUGI_IMPL_NODETYPE\n#undef PUGI_IMPL_IS_CHARTYPE_IMPL\n#undef PUGI_IMPL_IS_CHARTYPE\n#undef PUGI_IMPL_IS_CHARTYPEX\n#undef PUGI_IMPL_ENDSWITH\n#undef PUGI_IMPL_SKIPWS\n#undef PUGI_IMPL_OPTSET\n#undef PUGI_IMPL_PUSHNODE\n#undef PUGI_IMPL_POPNODE\n#undef PUGI_IMPL_SCANFOR\n#undef PUGI_IMPL_SCANWHILE\n#undef PUGI_IMPL_SCANWHILE_UNROLL\n#undef PUGI_IMPL_ENDSEG\n#undef PUGI_IMPL_THROW_ERROR\n#undef PUGI_IMPL_CHECK_ERROR\n\n#endif\n\n/**\n * Copyright (c) 2006-2025 Arseny Kapoulkine\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without\n * restriction, including without limitation the rights to use,\n * copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */\n"
  },
  {
    "path": "external/pugixml/src/pugixml.hpp",
    "content": "/**\n * pugixml parser - version 1.15\n * --------------------------------------------------------\n * Copyright (C) 2006-2025, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)\n * Report bugs and download new versions at https://pugixml.org/\n *\n * This library is distributed under the MIT License. See notice at the end\n * of this file.\n *\n * This work is based on the pugxml parser, which is:\n * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)\n */\n\n// Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons\n// Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits\n#ifndef PUGIXML_VERSION\n#\tdefine PUGIXML_VERSION 1150 // 1.15\n#endif\n\n// Include user configuration file (this can define various configuration macros)\n#include \"pugiconfig.hpp\"\n\n#ifndef HEADER_PUGIXML_HPP\n#define HEADER_PUGIXML_HPP\n\n// Include stddef.h for size_t and ptrdiff_t\n#include <stddef.h>\n\n// Include exception header for XPath\n#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)\n#\tinclude <exception>\n#endif\n\n// Include STL headers\n#ifndef PUGIXML_NO_STL\n#\tinclude <iterator>\n#\tinclude <iosfwd>\n#\tinclude <string>\n#endif\n\n// Check if std::string_view is available\n#if !defined(PUGIXML_HAS_STRING_VIEW) && !defined(PUGIXML_NO_STL)\n#\tif __cplusplus >= 201703L\n#\t\tdefine PUGIXML_HAS_STRING_VIEW\n#\telif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L\n#\t\tdefine PUGIXML_HAS_STRING_VIEW\n#\tendif\n#endif\n\n// Include string_view if appropriate\n#ifdef PUGIXML_HAS_STRING_VIEW\n#\tinclude <string_view>\n#endif\n\n// Macro for deprecated features\n#ifndef PUGIXML_DEPRECATED\n#\tif defined(__GNUC__)\n#\t\tdefine PUGIXML_DEPRECATED __attribute__((deprecated))\n#\telif defined(_MSC_VER) && _MSC_VER >= 1300\n#\t\tdefine PUGIXML_DEPRECATED __declspec(deprecated)\n#\telse\n#\t\tdefine PUGIXML_DEPRECATED\n#\tendif\n#endif\n\n// If no API is defined, assume default\n#ifndef PUGIXML_API\n#\tdefine PUGIXML_API\n#endif\n\n// If no API for classes is defined, assume default\n#ifndef PUGIXML_CLASS\n#\tdefine PUGIXML_CLASS PUGIXML_API\n#endif\n\n// If no API for functions is defined, assume default\n#ifndef PUGIXML_FUNCTION\n#\tdefine PUGIXML_FUNCTION PUGIXML_API\n#endif\n\n// If the platform is known to have long long support, enable long long functions\n#ifndef PUGIXML_HAS_LONG_LONG\n#\tif __cplusplus >= 201103\n#\t\tdefine PUGIXML_HAS_LONG_LONG\n#\telif defined(_MSC_VER) && _MSC_VER >= 1400\n#\t\tdefine PUGIXML_HAS_LONG_LONG\n#\tendif\n#endif\n\n// If the platform is known to have move semantics support, compile move ctor/operator implementation\n#ifndef PUGIXML_HAS_MOVE\n#\tif __cplusplus >= 201103\n#\t\tdefine PUGIXML_HAS_MOVE\n#\telif defined(_MSC_VER) && _MSC_VER >= 1600\n#\t\tdefine PUGIXML_HAS_MOVE\n#\tendif\n#endif\n\n// If C++ is 2011 or higher, use 'noexcept' specifiers\n#ifndef PUGIXML_NOEXCEPT\n#\tif __cplusplus >= 201103\n#\t\tdefine PUGIXML_NOEXCEPT noexcept\n#\telif defined(_MSC_VER) && _MSC_VER >= 1900\n#\t\tdefine PUGIXML_NOEXCEPT noexcept\n#\telse\n#\t\tdefine PUGIXML_NOEXCEPT throw()\n#\tendif\n#endif\n\n// Some functions can not be noexcept in compact mode\n#ifdef PUGIXML_COMPACT\n#\tdefine PUGIXML_NOEXCEPT_IF_NOT_COMPACT\n#else\n#\tdefine PUGIXML_NOEXCEPT_IF_NOT_COMPACT PUGIXML_NOEXCEPT\n#endif\n\n// If C++ is 2011 or higher, add 'override' qualifiers\n#ifndef PUGIXML_OVERRIDE\n#\tif __cplusplus >= 201103\n#\t\tdefine PUGIXML_OVERRIDE override\n#\telif defined(_MSC_VER) && _MSC_VER >= 1700\n#\t\tdefine PUGIXML_OVERRIDE override\n#\telse\n#\t\tdefine PUGIXML_OVERRIDE\n#\tendif\n#endif\n\n// If C++ is 2011 or higher, use 'nullptr'\n#ifndef PUGIXML_NULL\n#\tif __cplusplus >= 201103\n#\t\tdefine PUGIXML_NULL nullptr\n#\telif defined(_MSC_VER) && _MSC_VER >= 1600\n#\t\tdefine PUGIXML_NULL nullptr\n#\telse\n#\t\tdefine PUGIXML_NULL 0\n#\tendif\n#endif\n\n// Character interface macros\n#ifdef PUGIXML_WCHAR_MODE\n#\tdefine PUGIXML_TEXT(t) L ## t\n#\tdefine PUGIXML_CHAR wchar_t\n#else\n#\tdefine PUGIXML_TEXT(t) t\n#\tdefine PUGIXML_CHAR char\n#endif\n\nnamespace pugi\n{\n\t// Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE\n\ttypedef PUGIXML_CHAR char_t;\n\n#ifndef PUGIXML_NO_STL\n\t// String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE\n\ttypedef std::basic_string<PUGIXML_CHAR> string_t;\n#endif\n\n#ifdef PUGIXML_HAS_STRING_VIEW\n\t// String view type used for operations that can work with a length delimited string; depends on PUGIXML_WCHAR_MODE\n\ttypedef std::basic_string_view<PUGIXML_CHAR> string_view_t;\n#endif\n}\n\n// The PugiXML namespace\nnamespace pugi\n{\n\t// Tree node types\n\tenum xml_node_type\n\t{\n\t\tnode_null,\t\t\t// Empty (null) node handle\n\t\tnode_document,\t\t// A document tree's absolute root\n\t\tnode_element,\t\t// Element tag, i.e. '<node/>'\n\t\tnode_pcdata,\t\t// Plain character data, i.e. 'text'\n\t\tnode_cdata,\t\t\t// Character data, i.e. '<![CDATA[text]]>'\n\t\tnode_comment,\t\t// Comment tag, i.e. '<!-- text -->'\n\t\tnode_pi,\t\t\t// Processing instruction, i.e. '<?name?>'\n\t\tnode_declaration,\t// Document declaration, i.e. '<?xml version=\"1.0\"?>'\n\t\tnode_doctype\t\t// Document type declaration, i.e. '<!DOCTYPE doc>'\n\t};\n\n\t// Parsing options\n\n\t// Minimal parsing mode (equivalent to turning all other flags off).\n\t// Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.\n\tconst unsigned int parse_minimal = 0x0000;\n\n\t// This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default.\n\tconst unsigned int parse_pi = 0x0001;\n\n\t// This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default.\n\tconst unsigned int parse_comments = 0x0002;\n\n\t// This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default.\n\tconst unsigned int parse_cdata = 0x0004;\n\n\t// This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree.\n\t// This flag is off by default; turning it on usually results in slower parsing and more memory consumption.\n\tconst unsigned int parse_ws_pcdata = 0x0008;\n\n\t// This flag determines if character and entity references are expanded during parsing. This flag is on by default.\n\tconst unsigned int parse_escapes = 0x0010;\n\n\t// This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.\n\tconst unsigned int parse_eol = 0x0020;\n\n\t// This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.\n\tconst unsigned int parse_wconv_attribute = 0x0040;\n\n\t// This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.\n\tconst unsigned int parse_wnorm_attribute = 0x0080;\n\n\t// This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.\n\tconst unsigned int parse_declaration = 0x0100;\n\n\t// This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.\n\tconst unsigned int parse_doctype = 0x0200;\n\n\t// This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only\n\t// of whitespace is added to the DOM tree.\n\t// This flag is off by default; turning it on may result in slower parsing and more memory consumption.\n\tconst unsigned int parse_ws_pcdata_single = 0x0400;\n\n\t// This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default.\n\tconst unsigned int parse_trim_pcdata = 0x0800;\n\n\t// This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document\n\t// is a valid document. This flag is off by default.\n\tconst unsigned int parse_fragment = 0x1000;\n\n\t// This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of\n\t// the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments.\n\t// This flag is off by default.\n\tconst unsigned int parse_embed_pcdata = 0x2000;\n\n\t// This flag determines whether determines whether the the two pcdata should be merged or not, if no intermediatory data are parsed in the document.\n\t// This flag is off by default.\n\tconst unsigned int parse_merge_pcdata = 0x4000;\n\n\t// The default parsing mode.\n\t// Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,\n\t// End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.\n\tconst unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;\n\n\t// The full parsing mode.\n\t// Nodes of all types are added to the DOM tree, character/reference entities are expanded,\n\t// End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.\n\tconst unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;\n\n\t// These flags determine the encoding of input data for XML document\n\tenum xml_encoding\n\t{\n\t\tencoding_auto,\t\t// Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found\n\t\tencoding_utf8,\t\t// UTF8 encoding\n\t\tencoding_utf16_le,\t// Little-endian UTF16\n\t\tencoding_utf16_be,\t// Big-endian UTF16\n\t\tencoding_utf16,\t\t// UTF16 with native endianness\n\t\tencoding_utf32_le,\t// Little-endian UTF32\n\t\tencoding_utf32_be,\t// Big-endian UTF32\n\t\tencoding_utf32,\t\t// UTF32 with native endianness\n\t\tencoding_wchar,\t\t// The same encoding wchar_t has (either UTF16 or UTF32)\n\t\tencoding_latin1\n\t};\n\n\t// Formatting flags\n\n\t// Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default.\n\tconst unsigned int format_indent = 0x01;\n\n\t// Write encoding-specific BOM to the output stream. This flag is off by default.\n\tconst unsigned int format_write_bom = 0x02;\n\n\t// Use raw output mode (no indentation and no line breaks are written). This flag is off by default.\n\tconst unsigned int format_raw = 0x04;\n\n\t// Omit default XML declaration even if there is no declaration in the document. This flag is off by default.\n\tconst unsigned int format_no_declaration = 0x08;\n\n\t// Don't escape attribute values and PCDATA contents. This flag is off by default.\n\tconst unsigned int format_no_escapes = 0x10;\n\n\t// Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default.\n\tconst unsigned int format_save_file_text = 0x20;\n\n\t// Write every attribute on a new line with appropriate indentation. This flag is off by default.\n\tconst unsigned int format_indent_attributes = 0x40;\n\n\t// Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default.\n\tconst unsigned int format_no_empty_element_tags = 0x80;\n\n\t// Skip characters belonging to range [0; 32) instead of \"&#xNN;\" encoding. This flag is off by default.\n\tconst unsigned int format_skip_control_chars = 0x100;\n\n\t// Use single quotes ' instead of double quotes \" for enclosing attribute values. This flag is off by default.\n\tconst unsigned int format_attribute_single_quote = 0x200;\n\n\t// The default set of formatting flags.\n\t// Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.\n\tconst unsigned int format_default = format_indent;\n\n\tconst int default_double_precision = 17;\n\tconst int default_float_precision = 9;\n\n\t// Forward declarations\n\tstruct xml_attribute_struct;\n\tstruct xml_node_struct;\n\n\tclass xml_node_iterator;\n\tclass xml_attribute_iterator;\n\tclass xml_named_node_iterator;\n\n\tclass xml_tree_walker;\n\n\tstruct xml_parse_result;\n\n\tclass xml_node;\n\n\tclass xml_text;\n\n\t#ifndef PUGIXML_NO_XPATH\n\tclass xpath_node;\n\tclass xpath_node_set;\n\tclass xpath_query;\n\tclass xpath_variable_set;\n\t#endif\n\n\t// Range-based for loop support\n\ttemplate <typename It> class xml_object_range\n\t{\n\tpublic:\n\t\ttypedef It const_iterator;\n\t\ttypedef It iterator;\n\n\t\txml_object_range(It b, It e): _begin(b), _end(e)\n\t\t{\n\t\t}\n\n\t\tIt begin() const { return _begin; }\n\t\tIt end() const { return _end; }\n\n\t\tbool empty() const { return _begin == _end; }\n\n\tprivate:\n\t\tIt _begin, _end;\n\t};\n\n\t// Writer interface for node printing (see xml_node::print)\n\tclass PUGIXML_CLASS xml_writer\n\t{\n\tpublic:\n\t\tvirtual ~xml_writer();\n\n\t\t// Write memory chunk into stream/file/whatever\n\t\tvirtual void write(const void* data, size_t size) = 0;\n\t};\n\n\t// xml_writer implementation for FILE*\n\tclass PUGIXML_CLASS xml_writer_file: public xml_writer\n\t{\n\tpublic:\n\t\t// Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio\n\t\txml_writer_file(void* file);\n\n\t\tvirtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;\n\n\tprivate:\n\t\tvoid* file;\n\t};\n\n\t#ifndef PUGIXML_NO_STL\n\t// xml_writer implementation for streams\n\tclass PUGIXML_CLASS xml_writer_stream: public xml_writer\n\t{\n\tpublic:\n\t\t// Construct writer from an output stream object\n\t\txml_writer_stream(std::basic_ostream<char>& stream);\n\t\txml_writer_stream(std::basic_ostream<wchar_t>& stream);\n\n\t\tvirtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;\n\n\tprivate:\n\t\tstd::basic_ostream<char>* narrow_stream;\n\t\tstd::basic_ostream<wchar_t>* wide_stream;\n\t};\n\t#endif\n\n\t// A light-weight handle for manipulating attributes in DOM tree\n\tclass PUGIXML_CLASS xml_attribute\n\t{\n\t\tfriend class xml_attribute_iterator;\n\t\tfriend class xml_node;\n\n\tprivate:\n\t\txml_attribute_struct* _attr;\n\n\t\ttypedef void (*unspecified_bool_type)(xml_attribute***);\n\n\tpublic:\n\t\t// Default constructor. Constructs an empty attribute.\n\t\txml_attribute();\n\n\t\t// Constructs attribute from internal pointer\n\t\texplicit xml_attribute(xml_attribute_struct* attr);\n\n\t\t// Safe bool conversion operator\n\t\toperator unspecified_bool_type() const;\n\n\t\t// Borland C++ workaround\n\t\tbool operator!() const;\n\n\t\t// Comparison operators (compares wrapped attribute pointers)\n\t\tbool operator==(const xml_attribute& r) const;\n\t\tbool operator!=(const xml_attribute& r) const;\n\t\tbool operator<(const xml_attribute& r) const;\n\t\tbool operator>(const xml_attribute& r) const;\n\t\tbool operator<=(const xml_attribute& r) const;\n\t\tbool operator>=(const xml_attribute& r) const;\n\n\t\t// Check if attribute is empty (null)\n\t\tbool empty() const;\n\n\t\t// Get attribute name/value, or \"\" if attribute is empty\n\t\tconst char_t* name() const;\n\t\tconst char_t* value() const;\n\n\t\t// Get attribute value, or the default value if attribute is empty\n\t\tconst char_t* as_string(const char_t* def = PUGIXML_TEXT(\"\")) const;\n\n\t\t// Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty\n\t\tint as_int(int def = 0) const;\n\t\tunsigned int as_uint(unsigned int def = 0) const;\n\t\tdouble as_double(double def = 0) const;\n\t\tfloat as_float(float def = 0) const;\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\tlong long as_llong(long long def = 0) const;\n\t\tunsigned long long as_ullong(unsigned long long def = 0) const;\n\t#endif\n\n\t\t// Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty\n\t\tbool as_bool(bool def = false) const;\n\n\t\t// Set attribute name/value (returns false if attribute is empty or there is not enough memory)\n\t\tbool set_name(const char_t* rhs);\n\t\tbool set_name(const char_t* rhs, size_t size);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool set_name(string_view_t rhs);\n\t#endif\n\t\tbool set_value(const char_t* rhs);\n\t\tbool set_value(const char_t* rhs, size_t size);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool set_value(string_view_t rhs);\n\t#endif\n\n\t\t// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to \"true\"/\"false\")\n\t\tbool set_value(int rhs);\n\t\tbool set_value(unsigned int rhs);\n\t\tbool set_value(long rhs);\n\t\tbool set_value(unsigned long rhs);\n\t\tbool set_value(double rhs);\n\t\tbool set_value(double rhs, int precision);\n\t\tbool set_value(float rhs);\n\t\tbool set_value(float rhs, int precision);\n\t\tbool set_value(bool rhs);\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\tbool set_value(long long rhs);\n\t\tbool set_value(unsigned long long rhs);\n\t#endif\n\n\t\t// Set attribute value (equivalent to set_value without error checking)\n\t\txml_attribute& operator=(const char_t* rhs);\n\t\txml_attribute& operator=(int rhs);\n\t\txml_attribute& operator=(unsigned int rhs);\n\t\txml_attribute& operator=(long rhs);\n\t\txml_attribute& operator=(unsigned long rhs);\n\t\txml_attribute& operator=(double rhs);\n\t\txml_attribute& operator=(float rhs);\n\t\txml_attribute& operator=(bool rhs);\n\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_attribute& operator=(string_view_t rhs);\n\t#endif\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\txml_attribute& operator=(long long rhs);\n\t\txml_attribute& operator=(unsigned long long rhs);\n\t#endif\n\n\t\t// Get next/previous attribute in the attribute list of the parent node\n\t\txml_attribute next_attribute() const;\n\t\txml_attribute previous_attribute() const;\n\n\t\t// Get hash value (unique for handles to the same object)\n\t\tsize_t hash_value() const;\n\n\t\t// Get internal pointer\n\t\txml_attribute_struct* internal_object() const;\n\t};\n\n#ifdef __BORLANDC__\n\t// Borland C++ workaround\n\tbool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs);\n\tbool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs);\n#endif\n\n\t// A light-weight handle for manipulating nodes in DOM tree\n\tclass PUGIXML_CLASS xml_node\n\t{\n\t\tfriend class xml_attribute_iterator;\n\t\tfriend class xml_node_iterator;\n\t\tfriend class xml_named_node_iterator;\n\n\tprotected:\n\t\txml_node_struct* _root;\n\n\t\ttypedef void (*unspecified_bool_type)(xml_node***);\n\n\tpublic:\n\t\t// Default constructor. Constructs an empty node.\n\t\txml_node();\n\n\t\t// Constructs node from internal pointer\n\t\texplicit xml_node(xml_node_struct* p);\n\n\t\t// Safe bool conversion operator\n\t\toperator unspecified_bool_type() const;\n\n\t\t// Borland C++ workaround\n\t\tbool operator!() const;\n\n\t\t// Comparison operators (compares wrapped node pointers)\n\t\tbool operator==(const xml_node& r) const;\n\t\tbool operator!=(const xml_node& r) const;\n\t\tbool operator<(const xml_node& r) const;\n\t\tbool operator>(const xml_node& r) const;\n\t\tbool operator<=(const xml_node& r) const;\n\t\tbool operator>=(const xml_node& r) const;\n\n\t\t// Check if node is empty (null)\n\t\tbool empty() const;\n\n\t\t// Get node type\n\t\txml_node_type type() const;\n\n\t\t// Get node name, or \"\" if node is empty or it has no name\n\t\tconst char_t* name() const;\n\n\t\t// Get node value, or \"\" if node is empty or it has no value\n\t\t// Note: For <node>text</node> node.value() does not return \"text\"! Use child_value() or text() methods to access text inside nodes.\n\t\tconst char_t* value() const;\n\n\t\t// Get attribute list\n\t\txml_attribute first_attribute() const;\n\t\txml_attribute last_attribute() const;\n\n\t\t// Get children list\n\t\txml_node first_child() const;\n\t\txml_node last_child() const;\n\n\t\t// Get next/previous sibling in the children list of the parent node\n\t\txml_node next_sibling() const;\n\t\txml_node previous_sibling() const;\n\n\t\t// Get parent node\n\t\txml_node parent() const;\n\n\t\t// Get root of DOM tree this node belongs to\n\t\txml_node root() const;\n\n\t\t// Get text object for the current node\n\t\txml_text text() const;\n\n\t\t// Get child, attribute or next/previous sibling with the specified name\n\t\txml_node child(const char_t* name) const;\n\t\txml_attribute attribute(const char_t* name) const;\n\t\txml_node next_sibling(const char_t* name) const;\n\t\txml_node previous_sibling(const char_t* name) const;\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_node child(string_view_t name) const;\n\t\txml_attribute attribute(string_view_t name) const;\n\t\txml_node next_sibling(string_view_t name) const;\n\t\txml_node previous_sibling(string_view_t name) const;\n\t#endif\n\n\t\t// Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast)\n\t\txml_attribute attribute(const char_t* name, xml_attribute& hint) const;\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_attribute attribute(string_view_t name, xml_attribute& hint) const;\n\t#endif\n\n\t\t// Get child value of current node; that is, value of the first child node of type PCDATA/CDATA\n\t\tconst char_t* child_value() const;\n\n\t\t// Get child value of child with specified name. Equivalent to child(name).child_value().\n\t\tconst char_t* child_value(const char_t* name) const;\n\n\t\t// Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)\n\t\tbool set_name(const char_t* rhs);\n\t\tbool set_name(const char_t* rhs, size_t size);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool set_name(string_view_t rhs);\n\t#endif\n\t\tbool set_value(const char_t* rhs);\n\t\tbool set_value(const char_t* rhs, size_t size);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool set_value(string_view_t rhs);\n\t#endif\n\n\t\t// Add attribute with specified name. Returns added attribute, or empty attribute on errors.\n\t\txml_attribute append_attribute(const char_t* name);\n\t\txml_attribute prepend_attribute(const char_t* name);\n\t\txml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);\n\t\txml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_attribute append_attribute(string_view_t name);\n\t\txml_attribute prepend_attribute(string_view_t name);\n\t\txml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr);\n\t\txml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr);\n\t#endif\n\n\t\t// Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.\n\t\txml_attribute append_copy(const xml_attribute& proto);\n\t\txml_attribute prepend_copy(const xml_attribute& proto);\n\t\txml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);\n\t\txml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);\n\n\t\t// Add child node with specified type. Returns added node, or empty node on errors.\n\t\txml_node append_child(xml_node_type type = node_element);\n\t\txml_node prepend_child(xml_node_type type = node_element);\n\t\txml_node insert_child_after(xml_node_type type, const xml_node& node);\n\t\txml_node insert_child_before(xml_node_type type, const xml_node& node);\n\n\t\t// Add child element with specified name. Returns added node, or empty node on errors.\n\t\txml_node append_child(const char_t* name);\n\t\txml_node prepend_child(const char_t* name);\n\t\txml_node insert_child_after(const char_t* name, const xml_node& node);\n\t\txml_node insert_child_before(const char_t* name, const xml_node& node);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_node append_child(string_view_t name);\n\t\txml_node prepend_child(string_view_t name);\n\t\txml_node insert_child_after(string_view_t, const xml_node& node);\n\t\txml_node insert_child_before(string_view_t name, const xml_node& node);\n\t#endif\n\n\t\t// Add a copy of the specified node as a child. Returns added node, or empty node on errors.\n\t\txml_node append_copy(const xml_node& proto);\n\t\txml_node prepend_copy(const xml_node& proto);\n\t\txml_node insert_copy_after(const xml_node& proto, const xml_node& node);\n\t\txml_node insert_copy_before(const xml_node& proto, const xml_node& node);\n\n\t\t// Move the specified node to become a child of this node. Returns moved node, or empty node on errors.\n\t\txml_node append_move(const xml_node& moved);\n\t\txml_node prepend_move(const xml_node& moved);\n\t\txml_node insert_move_after(const xml_node& moved, const xml_node& node);\n\t\txml_node insert_move_before(const xml_node& moved, const xml_node& node);\n\n\t\t// Remove specified attribute\n\t\tbool remove_attribute(const xml_attribute& a);\n\t\tbool remove_attribute(const char_t* name);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool remove_attribute(string_view_t name);\n\t#endif\n\n\t\t// Remove all attributes\n\t\tbool remove_attributes();\n\n\t\t// Remove specified child\n\t\tbool remove_child(const xml_node& n);\n\t\tbool remove_child(const char_t* name);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool remove_child(string_view_t name);\n\t#endif\n\n\t\t// Remove all children\n\t\tbool remove_children();\n\n\t\t// Parses buffer as an XML document fragment and appends all nodes as children of the current node.\n\t\t// Copies/converts the buffer, so it may be deleted or changed after the function returns.\n\t\t// Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory.\n\t\txml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\n\t\t// Find attribute using predicate. Returns first attribute for which predicate returned true.\n\t\ttemplate <typename Predicate> xml_attribute find_attribute(Predicate pred) const\n\t\t{\n\t\t\tif (!_root) return xml_attribute();\n\n\t\t\tfor (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())\n\t\t\t\tif (pred(attrib))\n\t\t\t\t\treturn attrib;\n\n\t\t\treturn xml_attribute();\n\t\t}\n\n\t\t// Find child node using predicate. Returns first child for which predicate returned true.\n\t\ttemplate <typename Predicate> xml_node find_child(Predicate pred) const\n\t\t{\n\t\t\tif (!_root) return xml_node();\n\n\t\t\tfor (xml_node node = first_child(); node; node = node.next_sibling())\n\t\t\t\tif (pred(node))\n\t\t\t\t\treturn node;\n\n\t\t\treturn xml_node();\n\t\t}\n\n\t\t// Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true.\n\t\ttemplate <typename Predicate> xml_node find_node(Predicate pred) const\n\t\t{\n\t\t\tif (!_root) return xml_node();\n\n\t\t\txml_node cur = first_child();\n\n\t\t\twhile (cur._root && cur._root != _root)\n\t\t\t{\n\t\t\t\tif (pred(cur)) return cur;\n\n\t\t\t\tif (cur.first_child()) cur = cur.first_child();\n\t\t\t\telse if (cur.next_sibling()) cur = cur.next_sibling();\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twhile (!cur.next_sibling() && cur._root != _root) cur = cur.parent();\n\n\t\t\t\t\tif (cur._root != _root) cur = cur.next_sibling();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn xml_node();\n\t\t}\n\n\t\t// Find child node by attribute name/value\n\t\txml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;\n\t\txml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;\n\n\t#ifndef PUGIXML_NO_STL\n\t\t// Get the absolute node path from root as a text string.\n\t\tstring_t path(char_t delimiter = '/') const;\n\t#endif\n\n\t\t// Search for a node by path consisting of node names and . or .. elements.\n\t\txml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const;\n\n\t\t// Recursively traverse subtree with xml_tree_walker\n\t\tbool traverse(xml_tree_walker& walker);\n\n\t#ifndef PUGIXML_NO_XPATH\n\t\t// Select single node by evaluating XPath query. Returns first node from the resulting node set.\n\t\txpath_node select_node(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const;\n\t\txpath_node select_node(const xpath_query& query) const;\n\n\t\t// Select node set by evaluating XPath query\n\t\txpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const;\n\t\txpath_node_set select_nodes(const xpath_query& query) const;\n\n\t\t// (deprecated: use select_node instead) Select single node by evaluating XPath query.\n\t\tPUGIXML_DEPRECATED xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL) const;\n\t\tPUGIXML_DEPRECATED xpath_node select_single_node(const xpath_query& query) const;\n\n\t#endif\n\n\t\t// Print subtree using a writer object\n\t\tvoid print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;\n\n\t#ifndef PUGIXML_NO_STL\n\t\t// Print subtree to stream\n\t\tvoid print(std::basic_ostream<char>& os, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;\n\t\tvoid print(std::basic_ostream<wchar_t>& os, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, unsigned int depth = 0) const;\n\t#endif\n\n\t\t// Child nodes iterators\n\t\ttypedef xml_node_iterator iterator;\n\n\t\titerator begin() const;\n\t\titerator end() const;\n\n\t\t// Attribute iterators\n\t\ttypedef xml_attribute_iterator attribute_iterator;\n\n\t\tattribute_iterator attributes_begin() const;\n\t\tattribute_iterator attributes_end() const;\n\n\t\t// Range-based for support\n\t\txml_object_range<xml_node_iterator> children() const;\n\t\txml_object_range<xml_attribute_iterator> attributes() const;\n\n\t\t// Range-based for support for all children with the specified name\n\t\t// Note: name pointer must have a longer lifetime than the returned object; be careful with passing temporaries!\n\t\txml_object_range<xml_named_node_iterator> children(const char_t* name) const;\n\n\t\t// Get node offset in parsed file/string (in char_t units) for debugging purposes\n\t\tptrdiff_t offset_debug() const;\n\n\t\t// Get hash value (unique for handles to the same object)\n\t\tsize_t hash_value() const;\n\n\t\t// Get internal pointer\n\t\txml_node_struct* internal_object() const;\n\t};\n\n#ifdef __BORLANDC__\n\t// Borland C++ workaround\n\tbool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs);\n\tbool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs);\n#endif\n\n\t// A helper for working with text inside PCDATA nodes\n\tclass PUGIXML_CLASS xml_text\n\t{\n\t\tfriend class xml_node;\n\n\t\txml_node_struct* _root;\n\n\t\ttypedef void (*unspecified_bool_type)(xml_text***);\n\n\t\texplicit xml_text(xml_node_struct* root);\n\n\t\txml_node_struct* _data_new();\n\t\txml_node_struct* _data() const;\n\n\tpublic:\n\t\t// Default constructor. Constructs an empty object.\n\t\txml_text();\n\n\t\t// Safe bool conversion operator\n\t\toperator unspecified_bool_type() const;\n\n\t\t// Borland C++ workaround\n\t\tbool operator!() const;\n\n\t\t// Check if text object is empty (null)\n\t\tbool empty() const;\n\n\t\t// Get text, or \"\" if object is empty\n\t\tconst char_t* get() const;\n\n\t\t// Get text, or the default value if object is empty\n\t\tconst char_t* as_string(const char_t* def = PUGIXML_TEXT(\"\")) const;\n\n\t\t// Get text as a number, or the default value if conversion did not succeed or object is empty\n\t\tint as_int(int def = 0) const;\n\t\tunsigned int as_uint(unsigned int def = 0) const;\n\t\tdouble as_double(double def = 0) const;\n\t\tfloat as_float(float def = 0) const;\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\tlong long as_llong(long long def = 0) const;\n\t\tunsigned long long as_ullong(unsigned long long def = 0) const;\n\t#endif\n\n\t\t// Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty\n\t\tbool as_bool(bool def = false) const;\n\n\t\t// Set text (returns false if object is empty or there is not enough memory)\n\t\tbool set(const char_t* rhs);\n\t\tbool set(const char_t* rhs, size_t size);\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\tbool set(string_view_t rhs);\n\t#endif\n\n\t\t// Set text with type conversion (numbers are converted to strings, boolean is converted to \"true\"/\"false\")\n\t\tbool set(int rhs);\n\t\tbool set(unsigned int rhs);\n\t\tbool set(long rhs);\n\t\tbool set(unsigned long rhs);\n\t\tbool set(double rhs);\n\t\tbool set(double rhs, int precision);\n\t\tbool set(float rhs);\n\t\tbool set(float rhs, int precision);\n\t\tbool set(bool rhs);\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\tbool set(long long rhs);\n\t\tbool set(unsigned long long rhs);\n\t#endif\n\n\t\t// Set text (equivalent to set without error checking)\n\t\txml_text& operator=(const char_t* rhs);\n\t\txml_text& operator=(int rhs);\n\t\txml_text& operator=(unsigned int rhs);\n\t\txml_text& operator=(long rhs);\n\t\txml_text& operator=(unsigned long rhs);\n\t\txml_text& operator=(double rhs);\n\t\txml_text& operator=(float rhs);\n\t\txml_text& operator=(bool rhs);\n\n\t#ifdef PUGIXML_HAS_STRING_VIEW\n\t\txml_text& operator=(string_view_t rhs);\n\t#endif\n\n\t#ifdef PUGIXML_HAS_LONG_LONG\n\t\txml_text& operator=(long long rhs);\n\t\txml_text& operator=(unsigned long long rhs);\n\t#endif\n\n\t\t// Get the data node (node_pcdata or node_cdata) for this object\n\t\txml_node data() const;\n\t};\n\n#ifdef __BORLANDC__\n\t// Borland C++ workaround\n\tbool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs);\n\tbool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs);\n#endif\n\n\t// Child node iterator (a bidirectional iterator over a collection of xml_node)\n\tclass PUGIXML_CLASS xml_node_iterator\n\t{\n\t\tfriend class xml_node;\n\n\tprivate:\n\t\tmutable xml_node _wrap;\n\t\txml_node _parent;\n\n\t\txml_node_iterator(xml_node_struct* ref, xml_node_struct* parent);\n\n\tpublic:\n\t\t// Iterator traits\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef xml_node value_type;\n\t\ttypedef xml_node* pointer;\n\t\ttypedef xml_node& reference;\n\n\t#ifndef PUGIXML_NO_STL\n\t\ttypedef std::bidirectional_iterator_tag iterator_category;\n\t#endif\n\n\t\t// Default constructor\n\t\txml_node_iterator();\n\n\t\t// Construct an iterator which points to the specified node\n\t\txml_node_iterator(const xml_node& node);\n\n\t\t// Iterator operators\n\t\tbool operator==(const xml_node_iterator& rhs) const;\n\t\tbool operator!=(const xml_node_iterator& rhs) const;\n\n\t\txml_node& operator*() const;\n\t\txml_node* operator->() const;\n\n\t\txml_node_iterator& operator++();\n\t\txml_node_iterator operator++(int);\n\n\t\txml_node_iterator& operator--();\n\t\txml_node_iterator operator--(int);\n\t};\n\n\t// Attribute iterator (a bidirectional iterator over a collection of xml_attribute)\n\tclass PUGIXML_CLASS xml_attribute_iterator\n\t{\n\t\tfriend class xml_node;\n\n\tprivate:\n\t\tmutable xml_attribute _wrap;\n\t\txml_node _parent;\n\n\t\txml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent);\n\n\tpublic:\n\t\t// Iterator traits\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef xml_attribute value_type;\n\t\ttypedef xml_attribute* pointer;\n\t\ttypedef xml_attribute& reference;\n\n\t#ifndef PUGIXML_NO_STL\n\t\ttypedef std::bidirectional_iterator_tag iterator_category;\n\t#endif\n\n\t\t// Default constructor\n\t\txml_attribute_iterator();\n\n\t\t// Construct an iterator which points to the specified attribute\n\t\txml_attribute_iterator(const xml_attribute& attr, const xml_node& parent);\n\n\t\t// Iterator operators\n\t\tbool operator==(const xml_attribute_iterator& rhs) const;\n\t\tbool operator!=(const xml_attribute_iterator& rhs) const;\n\n\t\txml_attribute& operator*() const;\n\t\txml_attribute* operator->() const;\n\n\t\txml_attribute_iterator& operator++();\n\t\txml_attribute_iterator operator++(int);\n\n\t\txml_attribute_iterator& operator--();\n\t\txml_attribute_iterator operator--(int);\n\t};\n\n\t// Named node range helper\n\tclass PUGIXML_CLASS xml_named_node_iterator\n\t{\n\t\tfriend class xml_node;\n\n\tpublic:\n\t\t// Iterator traits\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef xml_node value_type;\n\t\ttypedef xml_node* pointer;\n\t\ttypedef xml_node& reference;\n\n\t#ifndef PUGIXML_NO_STL\n\t\ttypedef std::bidirectional_iterator_tag iterator_category;\n\t#endif\n\n\t\t// Default constructor\n\t\txml_named_node_iterator();\n\n\t\t// Construct an iterator which points to the specified node\n\t\t// Note: name pointer is stored in the iterator and must have a longer lifetime than iterator itself\n\t\txml_named_node_iterator(const xml_node& node, const char_t* name);\n\n\t\t// Iterator operators\n\t\tbool operator==(const xml_named_node_iterator& rhs) const;\n\t\tbool operator!=(const xml_named_node_iterator& rhs) const;\n\n\t\txml_node& operator*() const;\n\t\txml_node* operator->() const;\n\n\t\txml_named_node_iterator& operator++();\n\t\txml_named_node_iterator operator++(int);\n\n\t\txml_named_node_iterator& operator--();\n\t\txml_named_node_iterator operator--(int);\n\n\tprivate:\n\t\tmutable xml_node _wrap;\n\t\txml_node _parent;\n\t\tconst char_t* _name;\n\n\t\txml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name);\n\t};\n\n\t// Abstract tree walker class (see xml_node::traverse)\n\tclass PUGIXML_CLASS xml_tree_walker\n\t{\n\t\tfriend class xml_node;\n\n\tprivate:\n\t\tint _depth;\n\n\tprotected:\n\t\t// Get current traversal depth\n\t\tint depth() const;\n\n\tpublic:\n\t\txml_tree_walker();\n\t\tvirtual ~xml_tree_walker();\n\n\t\t// Callback that is called when traversal begins\n\t\tvirtual bool begin(xml_node& node);\n\n\t\t// Callback that is called for each node traversed\n\t\tvirtual bool for_each(xml_node& node) = 0;\n\n\t\t// Callback that is called when traversal ends\n\t\tvirtual bool end(xml_node& node);\n\t};\n\n\t// Parsing status, returned as part of xml_parse_result object\n\tenum xml_parse_status\n\t{\n\t\tstatus_ok = 0,\t\t\t\t// No error\n\n\t\tstatus_file_not_found,\t\t// File was not found during load_file()\n\t\tstatus_io_error,\t\t\t// Error reading from file/stream\n\t\tstatus_out_of_memory,\t\t// Could not allocate memory\n\t\tstatus_internal_error,\t\t// Internal error occurred\n\n\t\tstatus_unrecognized_tag,\t// Parser could not determine tag type\n\n\t\tstatus_bad_pi,\t\t\t\t// Parsing error occurred while parsing document declaration/processing instruction\n\t\tstatus_bad_comment,\t\t\t// Parsing error occurred while parsing comment\n\t\tstatus_bad_cdata,\t\t\t// Parsing error occurred while parsing CDATA section\n\t\tstatus_bad_doctype,\t\t\t// Parsing error occurred while parsing document type declaration\n\t\tstatus_bad_pcdata,\t\t\t// Parsing error occurred while parsing PCDATA section\n\t\tstatus_bad_start_element,\t// Parsing error occurred while parsing start element tag\n\t\tstatus_bad_attribute,\t\t// Parsing error occurred while parsing element attribute\n\t\tstatus_bad_end_element,\t\t// Parsing error occurred while parsing end element tag\n\t\tstatus_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)\n\n\t\tstatus_append_invalid_root,\t// Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer)\n\n\t\tstatus_no_document_element\t// Parsing resulted in a document without element nodes\n\t};\n\n\t// Parsing result\n\tstruct PUGIXML_CLASS xml_parse_result\n\t{\n\t\t// Parsing status (see xml_parse_status)\n\t\txml_parse_status status;\n\n\t\t// Last parsed offset (in char_t units from start of input data)\n\t\tptrdiff_t offset;\n\n\t\t// Source document encoding\n\t\txml_encoding encoding;\n\n\t\t// Default constructor, initializes object to failed state\n\t\txml_parse_result();\n\n\t\t// Cast to bool operator\n\t\toperator bool() const;\n\n\t\t// Get error description\n\t\tconst char* description() const;\n\t};\n\n\t// Document class (DOM tree root)\n\tclass PUGIXML_CLASS xml_document: public xml_node\n\t{\n\tprivate:\n\t\tchar_t* _buffer;\n\n\t\tchar _memory[192];\n\n\t\t// Non-copyable semantics\n\t\txml_document(const xml_document&);\n\t\txml_document& operator=(const xml_document&);\n\n\t\tvoid _create();\n\t\tvoid _destroy();\n\t\tvoid _move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT;\n\n\tpublic:\n\t\t// Default constructor, makes empty document\n\t\txml_document();\n\n\t\t// Destructor, invalidates all node/attribute handles to this document\n\t\t~xml_document();\n\n\t#ifdef PUGIXML_HAS_MOVE\n\t\t// Move semantics support\n\t\txml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT;\n\t\txml_document& operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT;\n\t#endif\n\n\t\t// Removes all nodes, leaving the empty document\n\t\tvoid reset();\n\n\t\t// Removes all nodes, then copies the entire contents of the specified document\n\t\tvoid reset(const xml_document& proto);\n\n\t#ifndef PUGIXML_NO_STL\n\t\t// Load document from stream.\n\t\txml_parse_result load(std::basic_istream<char>& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\t\txml_parse_result load(std::basic_istream<wchar_t>& stream, unsigned int options = parse_default);\n\t#endif\n\n\t\t// (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.\n\t\tPUGIXML_DEPRECATED xml_parse_result load(const char_t* contents, unsigned int options = parse_default);\n\n\t\t// Load document from zero-terminated string. No encoding conversions are applied.\n\t\txml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);\n\n\t\t// Load document from file\n\t\txml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\t\txml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\n\t\t// Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns.\n\t\txml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\n\t\t// Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).\n\t\t// You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.\n\t\txml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\n\t\t// Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).\n\t\t// You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).\n\t\txml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);\n\n\t\t// Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details).\n\t\tvoid save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;\n\n\t#ifndef PUGIXML_NO_STL\n\t\t// Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details).\n\t\tvoid save(std::basic_ostream<char>& stream, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;\n\t\tvoid save(std::basic_ostream<wchar_t>& stream, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default) const;\n\t#endif\n\n\t\t// Save XML to file\n\t\tbool save_file(const char* path, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;\n\t\tbool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT(\"\\t\"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;\n\n\t\t// Get document element\n\t\txml_node document_element() const;\n\t};\n\n#ifndef PUGIXML_NO_XPATH\n\t// XPath query return type\n\tenum xpath_value_type\n\t{\n\t\txpath_type_none,\t  // Unknown type (query failed to compile)\n\t\txpath_type_node_set,  // Node set (xpath_node_set)\n\t\txpath_type_number,\t  // Number\n\t\txpath_type_string,\t  // String\n\t\txpath_type_boolean\t  // Boolean\n\t};\n\n\t// XPath parsing result\n\tstruct PUGIXML_CLASS xpath_parse_result\n\t{\n\t\t// Error message (0 if no error)\n\t\tconst char* error;\n\n\t\t// Last parsed offset (in char_t units from string start)\n\t\tptrdiff_t offset;\n\n\t\t// Default constructor, initializes object to failed state\n\t\txpath_parse_result();\n\n\t\t// Cast to bool operator\n\t\toperator bool() const;\n\n\t\t// Get error description\n\t\tconst char* description() const;\n\t};\n\n\t// A single XPath variable\n\tclass PUGIXML_CLASS xpath_variable\n\t{\n\t\tfriend class xpath_variable_set;\n\n\tprotected:\n\t\txpath_value_type _type;\n\t\txpath_variable* _next;\n\n\t\txpath_variable(xpath_value_type type);\n\n\t\t// Non-copyable semantics\n\t\txpath_variable(const xpath_variable&);\n\t\txpath_variable& operator=(const xpath_variable&);\n\n\tpublic:\n\t\t// Get variable name\n\t\tconst char_t* name() const;\n\n\t\t// Get variable type\n\t\txpath_value_type type() const;\n\n\t\t// Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error\n\t\tbool get_boolean() const;\n\t\tdouble get_number() const;\n\t\tconst char_t* get_string() const;\n\t\tconst xpath_node_set& get_node_set() const;\n\n\t\t// Set variable value; no type conversion is performed, false is returned on type mismatch error\n\t\tbool set(bool value);\n\t\tbool set(double value);\n\t\tbool set(const char_t* value);\n\t\tbool set(const xpath_node_set& value);\n\t};\n\n\t// A set of XPath variables\n\tclass PUGIXML_CLASS xpath_variable_set\n\t{\n\tprivate:\n\t\txpath_variable* _data[64];\n\n\t\tvoid _assign(const xpath_variable_set& rhs);\n\t\tvoid _swap(xpath_variable_set& rhs);\n\n\t\txpath_variable* _find(const char_t* name) const;\n\n\t\tstatic bool _clone(xpath_variable* var, xpath_variable** out_result);\n\t\tstatic void _destroy(xpath_variable* var);\n\n\tpublic:\n\t\t// Default constructor/destructor\n\t\txpath_variable_set();\n\t\t~xpath_variable_set();\n\n\t\t// Copy constructor/assignment operator\n\t\txpath_variable_set(const xpath_variable_set& rhs);\n\t\txpath_variable_set& operator=(const xpath_variable_set& rhs);\n\n\t#ifdef PUGIXML_HAS_MOVE\n\t\t// Move semantics support\n\t\txpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT;\n\t\txpath_variable_set& operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT;\n\t#endif\n\n\t\t// Add a new variable or get the existing one, if the types match\n\t\txpath_variable* add(const char_t* name, xpath_value_type type);\n\n\t\t// Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch\n\t\tbool set(const char_t* name, bool value);\n\t\tbool set(const char_t* name, double value);\n\t\tbool set(const char_t* name, const char_t* value);\n\t\tbool set(const char_t* name, const xpath_node_set& value);\n\n\t\t// Get existing variable by name\n\t\txpath_variable* get(const char_t* name);\n\t\tconst xpath_variable* get(const char_t* name) const;\n\t};\n\n\t// A compiled XPath query object\n\tclass PUGIXML_CLASS xpath_query\n\t{\n\tprivate:\n\t\tvoid* _impl;\n\t\txpath_parse_result _result;\n\n\t\ttypedef void (*unspecified_bool_type)(xpath_query***);\n\n\t\t// Non-copyable semantics\n\t\txpath_query(const xpath_query&);\n\t\txpath_query& operator=(const xpath_query&);\n\n\tpublic:\n\t\t// Construct a compiled object from XPath expression.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.\n\t\texplicit xpath_query(const char_t* query, xpath_variable_set* variables = PUGIXML_NULL);\n\n\t\t// Constructor\n\t\txpath_query();\n\n\t\t// Destructor\n\t\t~xpath_query();\n\n\t#ifdef PUGIXML_HAS_MOVE\n\t\t// Move semantics support\n\t\txpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT;\n\t\txpath_query& operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT;\n\t#endif\n\n\t\t// Get query expression return type\n\t\txpath_value_type return_type() const;\n\n\t\t// Evaluate expression as boolean value in the specified context; performs type conversion if necessary.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.\n\t\tbool evaluate_boolean(const xpath_node& n) const;\n\n\t\t// Evaluate expression as double value in the specified context; performs type conversion if necessary.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.\n\t\tdouble evaluate_number(const xpath_node& n) const;\n\n\t#ifndef PUGIXML_NO_STL\n\t\t// Evaluate expression as string value in the specified context; performs type conversion if necessary.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.\n\t\tstring_t evaluate_string(const xpath_node& n) const;\n\t#endif\n\n\t\t// Evaluate expression as string value in the specified context; performs type conversion if necessary.\n\t\t// At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.\n\t\t// If PUGIXML_NO_EXCEPTIONS is defined, returns empty  set instead.\n\t\tsize_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;\n\n\t\t// Evaluate expression as node set in the specified context.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.\n\t\t// If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.\n\t\txpath_node_set evaluate_node_set(const xpath_node& n) const;\n\n\t\t// Evaluate expression as node set in the specified context.\n\t\t// Return first node in document order, or empty node if node set is empty.\n\t\t// If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.\n\t\t// If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead.\n\t\txpath_node evaluate_node(const xpath_node& n) const;\n\n\t\t// Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)\n\t\tconst xpath_parse_result& result() const;\n\n\t\t// Safe bool conversion operator\n\t\toperator unspecified_bool_type() const;\n\n\t\t// Borland C++ workaround\n\t\tbool operator!() const;\n\t};\n\n\t#ifndef PUGIXML_NO_EXCEPTIONS\n        #if defined(_MSC_VER)\n          // C4275 can be ignored in Visual C++ if you are deriving\n          // from a type in the Standard C++ Library\n          #pragma warning(push)\n          #pragma warning(disable: 4275)\n        #endif\n\t// XPath exception class\n\tclass PUGIXML_CLASS xpath_exception: public std::exception\n\t{\n\tprivate:\n\t\txpath_parse_result _result;\n\n\tpublic:\n\t\t// Construct exception from parse result\n\t\texplicit xpath_exception(const xpath_parse_result& result);\n\n\t\t// Get error message\n\t\tvirtual const char* what() const PUGIXML_NOEXCEPT PUGIXML_OVERRIDE;\n\n\t\t// Get parse result\n\t\tconst xpath_parse_result& result() const;\n\t};\n        #if defined(_MSC_VER)\n          #pragma warning(pop)\n        #endif\n\t#endif\n\n\t// XPath node class (either xml_node or xml_attribute)\n\tclass PUGIXML_CLASS xpath_node\n\t{\n\tprivate:\n\t\txml_node _node;\n\t\txml_attribute _attribute;\n\n\t\ttypedef void (*unspecified_bool_type)(xpath_node***);\n\n\tpublic:\n\t\t// Default constructor; constructs empty XPath node\n\t\txpath_node();\n\n\t\t// Construct XPath node from XML node/attribute\n\t\txpath_node(const xml_node& node);\n\t\txpath_node(const xml_attribute& attribute, const xml_node& parent);\n\n\t\t// Get node/attribute, if any\n\t\txml_node node() const;\n\t\txml_attribute attribute() const;\n\n\t\t// Get parent of contained node/attribute\n\t\txml_node parent() const;\n\n\t\t// Safe bool conversion operator\n\t\toperator unspecified_bool_type() const;\n\n\t\t// Borland C++ workaround\n\t\tbool operator!() const;\n\n\t\t// Comparison operators\n\t\tbool operator==(const xpath_node& n) const;\n\t\tbool operator!=(const xpath_node& n) const;\n\t};\n\n#ifdef __BORLANDC__\n\t// Borland C++ workaround\n\tbool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs);\n\tbool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs);\n#endif\n\n\t// A fixed-size collection of XPath nodes\n\tclass PUGIXML_CLASS xpath_node_set\n\t{\n\tpublic:\n\t\t// Collection type\n\t\tenum type_t\n\t\t{\n\t\t\ttype_unsorted,\t\t\t// Not ordered\n\t\t\ttype_sorted,\t\t\t// Sorted by document order (ascending)\n\t\t\ttype_sorted_reverse\t\t// Sorted by document order (descending)\n\t\t};\n\n\t\t// Constant iterator type\n\t\ttypedef const xpath_node* const_iterator;\n\n\t\t// We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work\n\t\ttypedef const xpath_node* iterator;\n\n\t\t// Default constructor. Constructs empty set.\n\t\txpath_node_set();\n\n\t\t// Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful\n\t\txpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);\n\n\t\t// Destructor\n\t\t~xpath_node_set();\n\n\t\t// Copy constructor/assignment operator\n\t\txpath_node_set(const xpath_node_set& ns);\n\t\txpath_node_set& operator=(const xpath_node_set& ns);\n\n\t#ifdef PUGIXML_HAS_MOVE\n\t\t// Move semantics support\n\t\txpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT;\n\t\txpath_node_set& operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT;\n\t#endif\n\n\t\t// Get collection type\n\t\ttype_t type() const;\n\n\t\t// Get collection size\n\t\tsize_t size() const;\n\n\t\t// Indexing operator\n\t\tconst xpath_node& operator[](size_t index) const;\n\n\t\t// Collection iterators\n\t\tconst_iterator begin() const;\n\t\tconst_iterator end() const;\n\n\t\t// Sort the collection in ascending/descending order by document order\n\t\tvoid sort(bool reverse = false);\n\n\t\t// Get first node in the collection by document order\n\t\txpath_node first() const;\n\n\t\t// Check if collection is empty\n\t\tbool empty() const;\n\n\tprivate:\n\t\ttype_t _type;\n\n\t\txpath_node _storage[1];\n\n\t\txpath_node* _begin;\n\t\txpath_node* _end;\n\n\t\tvoid _assign(const_iterator begin, const_iterator end, type_t type);\n\t\tvoid _move(xpath_node_set& rhs) PUGIXML_NOEXCEPT;\n\t};\n#endif\n\n#ifndef PUGIXML_NO_STL\n\t// Convert wide string to UTF8\n\tstd::basic_string<char> PUGIXML_FUNCTION as_utf8(const wchar_t* str);\n\tstd::basic_string<char> PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str);\n\n\t// Convert UTF8 to wide string\n\tstd::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str);\n\tstd::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::basic_string<char>& str);\n#endif\n\n\t// Memory allocation function interface; returns pointer to allocated memory or NULL on failure\n\ttypedef void* (*allocation_function)(size_t size);\n\n\t// Memory deallocation function interface\n\ttypedef void (*deallocation_function)(void* ptr);\n\n\t// Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.\n\tvoid PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);\n\n\t// Get current memory management functions\n\tallocation_function PUGIXML_FUNCTION get_memory_allocation_function();\n\tdeallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();\n}\n\n#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))\nnamespace std\n{\n\t// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&);\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&);\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&);\n}\n#endif\n\n#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)\nnamespace std\n{\n\t// Workarounds for (non-standard) iterator category detection\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&);\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&);\n\tstd::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&);\n}\n#endif\n\n#endif\n\n// Make sure implementation is included in header-only mode\n// Use macro expansion in #include to work around QMake (QTBUG-11923)\n#if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE)\n#\tdefine PUGIXML_SOURCE \"pugixml.cpp\"\n#\tinclude PUGIXML_SOURCE\n#endif\n\n/**\n * Copyright (c) 2006-2025 Arseny Kapoulkine\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without\n * restriction, including without limitation the rights to use,\n * copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */\n"
  },
  {
    "path": "tests/.gitignore",
    "content": "build/\n"
  },
  {
    "path": "tests/run_all_tests.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\n\ndeclare -a TEST_SCRIPTS=(\n    \"$ROOT_DIR/tests/run_database_tests.sh\"\n    \"$ROOT_DIR/tests/run_translation_tests.sh\"\n)\n\necho \"Running AI File Sorter test suite\"\necho \"=================================\"\n\nfor script in \"${TEST_SCRIPTS[@]}\"; do\n    if [[ ! -x \"$script\" ]]; then\n        echo \"ERROR: Test script '$script' is missing or not executable.\" >&2\n        exit 1\n    fi\n\n    name=\"$(basename \"$script\")\"\n    echo \"\"\n    echo \">>> $name\"\n    \"$script\"\ndone\n\necho \"\"\necho \"All tests completed successfully.\"\n"
  },
  {
    "path": "tests/run_database_tests.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\nBUILD_DIR=\"$ROOT_DIR/tests/build\"\nmkdir -p \"$BUILD_DIR\"\nmkdir -p \"$BUILD_DIR/spdlog/sinks\"\nmkdir -p \"$BUILD_DIR/spdlog/fmt\"\n\nTEST_SRC=\"$BUILD_DIR/database_manager_test.cpp\"\nSTUB_SRC=\"$BUILD_DIR/logger_stub.cpp\"\nOUTPUT=\"$BUILD_DIR/database_manager_test\"\n\ncat > \"$TEST_SRC\" <<'CPP'\n#include \"DatabaseManager.hpp\"\n#include \"Types.hpp\"\n\n#include <filesystem>\n#include <iostream>\n#include <set>\n#include <cstdlib>\n#include <chrono>\n#include <system_error>\n#include <vector>\n\nnamespace {\nstruct TempDir {\n    explicit TempDir(std::filesystem::path p) : path(std::move(p)) {}\n    ~TempDir() {\n        std::error_code ec;\n        std::filesystem::remove_all(path, ec);\n    }\n    std::filesystem::path path;\n};\n\n[[noreturn]] void fail(const std::string& message) {\n    std::cerr << message << '\\n';\n    std::exit(1);\n}\n} // namespace\n\nint main() {\n    const auto unique_dir = std::filesystem::temp_directory_path() /\n        (\"aifs-dbtest-\" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));\n    std::filesystem::create_directories(unique_dir);\n    TempDir guard(unique_dir);\n\n    DatabaseManager manager(unique_dir.string());\n\n    const std::string test_dir = \"/sample\";\n    DatabaseManager::ResolvedCategory valid{0, \"Docs\", \"Manuals\"};\n    DatabaseManager::ResolvedCategory empty_cat{0, \"\", \"\"};\n    DatabaseManager::ResolvedCategory whitespace_cat{0, \"   \", \"   \"};\n\n    if (!manager.insert_or_update_file_with_categorization(\"valid.txt\", \"F\", test_dir, valid, false, \"\")) {\n        fail(\"Failed to insert valid row\");\n    }\n    if (!manager.insert_or_update_file_with_categorization(\"empty.txt\", \"F\", test_dir, empty_cat, false, \"\")) {\n        fail(\"Failed to insert empty row\");\n    }\n    if (!manager.insert_or_update_file_with_categorization(\"space.txt\", \"F\", test_dir, whitespace_cat, false, \"\")) {\n        fail(\"Failed to insert whitespace row\");\n    }\n\n    auto removed = manager.remove_empty_categorizations(test_dir);\n    if (removed.size() != 2) {\n        fail(\"Expected 2 entries removed, got \" + std::to_string(removed.size()));\n    }\n\n    std::set<std::string> removed_names;\n    for (const auto& entry : removed) {\n        removed_names.insert(entry.file_name);\n    }\n    if (!removed_names.contains(\"empty.txt\") || !removed_names.contains(\"space.txt\")) {\n        fail(\"Unexpected entries removed\");\n    }\n\n    if (!manager.remove_empty_categorizations(test_dir).empty()) {\n        fail(\"Subsequent cleanup should find no additional entries\");\n    }\n\n    auto empty_lookup = manager.get_categorization_from_db(test_dir, \"empty.txt\", FileType::File);\n    if (!empty_lookup.empty()) {\n        fail(\"Empty entry still present after cleanup\");\n    }\n    auto whitespace_lookup = manager.get_categorization_from_db(test_dir, \"space.txt\", FileType::File);\n    if (!whitespace_lookup.empty()) {\n        fail(\"Whitespace entry still present after cleanup\");\n    }\n\n    auto remaining = manager.get_categorized_files(test_dir);\n    if (remaining.size() != 1 || remaining.front().file_name != \"valid.txt\" ||\n        remaining.front().category != \"Docs\" || remaining.front().subcategory != \"Manuals\") {\n        fail(\"Valid entry was not preserved during cleanup\");\n    }\n\n    std::cout << \"Database manager cleanup test passed\" << std::endl;\n    return 0;\n}\nCPP\n\ncat > \"$STUB_SRC\" <<'CPP'\n#include \"Logger.hpp\"\n#include <filesystem>\n\nstd::string Logger::get_log_directory() {\n    return std::filesystem::temp_directory_path().string();\n}\n\nvoid Logger::setup_loggers() {}\n\nstd::shared_ptr<spdlog::logger> Logger::get_logger(const std::string&) {\n    return nullptr;\n}\n\nstd::string Logger::get_log_file_path(const std::string& log_dir, const std::string& log_name) {\n    return log_dir + \"/\" + log_name;\n}\nCPP\n\ncat > \"$BUILD_DIR/spdlog/spdlog.h\" <<'CPP'\n#pragma once\n#include <chrono>\n#include <memory>\n#include <string>\n\nnamespace spdlog {\nnamespace level {\nenum level_enum {\n    trace,\n    debug,\n    info,\n    warn,\n    err,\n    critical,\n    off\n};\n}\n\nclass logger {\npublic:\n    template <typename... Args>\n    void log(level::level_enum, const std::string&, Args&&...) {}\n\n    template <typename... Args>\n    void info(const std::string&, Args&&...) {}\n\n    template <typename... Args>\n    void warn(const std::string&, Args&&...) {}\n\n    template <typename... Args>\n    void error(const std::string&, Args&&...) {}\n\n    void flush_on(level::level_enum) {}\n    void set_level(level::level_enum) {}\n};\n\ninline std::shared_ptr<logger> get(const std::string&) { return nullptr; }\ninline void register_logger(std::shared_ptr<logger>) {}\ninline void flush_every(std::chrono::seconds) {}\ninline void set_level(level::level_enum) {}\ninline void info(const std::string&) {}\n} // namespace spdlog\nCPP\n\ncat > \"$BUILD_DIR/spdlog/sinks/stdout_color_sinks.h\" <<'CPP'\n#pragma once\nnamespace spdlog { namespace sinks {\nclass stdout_color_sink_mt {};\n}} // namespace spdlog::sinks\nCPP\n\ncat > \"$BUILD_DIR/spdlog/sinks/basic_file_sink.h\" <<'CPP'\n#pragma once\nnamespace spdlog { namespace sinks {\nclass basic_file_sink_mt {};\n}} // namespace spdlog::sinks\nCPP\n\ncat > \"$BUILD_DIR/spdlog/sinks/rotating_file_sink.h\" <<'CPP'\n#pragma once\nnamespace spdlog { namespace sinks {\nclass rotating_file_sink_mt {};\n}} // namespace spdlog::sinks\nCPP\n\ncat > \"$BUILD_DIR/spdlog/fmt/fmt.h\" <<'CPP'\n#pragma once\n#include <string>\n\nnamespace fmt {\ninline const std::string& runtime(const std::string& value) {\n    return value;\n}\n\ntemplate <typename... Args>\nstd::string format(const std::string& fmt_str, Args&&...) {\n    return fmt_str;\n}\n} // namespace fmt\nCPP\n\nINCLUDES=(\n    -I\"$BUILD_DIR\"\n    -I\"$ROOT_DIR/app/include\"\n)\n\nLIBS=(\n    -lsqlite3\n    -pthread\n)\n\ng++ -std=c++20 -fPIC \"${INCLUDES[@]}\" \\\n    \"$TEST_SRC\" \"$STUB_SRC\" \\\n    \"$ROOT_DIR/app/lib/DatabaseManager.cpp\" \\\n    -o \"$OUTPUT\" \"${LIBS[@]}\"\n\n\"$OUTPUT\"\n"
  },
  {
    "path": "tests/run_translation_tests.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\nBUILD_DIR=\"$ROOT_DIR/tests/build\"\nmkdir -p \"$BUILD_DIR\"\nmkdir -p \"$BUILD_DIR/i18n\"\n\nif rg -n '<translation type=\"unfinished\"' \"$ROOT_DIR\"/app/resources/i18n/*.ts >/dev/null; then\n    echo \"Unfinished translations remain in app/resources/i18n\" >&2\n    rg -n '<translation type=\"unfinished\"' \"$ROOT_DIR\"/app/resources/i18n/*.ts >&2\n    exit 1\nfi\n\nSRC=\"$BUILD_DIR/translation_manager_test.cpp\"\ncat > \"$SRC\" <<'CPP'\n#include \"TranslationManager.hpp\"\n#include <QApplication>\n#include <QCoreApplication>\n#include <iostream>\n\nint main(int argc, char** argv)\n{\n    QApplication app(argc, argv);\n\n    TranslationManager::instance().initialize(qApp);\n\n    TranslationManager::instance().set_language(Language::French);\n    const QString french = QCoreApplication::translate(\"UiTranslator\", \"Analyze folder\");\n    if (french != QStringLiteral(\"Analyser le dossier\")) {\n        std::cerr << \"Expected French translation, got: \" << french.toStdString() << \"\\n\";\n        return 1;\n    }\n\n    TranslationManager::instance().set_language(Language::English);\n    const QString english = QCoreApplication::translate(\"UiTranslator\", \"Analyze folder\");\n    if (english != QStringLiteral(\"Analyze folder\")) {\n        std::cerr << \"Expected English fallback, got: \" << english.toStdString() << \"\\n\";\n        return 2;\n    }\n\n    std::cout << \"Translation manager test passed\" << std::endl;\n    return 0;\n}\nCPP\n\nOUTPUT=\"$BUILD_DIR/translation_manager_test\"\n\nfind_qt6_path_tool() {\n    local tool_name=\"$1\"\n    local fallback_path=\"$2\"\n    if command -v \"$tool_name\" >/dev/null 2>&1; then\n        command -v \"$tool_name\"\n        return 0\n    fi\n    if [[ -x \"$fallback_path\" ]]; then\n        printf '%s\\n' \"$fallback_path\"\n        return 0\n    fi\n    return 1\n}\n\nfind_qt6_lrelease() {\n    local candidate qt_host_dir\n\n    for candidate in lrelease6 lrelease-qt6; do\n        if command -v \"$candidate\" >/dev/null 2>&1; then\n            command -v \"$candidate\"\n            return 0\n        fi\n    done\n\n    if [[ -n \"${QTPATHS6:-}\" ]]; then\n        while IFS= read -r qt_host_dir; do\n            if [[ -n \"$qt_host_dir\" && -x \"$qt_host_dir/lrelease\" ]]; then\n                printf '%s\\n' \"$qt_host_dir/lrelease\"\n                return 0\n            fi\n        done < <(\n            \"$QTPATHS6\" --query QT_HOST_LIBEXECS 2>/dev/null || true\n            \"$QTPATHS6\" --query QT_HOST_BINS 2>/dev/null || true\n        )\n    fi\n\n    if [[ -n \"${QMAKE6:-}\" ]]; then\n        while IFS= read -r qt_host_dir; do\n            if [[ -n \"$qt_host_dir\" && -x \"$qt_host_dir/lrelease\" ]]; then\n                printf '%s\\n' \"$qt_host_dir/lrelease\"\n                return 0\n            fi\n        done < <(\n            \"$QMAKE6\" -query QT_HOST_LIBEXECS 2>/dev/null || true\n            \"$QMAKE6\" -query QT_HOST_BINS 2>/dev/null || true\n            \"$QMAKE6\" -query QT_INSTALL_BINS 2>/dev/null || true\n        )\n    fi\n\n    for candidate in \\\n        /usr/lib/qt6/libexec/lrelease \\\n        /usr/lib/qt6/bin/lrelease \\\n        /opt/homebrew/bin/lrelease \\\n        /opt/homebrew/opt/qt/share/qt/libexec/lrelease \\\n        /opt/homebrew/opt/qtbase/share/qt/libexec/lrelease \\\n        /usr/local/opt/qtbase/share/qt/libexec/lrelease; do\n        if [[ -x \"$candidate\" ]]; then\n            printf '%s\\n' \"$candidate\"\n            return 0\n        fi\n    done\n\n    if command -v lrelease >/dev/null 2>&1; then\n        candidate=\"$(command -v lrelease)\"\n        if \"$candidate\" -version 2>&1 | grep -Eq 'Qt[^0-9]*6|version 6'; then\n            printf '%s\\n' \"$candidate\"\n            return 0\n        fi\n    fi\n\n    return 1\n}\n\nQMAKE6=\"$(find_qt6_path_tool qmake6 /usr/lib/qt6/bin/qmake6 || true)\"\nQTPATHS6=\"$(find_qt6_path_tool qtpaths6 /usr/lib/qt6/bin/qtpaths6 || true)\"\n\npkg_includes=\"$(pkg-config --cflags Qt6Core Qt6Gui Qt6Widgets 2>/dev/null || true)\"\npkg_libs=\"$(pkg-config --libs Qt6Core Qt6Gui Qt6Widgets 2>/dev/null || true)\"\n\nif [[ -n \"$pkg_includes\" && -n \"$pkg_libs\" ]]; then\n    QT_FLAGS=\"$pkg_includes -I$ROOT_DIR/app/include\"\n    QT_LIB_FLAGS=\"$pkg_libs\"\nelse\n    qt_headers=\"\"\n    qt_libs=\"\"\n    if [[ -n \"$QMAKE6\" ]]; then\n        qt_headers=\"$(\"$QMAKE6\" -query QT_INSTALL_HEADERS 2>/dev/null || true)\"\n        qt_libs=\"$(\"$QMAKE6\" -query QT_INSTALL_LIBS 2>/dev/null || true)\"\n    elif command -v qmake >/dev/null 2>&1; then\n        qt_headers=\"$(qmake -query QT_INSTALL_HEADERS 2>/dev/null || true)\"\n        qt_libs=\"$(qmake -query QT_INSTALL_LIBS 2>/dev/null || true)\"\n    elif [[ -n \"$QTPATHS6\" ]]; then\n        prefix=\"$(\"$QTPATHS6\" --install-prefix 2>/dev/null || true)\"\n        if [[ -n \"$prefix\" ]]; then\n            qt_headers=\"$prefix/include\"\n            qt_libs=\"$prefix/lib\"\n        fi\n    elif command -v brew >/dev/null 2>&1; then\n        prefix=\"$(brew --prefix qt 2>/dev/null || brew --prefix qt6 2>/dev/null || true)\"\n        if [[ -n \"$prefix\" ]]; then\n            qt_headers=\"$prefix/include\"\n            qt_libs=\"$prefix/lib\"\n        fi\n    fi\n\n    if [[ -n \"$qt_headers\" ]]; then\n        QT_FLAGS=\"-I$ROOT_DIR/app/include -I$qt_headers -I$qt_headers/QtCore -I$qt_headers/QtGui -I$qt_headers/QtWidgets\"\n        if [[ -n \"$qt_libs\" ]]; then\n            for fw in QtCore QtGui QtWidgets; do\n                fw_headers=\"$qt_libs/$fw.framework/Headers\"\n                if [[ -d \"$fw_headers\" ]]; then\n                    QT_FLAGS=\"$QT_FLAGS -I$fw_headers\"\n                fi\n            done\n        fi\n    else\n        QT_FLAGS=\"-I$ROOT_DIR/app/include -I/usr/include/x86_64-linux-gnu/qt6 -I/usr/include/x86_64-linux-gnu/qt6/QtCore -I/usr/include/x86_64-linux-gnu/qt6/QtGui -I/usr/include/x86_64-linux-gnu/qt6/QtWidgets -I/opt/homebrew/include -I/opt/homebrew/include/QtCore -I/opt/homebrew/include/QtGui -I/opt/homebrew/include/QtWidgets\"\n    fi\n\n    if [[ -n \"$qt_libs\" ]]; then\n        if [[ -d \"$qt_libs/QtCore.framework\" ]]; then\n            QT_LIB_FLAGS=\"-F$qt_libs -framework QtCore -framework QtGui -framework QtWidgets\"\n        else\n            QT_LIB_FLAGS=\"-L$qt_libs -lQt6Core -lQt6Gui -lQt6Widgets\"\n        fi\n    else\n        QT_LIB_FLAGS=\"-L/opt/homebrew/lib -lQt6Core -lQt6Gui -lQt6Widgets\"\n    fi\nfi\n\nLRELEASE=\"$(find_qt6_lrelease || true)\"\n\nif [[ -z \"$LRELEASE\" ]]; then\n    echo \"Could not find a Qt 6 lrelease binary. Install qt6-l10n-tools or set LRELEASE=/path/to/qt6/lrelease\" >&2\n    exit 1\nfi\n\n\"$LRELEASE\" \"$ROOT_DIR/app/resources/i18n/aifilesorter_fr.ts\" -qm \"$BUILD_DIR/i18n/aifilesorter_fr.qm\"\n\n# shellcheck disable=SC2086\ng++ -std=c++20 -fPIC $QT_FLAGS \"$SRC\" \"$ROOT_DIR/app/lib/TranslationManager.cpp\" -o \"$OUTPUT\" $QT_LIB_FLAGS\nQT_QPA_PLATFORM=offscreen \"$OUTPUT\"\n"
  },
  {
    "path": "tests/unit/TestHelpers.hpp",
    "content": "/**\n * @file TestHelpers.hpp\n * @brief Common utilities for unit tests (temp paths, env guards, Qt context).\n */\n#pragma once\n\n#include <atomic>\n#include <chrono>\n#include <cstdint>\n#include <cstdlib>\n#include <filesystem>\n#include <fstream>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <vector>\n#include <cstring>\n#include <QApplication>\n#include \"TranslationManager.hpp\"\n#include \"Language.hpp\"\n\n/**\n * @brief Build a unique token string with the given prefix.\n * @param prefix Prefix to include in the token.\n * @return Unique token string that is safe for filenames.\n */\ninline std::string make_unique_token(std::string_view prefix) {\n    static std::atomic<uint64_t> counter{0};\n    const uint64_t value = counter.fetch_add(1, std::memory_order_relaxed);\n    const auto now = std::chrono::high_resolution_clock::now().time_since_epoch().count();\n    return std::string(prefix) + std::to_string(now) + \"-\" + std::to_string(value);\n}\n\n/**\n * @brief RAII helper that sets and restores environment variables.\n */\nclass EnvVarGuard {\npublic:\n    /**\n     * @brief Set or unset an environment variable for the guard lifetime.\n     * @param key Environment variable name.\n     * @param value New value; unset when std::nullopt.\n     */\n    EnvVarGuard(std::string key, std::optional<std::string> value)\n        : key_(std::move(key)) {\n        if (const char* existing = std::getenv(key_.c_str())) {\n            original_ = existing;\n        }\n        apply(value);\n    }\n\n    /**\n     * @brief Restore the original environment variable state.\n     */\n    ~EnvVarGuard() {\n        apply(original_);\n    }\n\n    EnvVarGuard(const EnvVarGuard&) = delete;\n    EnvVarGuard& operator=(const EnvVarGuard&) = delete;\n\nprivate:\n    static void set_env(const std::string& key, const std::string& value) {\n#ifdef _WIN32\n        _putenv_s(key.c_str(), value.c_str());\n#else\n        setenv(key.c_str(), value.c_str(), 1);\n#endif\n    }\n\n    static void unset_env(const std::string& key) {\n#ifdef _WIN32\n        _putenv_s(key.c_str(), \"\");\n#else\n        unsetenv(key.c_str());\n#endif\n    }\n\n    void apply(const std::optional<std::string>& value) {\n        if (value.has_value()) {\n            set_env(key_, *value);\n        } else {\n            unset_env(key_);\n        }\n    }\n\n    std::string key_;\n    std::optional<std::string> original_;\n};\n\n/**\n * @brief Creates a temporary directory and cleans it up on destruction.\n */\nclass TempDir {\npublic:\n    /**\n     * @brief Create a unique temporary directory.\n     */\n    TempDir()\n        : path_(std::filesystem::temp_directory_path() /\n                make_unique_token(\"aifs-test-\")) {\n        std::filesystem::create_directories(path_);\n    }\n\n    /**\n     * @brief Remove the temporary directory and its contents.\n     */\n    ~TempDir() {\n        std::error_code ec;\n        std::filesystem::remove_all(path_, ec);\n    }\n\n    TempDir(const TempDir&) = delete;\n    TempDir& operator=(const TempDir&) = delete;\n\n    /**\n     * @brief Return the temporary directory path.\n     * @return Reference to the directory path.\n     */\n    const std::filesystem::path& path() const { return path_; }\n\nprivate:\n    std::filesystem::path path_;\n};\n\n/**\n * @brief Creates a temporary GGUF-like file for model-related tests.\n */\nclass TempModelFile {\npublic:\n    /**\n     * @brief Create a temporary model file with minimal GGUF metadata.\n     * @param block_count GGUF block count to encode.\n     * @param file_size Total file size in bytes.\n     */\n    explicit TempModelFile(std::uint32_t block_count = 32,\n                           std::size_t file_size = 4 * 1024 * 1024) {\n        if (file_size < 32) {\n            file_size = 32;\n        }\n        path_ = std::filesystem::temp_directory_path() /\n                (make_unique_token(\"aifs-model-\") + \".gguf\");\n        std::vector<char> buffer(file_size, 0);\n        const std::string key = \"llama.block_count\";\n        const std::uint64_t len = static_cast<std::uint64_t>(key.size());\n        const std::uint32_t type = 4; // GGUF_TYPE_UINT32\n        const std::uint32_t value = block_count;\n\n        const std::size_t required =\n            sizeof(len) + key.size() + sizeof(type) + sizeof(value);\n        if (buffer.size() < required) {\n            buffer.resize(required);\n        }\n\n        std::size_t offset = 0;\n        std::memcpy(&buffer[offset], &len, sizeof(len));\n        offset += sizeof(len);\n        std::memcpy(&buffer[offset], key.data(), key.size());\n        offset += key.size();\n        std::memcpy(&buffer[offset], &type, sizeof(type));\n        offset += sizeof(type);\n        std::memcpy(&buffer[offset], &value, sizeof(value));\n\n        std::ofstream out(path_, std::ios::binary);\n        out.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));\n        out.close();\n    }\n\n    /**\n     * @brief Remove the temporary model file.\n     */\n    ~TempModelFile() {\n        std::error_code ec;\n        std::filesystem::remove(path_, ec);\n    }\n\n    /**\n     * @brief Return the temporary model file path.\n     * @return Reference to the file path.\n     */\n    const std::filesystem::path& path() const { return path_; }\n\nprivate:\n    std::filesystem::path path_;\n};\n\n/**\n * @brief Ensures a QApplication and translation manager are initialized.\n */\nclass QtAppContext {\npublic:\n    /**\n     * @brief Initialize QApplication (if needed) and load translations.\n     */\n    QtAppContext() {\n        if (!QApplication::instance()) {\n            static int argc = 1;\n            static char arg0[] = \"tests\";\n            static char* argv[] = {arg0, nullptr};\n            static QApplication* app = new QApplication(argc, argv);\n            Q_UNUSED(app);\n        }\n        TranslationManager::instance().initialize(qApp);\n        TranslationManager::instance().set_language(Language::English);\n    }\n};\n"
  },
  {
    "path": "tests/unit/test_cache_interactions.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"CategorizationService.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"FileScanner.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"ResultsCoordinator.hpp\"\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n\n#include <atomic>\n#include <algorithm>\n#include <fstream>\n#include <filesystem>\n#include <memory>\n#include <string>\n#include <unordered_set>\n\nnamespace {\nvoid write_file(const std::filesystem::path& path) {\n    std::filesystem::create_directories(path.parent_path());\n    std::ofstream out(path);\n    out << \"data\";\n}\n\nclass CountingLLM : public ILLMClient {\npublic:\n    CountingLLM(std::shared_ptr<int> calls, std::string response)\n        : calls_(std::move(calls)), response_(std::move(response)) {}\n\n    std::string categorize_file(const std::string&,\n                                const std::string&,\n                                FileType,\n                                const std::string&) override {\n        ++(*calls_);\n        return response_;\n    }\n\n    std::string complete_prompt(const std::string&, int) override {\n        return std::string();\n    }\n\n    void set_prompt_logging_enabled(bool) override {\n    }\n\nprivate:\n    std::shared_ptr<int> calls_;\n    std::string response_;\n};\n} // namespace\n\nTEST_CASE(\"CategorizationService uses cached categorization without calling LLM\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n\n    TempDir data_dir;\n    const std::string dir_path = data_dir.path().string();\n    const std::string file_name = \"cached.png\";\n    const auto resolved = db.resolve_category(\"Images\", \"Photos\");\n    REQUIRE(resolved.taxonomy_id > 0);\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        file_name, \"F\", dir_path, resolved, false, std::string(), false));\n\n    CategorizationService service(settings, db, nullptr);\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<CountingLLM>(calls, \"Documents : Reports\");\n    };\n\n    const auto full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    const auto categorized = service.categorize_entries(\n        files,\n        true,\n        stop_flag,\n        {},\n        {},\n        {},\n        {},\n        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Photos\");\n    CHECK(*calls == 0);\n}\n\nTEST_CASE(\"CategorizationService falls back to LLM when cache is empty\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n\n    TempDir data_dir;\n    const std::string dir_path = data_dir.path().string();\n    const std::string file_name = \"uncached.txt\";\n    DatabaseManager::ResolvedCategory empty{0, \"\", \"\"};\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        file_name, \"F\", dir_path, empty, false, std::string(), false));\n\n    CategorizationService service(settings, db, nullptr);\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<CountingLLM>(calls, \"Images : Photos\");\n    };\n\n    const auto full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    const auto categorized = service.categorize_entries(\n        files,\n        true,\n        stop_flag,\n        {},\n        {},\n        {},\n        {},\n        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Photos\");\n    CHECK(*calls == 1);\n\n    const auto cached = db.get_categorization_from_db(dir_path, file_name, FileType::File);\n    REQUIRE(cached.size() == 2);\n    CHECK(cached[0] == \"Images\");\n    CHECK(cached[1] == \"Photos\");\n}\n\nTEST_CASE(\"CategorizationService invokes completion callback per entry\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const auto first_path = (data_dir.path() / \"first.txt\").string();\n    const auto second_path = (data_dir.path() / \"second.txt\").string();\n    const std::vector<FileEntry> files = {\n        FileEntry{first_path, \"first.txt\", FileType::File},\n        FileEntry{second_path, \"second.txt\", FileType::File}\n    };\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<CountingLLM>(calls, \"Documents : Reports\");\n    };\n\n    std::size_t queued_count = 0;\n    std::size_t completed_count = 0;\n    const auto categorized = service.categorize_entries(\n        files,\n        true,\n        stop_flag,\n        {},\n        [&queued_count](const FileEntry&) { ++queued_count; },\n        [&completed_count](const FileEntry&) { ++completed_count; },\n        {},\n        factory);\n\n    REQUIRE(categorized.size() == files.size());\n    CHECK(queued_count == files.size());\n    CHECK(completed_count == files.size());\n    CHECK(*calls == static_cast<int>(files.size()));\n}\n\nTEST_CASE(\"CategorizationService loads cached entries recursively for analysis\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string root_path = data_dir.path().string();\n    const std::string child_path = (data_dir.path() / \"child\").string();\n\n    const auto resolved = db.resolve_category(\"Images\", \"Photos\");\n    REQUIRE(resolved.taxonomy_id > 0);\n\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"root.png\", \"F\", root_path, resolved, false, std::string(), false));\n    DatabaseManager::ResolvedCategory empty{0, \"\", \"\"};\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"suggested.png\", \"F\", child_path, empty, false, \"rename_me.png\", true));\n\n    settings.set_include_subdirectories(false);\n    auto cached_root_only = service.load_cached_entries(root_path);\n    REQUIRE(cached_root_only.size() == 1);\n    CHECK(cached_root_only.front().file_name == \"root.png\");\n\n    settings.set_include_subdirectories(true);\n    auto cached_recursive = service.load_cached_entries(root_path);\n    REQUIRE(cached_recursive.size() == 2);\n    const auto it = std::find_if(cached_recursive.begin(), cached_recursive.end(),\n                                 [](const CategorizedFile& entry) {\n                                     return entry.file_name == \"suggested.png\";\n                                 });\n    REQUIRE(it != cached_recursive.end());\n    CHECK(it->suggested_name == \"rename_me.png\");\n    CHECK(it->file_path == child_path);\n}\n\nTEST_CASE(\"Recursive recategorization clears stale subtree cache entries\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string root_path = data_dir.path().string();\n    const std::string child_path = (data_dir.path() / \"child\").string();\n\n    const auto resolved = db.resolve_category(\"Documents\", \"Reports\");\n    REQUIRE(resolved.taxonomy_id > 0);\n\n    // Simulate a partially re-categorized subtree: the root entry already uses the\n    // new style while a nested entry is still cached with the old style.\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"root.txt\", \"F\", root_path, resolved, true, std::string(), false));\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"child.txt\", \"F\", child_path, resolved, false, std::string(), false));\n\n    CHECK(db.has_categorization_style_conflict(root_path, true, true));\n\n    REQUIRE(db.clear_directory_categorizations(root_path, true));\n\n    settings.set_include_subdirectories(true);\n    CHECK(service.load_cached_entries(root_path).empty());\n}\n\nTEST_CASE(\"ResultsCoordinator respects full-path cache keys for recursive scans\") {\n    TempDir data_dir;\n    const auto root_file = data_dir.path() / \"sample.txt\";\n    const auto nested_file = data_dir.path() / \"nested\" / \"sample.txt\";\n    write_file(root_file);\n    write_file(nested_file);\n\n    FileScanner scanner;\n    ResultsCoordinator coordinator(scanner);\n    const auto options = FileScanOptions::Files | FileScanOptions::Recursive;\n\n    std::unordered_set<std::string> cached_by_name{\"sample.txt\"};\n    auto uncached_by_name = coordinator.find_files_to_categorize(\n        data_dir.path().string(),\n        options,\n        cached_by_name,\n        false);\n    CHECK(uncached_by_name.empty());\n\n    std::unordered_set<std::string> cached_by_path{root_file.string()};\n    auto uncached_by_path = coordinator.find_files_to_categorize(\n        data_dir.path().string(),\n        options,\n        cached_by_path,\n        true);\n    REQUIRE(uncached_by_path.size() == 1);\n    CHECK(uncached_by_path.front().full_path == nested_file.string());\n}\n"
  },
  {
    "path": "tests/unit/test_categorization_dialog.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"CategorizationDialog.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"TestHooks.hpp\"\n#include \"TestHelpers.hpp\"\n#include <QCheckBox>\n#include <QTableView>\n#include <QStandardItemModel>\n#include <filesystem>\n#include <fstream>\n\n#ifndef _WIN32\n\nnamespace {\n\nstruct MoveProbeGuard {\n    ~MoveProbeGuard() {\n        TestHooks::reset_categorization_move_probe();\n    }\n};\n\nCategorizedFile sample_file() {\n    CategorizedFile file;\n    file.file_path = \"/tmp\";\n    file.file_name = \"example.txt\";\n    file.type = FileType::File;\n    file.category = \"Docs\";\n    file.subcategory = \"Reports\";\n    return file;\n}\n\n} // namespace\n\nTEST_CASE(\"CategorizationDialog uses subcategory toggle when moving files\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    const std::vector<CategorizedFile> files = {sample_file()};\n\n    auto verify_toggle = [&](bool initial_state, bool toggled_state) {\n        TempDir undo_dir;\n        CategorizationDialog dialog(nullptr, initial_state, undo_dir.path().string());\n        dialog.test_set_entries(files);\n\n        bool probe_called = false;\n        bool recorded_flag = !toggled_state;\n        MoveProbeGuard guard;\n\n        TestHooks::set_categorization_move_probe(\n            [&](const TestHooks::CategorizationMoveInfo& info) {\n                probe_called = true;\n                recorded_flag = info.show_subcategory_folders;\n            });\n\n        dialog.set_show_subcategory_column(toggled_state);\n        dialog.test_trigger_confirm();\n\n        REQUIRE(probe_called);\n        CHECK(recorded_flag == toggled_state);\n    };\n\n    SECTION(\"Enabled state honored\") {\n        verify_toggle(true, true);\n    }\n\n    SECTION(\"Disabling hides subcategory folders\") {\n        verify_toggle(true, false);\n    }\n\n    SECTION(\"Enabling from disabled state works\") {\n        verify_toggle(false, true);\n    }\n}\n\n#ifndef _WIN32\nTEST_CASE(\"CategorizationDialog supports sorting by columns\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile alpha;\n    alpha.file_path = \"/tmp\";\n    alpha.file_name = \"b.txt\";\n    alpha.type = FileType::File;\n    alpha.category = \"Alpha\";\n    alpha.subcategory = \"One\";\n\n    CategorizedFile beta;\n    beta.file_path = \"/tmp\";\n    beta.file_name = \"a.txt\";\n    beta.type = FileType::File;\n    beta.category = \"Beta\";\n    beta.subcategory = \"Two\";\n\n    TempDir undo_dir;\n    CategorizationDialog dialog(nullptr, true, undo_dir.path().string());\n    dialog.test_set_entries({alpha, beta});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    SECTION(\"Sorts by file name ascending\") {\n        table->sortByColumn(1, Qt::AscendingOrder); // file name column\n        REQUIRE(model->item(0, 1)->text() == QStringLiteral(\"a.txt\"));\n        REQUIRE(model->item(1, 1)->text() == QStringLiteral(\"b.txt\"));\n    }\n\n    SECTION(\"Sorts by category descending\") {\n        table->sortByColumn(4, Qt::DescendingOrder); // category column\n        REQUIRE(model->item(0, 4)->text() == QStringLiteral(\"Beta\"));\n        REQUIRE(model->item(1, 4)->text() == QStringLiteral(\"Alpha\"));\n    }\n}\n#endif\n\n#ifndef _WIN32\nTEST_CASE(\"CategorizationDialog undo restores moved files\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string file_name = \"alpha.txt\";\n    const std::filesystem::path source = base / file_name;\n    std::ofstream(source).put('x');\n\n    CategorizedFile file;\n    file.file_path = base.string();\n    file.file_name = file_name;\n    file.type = FileType::File;\n    file.category = \"Docs\";\n    file.subcategory = \"Reports\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({file});\n\n    REQUIRE_FALSE(dialog.test_undo_enabled());\n\n    dialog.test_trigger_confirm();\n\n    const std::filesystem::path destination = base / file.category / file.subcategory / file_name;\n    REQUIRE_FALSE(std::filesystem::exists(source));\n    REQUIRE(std::filesystem::exists(destination));\n    REQUIRE(dialog.test_undo_enabled());\n\n    dialog.test_trigger_undo();\n\n    REQUIRE(std::filesystem::exists(source));\n    REQUIRE_FALSE(std::filesystem::exists(destination));\n    REQUIRE_FALSE(dialog.test_undo_enabled());\n}\n\nTEST_CASE(\"CategorizationDialog undo allows renaming again\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string file_name = \"photo.jpg\";\n    const std::string renamed = \"sunset.jpg\";\n    const std::filesystem::path source = base / file_name;\n    const std::filesystem::path destination = base / renamed;\n    std::ofstream(source).put('x');\n\n    CategorizedFile file;\n    file.file_path = base.string();\n    file.file_name = file_name;\n    file.type = FileType::File;\n    file.rename_only = true;\n    file.suggested_name = renamed;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({file});\n\n    dialog.test_trigger_confirm();\n    REQUIRE_FALSE(std::filesystem::exists(source));\n    REQUIRE(std::filesystem::exists(destination));\n\n    dialog.test_trigger_undo();\n    REQUIRE(std::filesystem::exists(source));\n    REQUIRE_FALSE(std::filesystem::exists(destination));\n\n    dialog.test_trigger_confirm();\n    REQUIRE_FALSE(std::filesystem::exists(source));\n    REQUIRE(std::filesystem::exists(destination));\n}\n\nTEST_CASE(\"CategorizationDialog rename-only updates cached filename\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    DatabaseManager db(config_dir.path().string());\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string file_name = \"photo.jpg\";\n    const std::string renamed = \"sunset.jpg\";\n    const std::filesystem::path source = base / file_name;\n    const std::filesystem::path destination = base / renamed;\n    std::ofstream(source).put('x');\n\n    CategorizedFile file;\n    file.file_path = base.string();\n    file.file_name = file_name;\n    file.type = FileType::File;\n    file.rename_only = true;\n    file.suggested_name = renamed;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({file});\n\n    dialog.test_trigger_confirm();\n    REQUIRE_FALSE(std::filesystem::exists(source));\n    REQUIRE(std::filesystem::exists(destination));\n\n    const auto old_cache = db.get_categorization_from_db(base.string(), file_name, FileType::File);\n    REQUIRE(old_cache.empty());\n\n    const auto cached = db.get_categorized_files(base.string());\n    REQUIRE(cached.size() == 1);\n    CHECK(cached.front().file_name == renamed);\n    CHECK(cached.front().rename_only);\n    CHECK(cached.front().suggested_name == renamed);\n}\n\nTEST_CASE(\"CategorizationDialog allows editing when rename-only checkbox is off\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile rename_only_entry;\n    rename_only_entry.file_path = \"/tmp\";\n    rename_only_entry.file_name = \"a.png\";\n    rename_only_entry.type = FileType::File;\n    rename_only_entry.rename_only = true;\n    rename_only_entry.suggested_name = \"example.png\";\n\n    CategorizedFile categorized_entry;\n    categorized_entry.file_path = \"/tmp\";\n    categorized_entry.file_name = \"b.png\";\n    categorized_entry.type = FileType::File;\n    categorized_entry.category = \"Images\";\n    categorized_entry.subcategory = \"Screens\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({rename_only_entry, categorized_entry});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    CHECK(model->item(0, 4)->isEditable());\n    CHECK(model->item(1, 4)->isEditable());\n}\n\nTEST_CASE(\"CategorizationDialog deduplicates suggested names when rename-only is toggled\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile first;\n    first.file_path = \"/tmp\";\n    first.file_name = \"a.png\";\n    first.type = FileType::File;\n    first.category = \"Images\";\n    first.subcategory = \"Screens\";\n    first.suggested_name = \"computer_screen_youtube.png\";\n\n    CategorizedFile second = first;\n    second.file_name = \"b.png\";\n    second.category = \"Media\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({first, second});\n\n    QCheckBox* rename_checkbox = nullptr;\n    const auto checkboxes = dialog.findChildren<QCheckBox*>();\n    for (auto* checkbox : checkboxes) {\n        if (checkbox && checkbox->text() == QStringLiteral(\"Do not categorize picture files (only rename)\")) {\n            rename_checkbox = checkbox;\n            break;\n        }\n    }\n    REQUIRE(rename_checkbox != nullptr);\n    rename_checkbox->setChecked(true);\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    const QString first_suggestion = model->item(0, 3)->text();\n    const QString second_suggestion = model->item(1, 3)->text();\n\n    CHECK(first_suggestion == QStringLiteral(\"computer_screen_youtube_1.png\"));\n    CHECK(second_suggestion == QStringLiteral(\"computer_screen_youtube_2.png\"));\n}\n\nTEST_CASE(\"CategorizationDialog avoids double suffixes for numbered suggestions\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile first;\n    first.file_path = \"/tmp\";\n    first.file_name = \"a.png\";\n    first.type = FileType::File;\n    first.rename_only = true;\n    first.suggested_name = \"computer_screen_youtube_1.png\";\n\n    CategorizedFile second = first;\n    second.file_name = \"b.png\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({first, second});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    const QString first_suggestion = model->item(0, 3)->text();\n    const QString second_suggestion = model->item(1, 3)->text();\n\n    CHECK(first_suggestion == QStringLiteral(\"computer_screen_youtube_1.png\"));\n    CHECK(second_suggestion == QStringLiteral(\"computer_screen_youtube_2.png\"));\n}\n\nTEST_CASE(\"CategorizationDialog hides suggested names for renamed entries\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile entry;\n    entry.file_path = \"/tmp\";\n    entry.file_name = \"already_renamed.png\";\n    entry.type = FileType::File;\n    entry.suggested_name = \"new_name.png\";\n    entry.rename_applied = true;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({entry});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    CHECK(model->item(0, 3)->text().isEmpty());\n    CHECK_FALSE(model->item(0, 3)->isEditable());\n}\n\nTEST_CASE(\"CategorizationDialog hides already renamed rows when rename-only is on\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    CategorizedFile renamed;\n    renamed.file_path = \"/tmp\";\n    renamed.file_name = \"renamed.png\";\n    renamed.type = FileType::File;\n    renamed.category = \"Images\";\n    renamed.subcategory = \"Screens\";\n    renamed.rename_applied = true;\n\n    CategorizedFile pending;\n    pending.file_path = \"/tmp\";\n    pending.file_name = \"pending.png\";\n    pending.type = FileType::File;\n    pending.category = \"Images\";\n    pending.subcategory = \"Screens\";\n    pending.suggested_name = \"pending_new.png\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({renamed, pending});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    auto find_row = [&](const QString& name) -> int {\n        for (int row = 0; row < model->rowCount(); ++row) {\n            if (model->item(row, 1)->text() == name) {\n                return row;\n            }\n        }\n        return -1;\n    };\n\n    const int renamed_row = find_row(QStringLiteral(\"renamed.png\"));\n    const int pending_row = find_row(QStringLiteral(\"pending.png\"));\n    REQUIRE(renamed_row >= 0);\n    REQUIRE(pending_row >= 0);\n\n    CHECK_FALSE(table->isRowHidden(renamed_row));\n    CHECK_FALSE(table->isRowHidden(pending_row));\n\n    QCheckBox* rename_checkbox = nullptr;\n    const auto checkboxes = dialog.findChildren<QCheckBox*>();\n    for (auto* checkbox : checkboxes) {\n        if (checkbox && checkbox->text() == QStringLiteral(\"Do not categorize picture files (only rename)\")) {\n            rename_checkbox = checkbox;\n            break;\n        }\n    }\n    REQUIRE(rename_checkbox != nullptr);\n\n    rename_checkbox->setChecked(true);\n    CHECK(table->isRowHidden(renamed_row));\n}\n\nTEST_CASE(\"CategorizationDialog deduplicates suggested picture filenames\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n\n    CategorizedFile first;\n    first.file_path = base.string();\n    first.file_name = \"a.png\";\n    first.type = FileType::File;\n    first.suggested_name = \"sunny_barbeque_dinner.png\";\n    first.rename_only = true;\n\n    CategorizedFile second = first;\n    second.file_name = \"b.png\";\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({first, second});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    const QString first_suggestion = model->item(0, 3)->text();\n    const QString second_suggestion = model->item(1, 3)->text();\n\n    CHECK(first_suggestion == QStringLiteral(\"sunny_barbeque_dinner_1.png\"));\n    CHECK(second_suggestion == QStringLiteral(\"sunny_barbeque_dinner_2.png\"));\n}\n\nTEST_CASE(\"CategorizationDialog avoids existing picture filename collisions\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string existing_name = \"sunny_barbeque_dinner.png\";\n    std::ofstream(base / existing_name).put('x');\n\n    CategorizedFile entry;\n    entry.file_path = base.string();\n    entry.file_name = \"c.png\";\n    entry.type = FileType::File;\n    entry.suggested_name = existing_name;\n    entry.rename_only = true;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(nullptr, false, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({entry});\n\n    auto* table = dialog.findChild<QTableView*>();\n    REQUIRE(table != nullptr);\n    auto* model = qobject_cast<QStandardItemModel*>(table->model());\n    REQUIRE(model != nullptr);\n\n    const QString suggestion = model->item(0, 3)->text();\n    CHECK(suggestion == QStringLiteral(\"sunny_barbeque_dinner_1.png\"));\n}\n\nTEST_CASE(\"CategorizationDialog rename-only preserves cached categories without renaming\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    DatabaseManager db(config_dir.path().string());\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string file_name = \"photo.jpg\";\n    std::ofstream(base / file_name).put('x');\n\n    auto resolved = db.resolve_category(\"Images\", \"Screens\");\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        file_name, \"F\", base.string(), resolved, false, std::string(), false));\n\n    CategorizedFile file;\n    file.file_path = base.string();\n    file.file_name = file_name;\n    file.type = FileType::File;\n    file.rename_only = true;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({file});\n\n    dialog.test_trigger_confirm();\n\n    const auto cached = db.get_categorized_file(base.string(), file_name, FileType::File);\n    REQUIRE(cached.has_value());\n    CHECK(cached->category == resolved.category);\n    CHECK(cached->subcategory == resolved.subcategory);\n    CHECK(cached->rename_only);\n}\n\nTEST_CASE(\"CategorizationDialog rename-only preserves cached categories when renaming\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    DatabaseManager db(config_dir.path().string());\n\n    TempDir temp_dir;\n    const std::filesystem::path base = temp_dir.path();\n    const std::string file_name = \"photo.jpg\";\n    const std::string renamed = \"sunset.jpg\";\n    const std::filesystem::path source = base / file_name;\n    const std::filesystem::path destination = base / renamed;\n    std::ofstream(source).put('x');\n\n    auto resolved = db.resolve_category(\"Images\", \"Screens\");\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        file_name, \"F\", base.string(), resolved, false, std::string(), false));\n\n    CategorizedFile file;\n    file.file_path = base.string();\n    file.file_name = file_name;\n    file.type = FileType::File;\n    file.rename_only = true;\n    file.suggested_name = renamed;\n\n    TempDir undo_dir_for_dialog;\n    CategorizationDialog dialog(&db, true, undo_dir_for_dialog.path().string());\n    dialog.test_set_entries({file});\n\n    dialog.test_trigger_confirm();\n    REQUIRE_FALSE(std::filesystem::exists(source));\n    REQUIRE(std::filesystem::exists(destination));\n\n    const auto cached = db.get_categorized_file(base.string(), renamed, FileType::File);\n    REQUIRE(cached.has_value());\n    CHECK(cached->category == resolved.category);\n    CHECK(cached->subcategory == resolved.subcategory);\n    CHECK(cached->rename_only);\n}\n#endif\n\n#endif // !_WIN32\n"
  },
  {
    "path": "tests/unit/test_checkbox_matrix.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"DocumentTextAnalyzer.hpp\"\n#include \"LlavaImageAnalyzer.hpp\"\n#include \"MainAppTestAccess.hpp\"\n#include \"Types.hpp\"\n\n#include <algorithm>\n#include <filesystem>\n#include <iostream>\n#include <sstream>\n#include <string>\n#include <unordered_set>\n#include <vector>\n\nnamespace {\n\nstruct Combo {\n    bool analyze_images;\n    bool analyze_documents;\n    bool process_images_only;\n    bool process_documents_only;\n    bool rename_images_only;\n    bool rename_documents_only;\n    bool categorize_files;\n};\n\nenum class Bucket {\n    None,\n    Image,\n    Document,\n    Other\n};\n\nstd::string combo_label(const Combo& combo) {\n    std::ostringstream out;\n    out << \"AI=\" << combo.analyze_images\n        << \" AD=\" << combo.analyze_documents\n        << \" PI=\" << combo.process_images_only\n        << \" PD=\" << combo.process_documents_only\n        << \" RI=\" << combo.rename_images_only\n        << \" RD=\" << combo.rename_documents_only\n        << \" CF=\" << combo.categorize_files;\n    return out.str();\n}\n\nbool contains_name(const std::vector<FileEntry>& entries, const std::string& name) {\n    return std::any_of(entries.begin(), entries.end(), [&name](const FileEntry& entry) {\n        return entry.file_name == name;\n    });\n}\n\nBucket expected_bucket(const FileEntry& entry,\n                       const Combo& combo,\n                       const std::unordered_set<std::string>& renamed_files) {\n    const bool restrict_types = combo.process_images_only || combo.process_documents_only;\n    const bool allow_images = !restrict_types || combo.process_images_only;\n    const bool allow_documents = !restrict_types || combo.process_documents_only;\n    const bool allow_other_files = combo.categorize_files && !restrict_types;\n\n    if (entry.type == FileType::Directory) {\n        return restrict_types ? Bucket::None : Bucket::Other;\n    }\n\n    const bool is_image = LlavaImageAnalyzer::is_supported_image(entry.full_path);\n    const bool is_document = DocumentTextAnalyzer::is_supported_document(entry.full_path);\n\n    if (is_image) {\n        if (!allow_images) {\n            return Bucket::None;\n        }\n        if (combo.analyze_images) {\n            const bool already_renamed = renamed_files.contains(entry.file_name);\n            if (already_renamed) {\n                return combo.rename_images_only ? Bucket::None : Bucket::Other;\n            }\n            return Bucket::Image;\n        }\n        return allow_other_files ? Bucket::Other : Bucket::None;\n    }\n\n    if (is_document) {\n        if (!allow_documents) {\n            return Bucket::None;\n        }\n        if (combo.analyze_documents) {\n            const bool already_renamed = renamed_files.contains(entry.file_name);\n            if (already_renamed) {\n                return combo.rename_documents_only ? Bucket::None : Bucket::Other;\n            }\n            return Bucket::Document;\n        }\n        return allow_other_files ? Bucket::Other : Bucket::None;\n    }\n\n    return allow_other_files ? Bucket::Other : Bucket::None;\n}\n\nBucket actual_bucket(const FileEntry& entry,\n                     const std::vector<FileEntry>& image_entries,\n                     const std::vector<FileEntry>& document_entries,\n                     const std::vector<FileEntry>& other_entries) {\n    const bool in_images = contains_name(image_entries, entry.file_name);\n    const bool in_docs = contains_name(document_entries, entry.file_name);\n    const bool in_other = contains_name(other_entries, entry.file_name);\n\n    const int count = static_cast<int>(in_images) + static_cast<int>(in_docs) + static_cast<int>(in_other);\n    CHECK(count <= 1);\n\n    if (in_images) {\n        return Bucket::Image;\n    }\n    if (in_docs) {\n        return Bucket::Document;\n    }\n    if (in_other) {\n        return Bucket::Other;\n    }\n    return Bucket::None;\n}\n\nvoid run_combo_matrix(const std::vector<FileEntry>& files,\n                      const std::unordered_set<std::string>& renamed_files,\n                      bool renamed_label) {\n    for (int mask = 0; mask < 128; ++mask) {\n        Combo combo{\n            static_cast<bool>(mask & (1 << 0)),\n            static_cast<bool>(mask & (1 << 1)),\n            static_cast<bool>(mask & (1 << 2)),\n            static_cast<bool>(mask & (1 << 3)),\n            static_cast<bool>(mask & (1 << 4)),\n            static_cast<bool>(mask & (1 << 5)),\n            static_cast<bool>(mask & (1 << 6))\n        };\n\n        std::vector<FileEntry> image_entries;\n        std::vector<FileEntry> document_entries;\n        std::vector<FileEntry> other_entries;\n\n        MainAppTestAccess::split_entries_for_analysis(files,\n                                                      combo.analyze_images,\n                                                      combo.analyze_documents,\n                                                      combo.process_images_only,\n                                                      combo.process_documents_only,\n                                                      combo.rename_images_only,\n                                                      combo.rename_documents_only,\n                                                      combo.categorize_files,\n                                                      false,\n                                                      renamed_files,\n                                                      image_entries,\n                                                      document_entries,\n                                                      other_entries);\n\n        std::cout << \"[combo] \" << combo_label(combo)\n                  << \" renamed=\" << renamed_label\n                  << \" -> img=\" << image_entries.size()\n                  << \" doc=\" << document_entries.size()\n                  << \" other=\" << other_entries.size()\n                  << std::endl;\n\n        INFO(combo_label(combo));\n\n        for (const auto& entry : files) {\n            const Bucket expected = expected_bucket(entry, combo, renamed_files);\n            const Bucket actual = actual_bucket(entry, image_entries, document_entries, other_entries);\n            CHECK(expected == actual);\n        }\n\n        for (const auto& entry : image_entries) {\n            CHECK(LlavaImageAnalyzer::is_supported_image(entry.full_path));\n        }\n        for (const auto& entry : document_entries) {\n            CHECK(DocumentTextAnalyzer::is_supported_document(entry.full_path));\n        }\n    }\n}\n\n} // namespace\n\nTEST_CASE(\"Checkbox combinations route entries without renamed files\") {\n    const std::vector<FileEntry> files = {\n        {\"/tmp/photo.png\", \"photo.png\", FileType::File},\n        {\"/tmp/report.pdf\", \"report.pdf\", FileType::File},\n        {\"/tmp/archive.bin\", \"archive.bin\", FileType::File},\n        {\"/tmp/folder\", \"folder\", FileType::Directory}\n    };\n\n    std::unordered_set<std::string> renamed_files;\n    run_combo_matrix(files, renamed_files, false);\n}\n\nTEST_CASE(\"Checkbox combinations route entries with renamed files\") {\n    const std::vector<FileEntry> files = {\n        {\"/tmp/photo.png\", \"photo.png\", FileType::File},\n        {\"/tmp/report.pdf\", \"report.pdf\", FileType::File},\n        {\"/tmp/archive.bin\", \"archive.bin\", FileType::File},\n        {\"/tmp/folder\", \"folder\", FileType::Directory}\n    };\n\n    std::unordered_set<std::string> renamed_files = {\"photo.png\", \"report.pdf\"};\n    run_combo_matrix(files, renamed_files, true);\n}\n"
  },
  {
    "path": "tests/unit/test_cli_reporter.cpp",
    "content": "#include <catch2/reporters/catch_reporter_event_listener.hpp>\n#include <catch2/reporters/catch_reporter_registrars.hpp>\n#include <catch2/catch_test_case_info.hpp>\n\n#include <iostream>\n\nclass TestNamePrinter : public Catch::EventListenerBase {\npublic:\n    using Catch::EventListenerBase::EventListenerBase;\n\n    void testCaseStarting(Catch::TestCaseInfo const& info) override {\n        std::cout << \"[TEST] \" << info.name << std::endl;\n    }\n};\n\nCATCH_REGISTER_LISTENER(TestNamePrinter)\n"
  },
  {
    "path": "tests/unit/test_custom_api_endpoint.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n\nTEST_CASE(\"Custom API endpoints persist across Settings load/save\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n\n    Settings settings;\n    settings.load();\n\n    CustomApiEndpoint endpoint;\n    endpoint.name = \"Local LM Studio\";\n    endpoint.description = \"Local OpenAI-compatible endpoint\";\n    endpoint.base_url = \"http://localhost:1234/v1\";\n    endpoint.api_key = \"local-key\";\n    endpoint.model = \"llama-3.1\";\n\n    const std::string id = settings.upsert_custom_api_endpoint(endpoint);\n    REQUIRE_FALSE(id.empty());\n    settings.set_active_custom_api_id(id);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    reloaded.load();\n    const CustomApiEndpoint loaded = reloaded.find_custom_api_endpoint(id);\n\n    REQUIRE(loaded.id == id);\n    REQUIRE(loaded.name == endpoint.name);\n    REQUIRE(loaded.description == endpoint.description);\n    REQUIRE(loaded.base_url == endpoint.base_url);\n    REQUIRE(loaded.api_key == endpoint.api_key);\n    REQUIRE(loaded.model == endpoint.model);\n    REQUIRE(reloaded.get_active_custom_api_id() == id);\n}\n"
  },
  {
    "path": "tests/unit/test_custom_llm.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n\nTEST_CASE(\"Custom LLM entries persist across Settings load/save\") {\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n\n    Settings settings;\n    settings.load();\n\n    CustomLLM llm;\n    llm.name = \"My Local Model\";\n    llm.path = \"/models/custom.gguf\";\n\n    const std::string id = settings.upsert_custom_llm(llm);\n    REQUIRE_FALSE(id.empty());\n    settings.set_active_custom_llm_id(id);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    reloaded.load();\n    const CustomLLM loaded = reloaded.find_custom_llm(id);\n\n    REQUIRE(loaded.id == id);\n    REQUIRE(loaded.name == llm.name);\n    REQUIRE(loaded.path == llm.path);\n    REQUIRE(reloaded.get_active_custom_llm_id() == id);\n}\n"
  },
  {
    "path": "tests/unit/test_database_manager_rename_only.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"DatabaseManager.hpp\"\n#include \"TestHelpers.hpp\"\n\nTEST_CASE(\"DatabaseManager keeps rename-only entries with empty labels\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    const std::string dir_path = \"/sample\";\n    DatabaseManager::ResolvedCategory empty{0, \"\", \"\"};\n    const std::string suggested_name = \"rename_suggestion.png\";\n\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"rename.png\", \"F\", dir_path, empty, false, suggested_name, true));\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"empty.png\", \"F\", dir_path, empty, false, std::string(), false));\n\n    const auto removed = db.remove_empty_categorizations(dir_path);\n    REQUIRE(removed.size() == 1);\n    CHECK(removed.front().file_name == \"empty.png\");\n\n    const auto entries = db.get_categorized_files(dir_path);\n    REQUIRE(entries.size() == 1);\n    CHECK(entries.front().file_name == \"rename.png\");\n    CHECK(entries.front().rename_only);\n    CHECK_FALSE(entries.front().rename_applied);\n    CHECK(entries.front().suggested_name == suggested_name);\n    CHECK(entries.front().category.empty());\n    CHECK(entries.front().subcategory.empty());\n}\n\nTEST_CASE(\"DatabaseManager keeps suggestion-only entries with empty labels\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    const std::string dir_path = \"/sample\";\n    DatabaseManager::ResolvedCategory empty{0, \"\", \"\"};\n    const std::string suggested_name = \"suggested_name.png\";\n\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"suggested.png\", \"F\", dir_path, empty, false, suggested_name, false));\n\n    const auto removed = db.remove_empty_categorizations(dir_path);\n    CHECK(removed.empty());\n\n    const auto entries = db.get_categorized_files(dir_path);\n    REQUIRE(entries.size() == 1);\n    CHECK(entries.front().file_name == \"suggested.png\");\n    CHECK_FALSE(entries.front().rename_only);\n    CHECK(entries.front().suggested_name == suggested_name);\n    CHECK(entries.front().category.empty());\n    CHECK(entries.front().subcategory.empty());\n}\n\nTEST_CASE(\"DatabaseManager sanitizes invalid UTF-8 in cached labels\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    const std::string dir_path = \"/sample\";\n    std::string invalid_category = \"Imag\";\n    invalid_category.push_back(static_cast<char>(0xFF));\n    invalid_category += \"es\";\n    std::string invalid_subcategory = \"Phot\";\n    invalid_subcategory.push_back(static_cast<char>(0xFF));\n    invalid_subcategory += \"os\";\n    std::string invalid_suggested = \"sum\";\n    invalid_suggested.push_back(static_cast<char>(0xFF));\n    invalid_suggested += \"mer.png\";\n\n    DatabaseManager::ResolvedCategory resolved{\n        0,\n        invalid_category,\n        invalid_subcategory,\n    };\n\n    REQUIRE(db.insert_or_update_file_with_categorization(\n        \"photo.png\", \"F\", dir_path, resolved, false, invalid_suggested, false));\n\n    const auto entries = db.get_categorized_files(dir_path);\n    REQUIRE(entries.size() == 1);\n    CHECK(entries.front().category == \"Images\");\n    CHECK(entries.front().subcategory == \"Photos\");\n    CHECK(entries.front().suggested_name == \"summer.png\");\n}\n\nTEST_CASE(\"DatabaseManager normalizes subcategory stopword suffixes for taxonomy matching\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    auto base = db.resolve_category(\"Images\", \"Graphics\");\n    auto with_suffix = db.resolve_category(\"Images\", \"Graphics files\");\n\n    REQUIRE(base.taxonomy_id > 0);\n    CHECK(with_suffix.taxonomy_id == base.taxonomy_id);\n    CHECK(with_suffix.category == base.category);\n    CHECK(with_suffix.subcategory == base.subcategory);\n\n    auto photos = db.resolve_category(\"Images\", \"Photos\");\n    CHECK(photos.subcategory == \"Photos\");\n}\n\nTEST_CASE(\"DatabaseManager normalizes backup category synonyms for taxonomy matching\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    auto archives = db.resolve_category(\"Archives\", \"General\");\n    auto backup = db.resolve_category(\"backup files\", \"General\");\n\n    REQUIRE(archives.taxonomy_id > 0);\n    CHECK(backup.taxonomy_id == archives.taxonomy_id);\n    CHECK(backup.category == archives.category);\n    CHECK(backup.category == \"Archives\");\n    CHECK(backup.subcategory == \"General\");\n}\n\nTEST_CASE(\"DatabaseManager normalizes image category synonyms and image media aliases\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    auto images = db.resolve_category(\"Images\", \"Photos\");\n    auto graphics = db.resolve_category(\"Graphics\", \"Photos\");\n    auto media_images = db.resolve_category(\"Media\", \"Photos\");\n    auto media_audio = db.resolve_category(\"Media\", \"Audio\");\n\n    REQUIRE(images.taxonomy_id > 0);\n    CHECK(graphics.taxonomy_id == images.taxonomy_id);\n    CHECK(media_images.taxonomy_id == images.taxonomy_id);\n    CHECK(graphics.category == \"Images\");\n    CHECK(media_images.category == \"Images\");\n\n    CHECK(media_audio.category == \"Media\");\n    CHECK(media_audio.taxonomy_id != images.taxonomy_id);\n}\n\nTEST_CASE(\"DatabaseManager normalizes document category synonyms for taxonomy matching\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    auto documents = db.resolve_category(\"Documents\", \"Reports\");\n    auto texts = db.resolve_category(\"Texts\", \"Reports\");\n    auto papers = db.resolve_category(\"Papers\", \"Reports\");\n    auto spreadsheets = db.resolve_category(\"Spreadsheets\", \"Reports\");\n\n    REQUIRE(documents.taxonomy_id > 0);\n    CHECK(texts.taxonomy_id == documents.taxonomy_id);\n    CHECK(papers.taxonomy_id == documents.taxonomy_id);\n    CHECK(spreadsheets.taxonomy_id == documents.taxonomy_id);\n    CHECK(texts.category == \"Documents\");\n    CHECK(papers.category == \"Documents\");\n    CHECK(spreadsheets.category == \"Documents\");\n}\n\nTEST_CASE(\"DatabaseManager normalizes installer and update category synonyms for taxonomy matching\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    DatabaseManager db(base_dir.path().string());\n\n    auto software = db.resolve_category(\"Software\", \"Installers\");\n    auto installers = db.resolve_category(\"Installers\", \"Installers\");\n    auto setup_files = db.resolve_category(\"Setup files\", \"Installers\");\n    auto updates = db.resolve_category(\"Software Update\", \"Installers\");\n    auto patches = db.resolve_category(\"Patches\", \"Installers\");\n\n    REQUIRE(software.taxonomy_id > 0);\n    CHECK(installers.taxonomy_id == software.taxonomy_id);\n    CHECK(setup_files.taxonomy_id == software.taxonomy_id);\n    CHECK(updates.taxonomy_id == software.taxonomy_id);\n    CHECK(patches.taxonomy_id == software.taxonomy_id);\n    CHECK(installers.category == \"Software\");\n    CHECK(setup_files.category == \"Software\");\n    CHECK(updates.category == \"Software\");\n    CHECK(patches.category == \"Software\");\n}\n"
  },
  {
    "path": "tests/unit/test_file_scanner.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"FileScanner.hpp\"\n#include \"TestHelpers.hpp\"\n#include <algorithm>\n#include <fstream>\n#include <filesystem>\n#ifdef _WIN32\n#include <windows.h>\n#else\n#include <unistd.h>\n#endif\n\nstatic void write_file(const std::filesystem::path& path) {\n    std::filesystem::create_directories(path.parent_path());\n    std::ofstream out(path);\n    out << \"data\";\n}\n\nTEST_CASE(\"hidden files require explicit flag\") {\n    TempDir temp_dir;\n    const auto hidden_file = temp_dir.path() / \".secret.txt\";\n    write_file(hidden_file);\n#ifdef _WIN32\n    auto current_attrs = GetFileAttributesW(hidden_file.c_str());\n    if (current_attrs == INVALID_FILE_ATTRIBUTES) {\n        FAIL(\"Failed to get attributes for hidden test file\");\n    }\n    SetFileAttributesW(hidden_file.c_str(), current_attrs | FILE_ATTRIBUTE_HIDDEN);\n#endif\n\n    FileScanner scanner;\n    auto entries = scanner.get_directory_entries(temp_dir.path().string(),\n        FileScanOptions::Files);\n    REQUIRE(entries.empty());\n\n    entries = scanner.get_directory_entries(temp_dir.path().string(),\n        FileScanOptions::Files | FileScanOptions::HiddenFiles);\n    REQUIRE(entries.size() == 1);\n    CHECK(entries.front().file_name == \".secret.txt\");\n    CHECK(entries.front().type == FileType::File);\n}\n\nTEST_CASE(\"junk files are skipped regardless of flags\") {\n    TempDir temp_dir;\n    const auto junk_file = temp_dir.path() / \".DS_Store\";\n    write_file(junk_file);\n\n    FileScanner scanner;\n    auto entries = scanner.get_directory_entries(temp_dir.path().string(),\n        FileScanOptions::Files | FileScanOptions::HiddenFiles);\n    REQUIRE(entries.empty());\n}\n\nTEST_CASE(\"application bundles are treated as files\") {\n    TempDir temp_dir;\n    const auto bundle_dir = temp_dir.path() / \"Sample.app\";\n    std::filesystem::create_directories(bundle_dir / \"Contents\");\n\n    FileScanner scanner;\n    auto file_entries = scanner.get_directory_entries(temp_dir.path().string(),\n        FileScanOptions::Files);\n    REQUIRE(file_entries.size() == 1);\n    CHECK(file_entries.front().file_name == \"Sample.app\");\n    CHECK(file_entries.front().type == FileType::File);\n\n    auto dir_entries = scanner.get_directory_entries(temp_dir.path().string(),\n        FileScanOptions::Directories);\n    REQUIRE(dir_entries.empty());\n}\n\nTEST_CASE(\"recursive scans include nested files\") {\n    TempDir temp_dir;\n    write_file(temp_dir.path() / \"top.txt\");\n    write_file(temp_dir.path() / \"nested\" / \"deep.txt\");\n\n    FileScanner scanner;\n    const auto entries = scanner.get_directory_entries(\n        temp_dir.path().string(),\n        FileScanOptions::Files | FileScanOptions::Recursive);\n\n    REQUIRE(entries.size() == 2);\n    CHECK(std::any_of(entries.begin(), entries.end(), [](const FileEntry& entry) {\n        return entry.file_name == \"top.txt\";\n    }));\n    CHECK(std::any_of(entries.begin(), entries.end(), [](const FileEntry& entry) {\n        return entry.file_name == \"deep.txt\";\n    }));\n}\n\n#ifndef _WIN32\nclass PermissionRestore {\npublic:\n    explicit PermissionRestore(std::filesystem::path path)\n        : path_(std::move(path))\n    {\n    }\n\n    ~PermissionRestore() {\n        std::error_code ec;\n        std::filesystem::permissions(\n            path_,\n            std::filesystem::perms::owner_all,\n            std::filesystem::perm_options::add,\n            ec);\n    }\n\nprivate:\n    std::filesystem::path path_;\n};\n\nTEST_CASE(\"recursive scans skip unreadable directories and continue\") {\n    TempDir temp_dir;\n    const auto readable_file = temp_dir.path() / \"readable\" / \"keep.txt\";\n    const auto blocked_dir = temp_dir.path() / \"blocked\";\n    const auto blocked_file = blocked_dir / \"skip.txt\";\n\n    write_file(readable_file);\n    write_file(blocked_file);\n    PermissionRestore restore_permissions(blocked_dir);\n\n    std::error_code ec;\n    std::filesystem::permissions(\n        blocked_dir,\n        std::filesystem::perms::owner_all |\n            std::filesystem::perms::group_all |\n            std::filesystem::perms::others_all,\n        std::filesystem::perm_options::remove,\n        ec);\n    REQUIRE(!ec);\n\n    if (::access(blocked_dir.c_str(), R_OK | X_OK) == 0) {\n        SKIP(\"permission restrictions are not enforced in this test environment\");\n    }\n\n    FileScanner scanner;\n    std::vector<FileEntry> entries;\n    REQUIRE_NOTHROW(entries = scanner.get_directory_entries(\n        temp_dir.path().string(),\n        FileScanOptions::Files | FileScanOptions::Recursive));\n\n    REQUIRE(entries.size() == 1);\n    CHECK(entries.front().file_name == \"keep.txt\");\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_ggml_runtime_paths.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"GgmlRuntimePaths.hpp\"\n#include \"TestHelpers.hpp\"\n\n#include <algorithm>\n#include <fstream>\n\nTEST_CASE(\"macOS ggml runtime candidates stay relative to the app layout\") {\n    const std::filesystem::path exe =\n        \"/tmp/AIFileSorter.app/Contents/MacOS/aifilesorter\";\n\n    const auto candidates =\n        GgmlRuntimePaths::macos_candidate_dirs(exe, \"precompiled-m2\");\n\n    REQUIRE_FALSE(candidates.empty());\n    REQUIRE(candidates[0] ==\n            std::filesystem::path(\"/tmp/AIFileSorter.app/Contents/MacOS/../lib/precompiled-m1\"));\n    REQUIRE(candidates[1] ==\n            std::filesystem::path(\"/tmp/AIFileSorter.app/Contents/MacOS/../lib/precompiled-m2\"));\n    REQUIRE(candidates[5] ==\n            std::filesystem::path(\"/tmp/AIFileSorter.app/Contents/MacOS/../lib/aifilesorter\"));\n    REQUIRE(candidates[6] ==\n            std::filesystem::path(\"/tmp/AIFileSorter.app/Contents/MacOS/../../lib/aifilesorter\"));\n    REQUIRE(std::find(candidates.begin(),\n                      candidates.end(),\n                      std::filesystem::path(\"/usr/local/lib\")) == candidates.end());\n    REQUIRE(std::find(candidates.begin(),\n                      candidates.end(),\n                      std::filesystem::path(\"/opt/homebrew/lib\")) == candidates.end());\n}\n\nTEST_CASE(\"macOS ggml runtime resolution prefers bundled directories over generic siblings\") {\n    TempDir temp_dir;\n    const auto root = temp_dir.path();\n    const auto exe = root / \"bin\" / \"m2\" / \"aifilesorter\";\n    const auto bundled = root / \"lib\" / \"precompiled-m2\";\n    const auto generic = root / \"lib\" / \"aifilesorter\";\n\n    std::filesystem::create_directories(exe.parent_path());\n    std::ofstream(exe).put('x');\n\n    std::filesystem::create_directories(bundled);\n    std::ofstream(bundled / \"libggml-metal.dylib\").put('x');\n\n    std::filesystem::create_directories(generic);\n    std::ofstream(generic / \"libggml-cpu.dylib\").put('x');\n\n    const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir(\n        std::nullopt,\n        exe,\n        \"precompiled-m2\");\n\n    REQUIRE(resolved.has_value());\n    REQUIRE(*resolved == bundled);\n}\n\nTEST_CASE(\"macOS ggml runtime resolution preserves a valid explicit override\") {\n    TempDir temp_dir;\n    const auto root = temp_dir.path();\n    const auto exe = root / \"bin\" / \"aifilesorter\";\n    const auto custom = root / \"custom-ggml\";\n\n    std::filesystem::create_directories(exe.parent_path());\n    std::ofstream(exe).put('x');\n\n    std::filesystem::create_directories(custom);\n    std::ofstream(custom / \"libggml-blas.dylib\").put('x');\n\n    const auto resolved = GgmlRuntimePaths::resolve_macos_backend_dir(\n        custom,\n        exe,\n        \"precompiled\");\n\n    REQUIRE(resolved.has_value());\n    REQUIRE(*resolved == custom);\n}\n"
  },
  {
    "path": "tests/unit/test_image_rename_metadata_service.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"ImageRenameMetadataService.hpp\"\n\n#include <chrono>\n#include <cstdlib>\n#include <filesystem>\n#include <fstream>\n#include <optional>\n#include <string>\n#include <vector>\n\nnamespace {\n\nvoid append_u16_le(std::vector<uint8_t>& buffer, uint16_t value)\n{\n    buffer.push_back(static_cast<uint8_t>(value & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));\n}\n\nvoid append_u32_le(std::vector<uint8_t>& buffer, uint32_t value)\n{\n    buffer.push_back(static_cast<uint8_t>(value & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));\n}\n\nvoid append_u32_be(std::vector<uint8_t>& buffer, uint32_t value)\n{\n    buffer.push_back(static_cast<uint8_t>((value >> 24) & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 16) & 0xFF));\n    buffer.push_back(static_cast<uint8_t>((value >> 8) & 0xFF));\n    buffer.push_back(static_cast<uint8_t>(value & 0xFF));\n}\n\nstd::vector<uint8_t> make_tiff_with_datetime(const std::string& datetime)\n{\n    std::string text = datetime;\n    text.push_back('\\0');\n\n    std::vector<uint8_t> tiff;\n    tiff.reserve(8 + 2 + 12 + 4 + text.size());\n\n    // TIFF header (little-endian) + first IFD offset.\n    tiff.push_back('I');\n    tiff.push_back('I');\n    append_u16_le(tiff, 42);\n    append_u32_le(tiff, 8);\n\n    // IFD0 with one DateTime entry.\n    append_u16_le(tiff, 1);\n    append_u16_le(tiff, 0x0132); // DateTime\n    append_u16_le(tiff, 2);      // ASCII\n    append_u32_le(tiff, static_cast<uint32_t>(text.size()));\n    append_u32_le(tiff, 8 + 2 + 12 + 4); // data offset after IFD0 + next-ifd ptr\n    append_u32_le(tiff, 0);              // next IFD\n\n    tiff.insert(tiff.end(), text.begin(), text.end());\n    return tiff;\n}\n\nstd::vector<uint8_t> make_png_with_exif_chunk(const std::vector<uint8_t>& tiff_payload)\n{\n    std::vector<uint8_t> png = {\n        0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A\n    };\n\n    append_u32_be(png, static_cast<uint32_t>(tiff_payload.size()));\n    png.push_back('e');\n    png.push_back('X');\n    png.push_back('I');\n    png.push_back('f');\n    png.insert(png.end(), tiff_payload.begin(), tiff_payload.end());\n    append_u32_be(png, 0); // CRC is not validated by parser.\n\n    append_u32_be(png, 0);\n    png.push_back('I');\n    png.push_back('E');\n    png.push_back('N');\n    png.push_back('D');\n    append_u32_be(png, 0);\n\n    return png;\n}\n\nvoid write_binary_file(const std::filesystem::path& path, const std::vector<uint8_t>& bytes)\n{\n    std::ofstream out(path, std::ios::binary | std::ios::trunc);\n    REQUIRE(out.good());\n    out.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));\n    REQUIRE(out.good());\n}\n\nstd::filesystem::path make_temp_dir(const std::string& suffix)\n{\n    const auto stamp = std::chrono::steady_clock::now().time_since_epoch().count();\n    const auto dir = std::filesystem::temp_directory_path() /\n                     (\"aifs_image_metadata_\" + suffix + \"_\" + std::to_string(stamp));\n    std::filesystem::create_directories(dir);\n    return dir;\n}\n\nvoid set_path_value(const std::string& value)\n{\n#if defined(_WIN32)\n    _putenv_s(\"PATH\", value.c_str());\n#else\n    setenv(\"PATH\", value.c_str(), 1);\n#endif\n}\n\nvoid clear_path_value()\n{\n#if defined(_WIN32)\n    _putenv_s(\"PATH\", \"\");\n#else\n    unsetenv(\"PATH\");\n#endif\n}\n\nclass PathGuard {\npublic:\n    PathGuard()\n    {\n        const char* existing = std::getenv(\"PATH\");\n        if (existing) {\n            had_value_ = true;\n            old_value_ = existing;\n        }\n    }\n\n    ~PathGuard()\n    {\n        if (had_value_) {\n            set_path_value(old_value_);\n        } else {\n            clear_path_value();\n        }\n    }\n\nprivate:\n    bool had_value_{false};\n    std::string old_value_;\n};\n\n} // namespace\n\nTEST_CASE(\"ImageRenameMetadataService composes date and place prefixes\") {\n    const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename(\n        \"black_ducks_row.jpg\",\n        std::optional<std::string>(\"2014-03-10\"),\n        std::optional<std::string>(\"Venice\"));\n\n    CHECK(actual == \"2014-03-10_venice_black_ducks_row.jpg\");\n}\n\nTEST_CASE(\"ImageRenameMetadataService skips prefix duplication\") {\n    const std::string already_prefixed = \"2014-03-10_venice_black_ducks_row.jpg\";\n    const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename(\n        already_prefixed,\n        std::optional<std::string>(\"2014-03-10\"),\n        std::optional<std::string>(\"venice\"));\n\n    CHECK(actual == already_prefixed);\n}\n\nTEST_CASE(\"ImageRenameMetadataService sanitizes place labels\") {\n    const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename(\n        \"street_market.jpg\",\n        std::optional<std::string>(\"2020-01-05\"),\n        std::optional<std::string>(\"New York City\"));\n\n    CHECK(actual == \"2020-01-05_new_york_city_street_market.jpg\");\n}\n\nTEST_CASE(\"ImageRenameMetadataService returns original when no prefix data\") {\n    const std::string original = \"sunset.jpg\";\n    const std::string actual = ImageRenameMetadataService::apply_prefix_to_filename(\n        original,\n        std::nullopt,\n        std::nullopt);\n\n    CHECK(actual == original);\n}\n\nTEST_CASE(\"ImageRenameMetadataService reads TIFF date metadata for rename prefix\")\n{\n    const auto temp_dir = make_temp_dir(\"tiff\");\n    const auto image_path = temp_dir / \"sample.tiff\";\n    write_binary_file(image_path, make_tiff_with_datetime(\"2014:03:10 12:00:00\"));\n\n    {\n        ImageRenameMetadataService service(temp_dir.string());\n        const std::string actual = service.enrich_suggested_name(image_path, \"black_ducks_row.tiff\");\n\n        CHECK(actual == \"2014-03-10_black_ducks_row.tiff\");\n    }\n    std::filesystem::remove_all(temp_dir);\n}\n\nTEST_CASE(\"ImageRenameMetadataService extracts TIFF capture date\")\n{\n    const auto temp_dir = make_temp_dir(\"tiff_date\");\n    const auto image_path = temp_dir / \"sample.tiff\";\n    write_binary_file(image_path, make_tiff_with_datetime(\"2016:11:04 09:30:00\"));\n\n    {\n        ImageRenameMetadataService service(temp_dir.string());\n        const auto date = service.extract_capture_date(image_path);\n\n        REQUIRE(date.has_value());\n        CHECK(*date == \"2016-11-04\");\n    }\n    std::filesystem::remove_all(temp_dir);\n}\n\nTEST_CASE(\"ImageRenameMetadataService reads PNG eXIf date metadata for rename prefix\")\n{\n    const auto temp_dir = make_temp_dir(\"png\");\n    const auto image_path = temp_dir / \"sample.png\";\n    const auto tiff_payload = make_tiff_with_datetime(\"2021:09:17 08:45:30\");\n    write_binary_file(image_path, make_png_with_exif_chunk(tiff_payload));\n\n    {\n        ImageRenameMetadataService service(temp_dir.string());\n        const std::string actual = service.enrich_suggested_name(image_path, \"street_market.png\");\n\n        CHECK(actual == \"2021-09-17_street_market.png\");\n    }\n    std::filesystem::remove_all(temp_dir);\n}\n\n#if !defined(_WIN32)\nTEST_CASE(\"ImageRenameMetadataService reads HEIC date metadata via exiftool fallback\")\n{\n    const auto temp_dir = make_temp_dir(\"heic\");\n    const auto image_path = temp_dir / \"sample.heic\";\n    write_binary_file(image_path, std::vector<uint8_t>{0x00, 0x00, 0x00, 0x00});\n\n    const auto exiftool_path = temp_dir / \"exiftool\";\n    {\n        std::ofstream script(exiftool_path, std::ios::binary | std::ios::trunc);\n        REQUIRE(script.good());\n        script << \"#!/bin/sh\\n\";\n        script << \"printf '[{\\\"DateTimeOriginal\\\":\\\"2019:07:11 14:20:00\\\"}]\\\\n'\\n\";\n        REQUIRE(script.good());\n    }\n    std::filesystem::permissions(exiftool_path,\n                                 std::filesystem::perms::owner_exec |\n                                 std::filesystem::perms::group_exec |\n                                 std::filesystem::perms::others_exec,\n                                 std::filesystem::perm_options::add);\n\n    PathGuard path_guard;\n    const std::string old_path = std::getenv(\"PATH\") ? std::getenv(\"PATH\") : \"\";\n    const std::string new_path = temp_dir.string() + \":\" + old_path;\n    set_path_value(new_path);\n\n    {\n        ImageRenameMetadataService service(temp_dir.string());\n        const std::string actual = service.enrich_suggested_name(image_path, \"trip.heic\");\n\n        CHECK(actual == \"2019-07-11_trip.heic\");\n    }\n    std::filesystem::remove_all(temp_dir);\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_llava_image_analyzer.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"LlavaImageAnalyzer.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"TestHooks.hpp\"\n\n#ifndef GGML_USE_METAL\nnamespace {\n\nstruct BackendProbeGuard {\n    ~BackendProbeGuard() {\n        TestHooks::reset_backend_memory_probe();\n        TestHooks::reset_backend_availability_probe();\n    }\n};\n\n} // namespace\n#endif\n\nTEST_CASE(\"LlavaImageAnalyzer uses conservative default visual batch sizing\") {\n    CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(false, \"vulkan\") == 512);\n    CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, \"metal\") == 1024);\n    CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, \"vulkan\") == 512);\n#if defined(_WIN32)\n    CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, \"cuda\") == 512);\n#else\n    CHECK(LlavaImageAnalyzerTestAccess::default_visual_batch_size(true, \"cuda\") == 768);\n#endif\n}\n\n#ifndef GGML_USE_METAL\nTEST_CASE(\"LlavaImageAnalyzer ignores global GPU layer override by default\") {\n    TempModelFile model(48, 8 * 1024 * 1024);\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard global_override(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"30\");\n    EnvVarGuard visual_override(\"AI_FILE_SORTER_VISUAL_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_override(\"LLAMA_CPP_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n    TestHooks::set_backend_memory_probe([](std::string_view) {\n        TestHooks::BackendMemoryInfo info;\n        info.memory.free_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL;\n        info.memory.total_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL;\n        info.is_integrated = false;\n        info.name = \"Visual Test GPU\";\n        return info;\n    });\n\n    const int32_t actual =\n        LlavaImageAnalyzerTestAccess::visual_model_n_gpu_layers_for_model(model.path().string());\n    CHECK(actual != 30);\n    CHECK(actual > 0);\n}\n\nTEST_CASE(\"LlavaImageAnalyzer honors visual-specific GPU layer override\") {\n    TempModelFile model(48, 8 * 1024 * 1024);\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard global_override(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"30\");\n    EnvVarGuard visual_override(\"AI_FILE_SORTER_VISUAL_N_GPU_LAYERS\", \"12\");\n    EnvVarGuard llama_override(\"LLAMA_CPP_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n    TestHooks::set_backend_memory_probe([](std::string_view) {\n        return std::nullopt;\n    });\n\n    const int32_t actual =\n        LlavaImageAnalyzerTestAccess::visual_model_n_gpu_layers_for_model(model.path().string());\n    CHECK(actual == 12);\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_llm_downloader.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include <atomic>\n#include <chrono>\n#include <filesystem>\n#include <fstream>\n#include <future>\n\n#include \"LLMDownloader.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"TestHooks.hpp\"\n#include \"Utils.hpp\"\n\nnamespace {\n\nvoid write_bytes(const std::filesystem::path& path, std::size_t count) {\n    std::filesystem::create_directories(path.parent_path());\n    std::ofstream out(path, std::ios::binary | std::ios::trunc);\n    for (std::size_t i = 0; i < count; ++i) {\n        out.put('x');\n    }\n}\n\nvoid write_metadata(const std::filesystem::path& path,\n                    const std::string& url,\n                    long long content_length) {\n    std::filesystem::create_directories(path.parent_path());\n    std::ofstream out(path, std::ios::trunc);\n    out << \"url=\" << url << \"\\n\";\n    out << \"content_length=\" << content_length << \"\\n\";\n}\n\nstd::string make_unique_url() {\n    return std::string(\"http://example.com/\") + make_unique_token(\"model-\") + \".gguf\";\n}\n\n} // namespace\n\nTEST_CASE(\"LLMDownloader retries full download after a range error\") {\n    TempDir tmp;\n    const auto destination = (tmp.path() / \"model.gguf\").string();\n    const auto partial_destination = destination + \".part\";\n\n    {\n        std::ofstream out(destination, std::ios::binary);\n        out << \"abc\";\n    }\n\n    LLMDownloader downloader(\"http://example.com/model.gguf\");\n    LLMDownloader::LLMDownloaderTestAccess::set_download_destination(downloader, destination);\n    LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(downloader, 6);\n\n    std::atomic<int> attempts{0};\n    TestHooks::set_llm_download_probe(\n        [&](long offset, const std::string& path) -> CURLcode {\n            ++attempts;\n            if (attempts == 1) {\n                REQUIRE(offset == 3);\n                REQUIRE(path == partial_destination);\n                return CURLE_HTTP_RANGE_ERROR;\n            }\n            REQUIRE(offset == 0);\n            REQUIRE(path == partial_destination);\n            std::ofstream out(path, std::ios::binary | std::ios::trunc);\n            out << \"abcdef\";\n            return CURLE_OK;\n        });\n\n    std::promise<void> done;\n    std::future<void> finished = done.get_future();\n    std::atomic<bool> success{false};\n    std::string error_text;\n\n    downloader.start_download(\n        [](double) {},\n        [&]() {\n            success = true;\n            done.set_value();\n        },\n        nullptr,\n        [&](const std::string& err) {\n            error_text = err;\n            done.set_value();\n        });\n\n    const auto status = finished.wait_for(std::chrono::seconds(2));\n    TestHooks::reset_llm_download_probe();\n    REQUIRE(status == std::future_status::ready);\n    REQUIRE(error_text.empty());\n    REQUIRE(success.load());\n    REQUIRE(attempts.load() == 2);\n    REQUIRE(std::filesystem::file_size(destination) == 6);\n    REQUIRE_FALSE(std::filesystem::exists(partial_destination));\n}\n\nTEST_CASE(\"LLMDownloader uses cached metadata for partial downloads\") {\n    TempDir tmp;\n    EnvVarGuard home_guard(\"HOME\", tmp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", tmp.path().string());\n#endif\n\n    const std::string url = make_unique_url();\n    const std::filesystem::path destination =\n        Utils::make_default_path_to_file_from_download_url(url);\n    const std::filesystem::path metadata = destination.string() + \".aifs.meta\";\n\n    write_bytes(destination, 4);\n    write_metadata(metadata, url, 16);\n\n    LLMDownloader downloader(url);\n    CHECK(downloader.get_real_content_length() == 16);\n    CHECK_FALSE(std::filesystem::exists(destination));\n    CHECK(std::filesystem::exists(destination.string() + \".part\"));\n    CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::InProgress);\n    CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::InProgress);\n    CHECK_FALSE(downloader.is_inited());\n}\n\nTEST_CASE(\"LLMDownloader resets to not started when local file is missing\") {\n    TempDir tmp;\n    EnvVarGuard home_guard(\"HOME\", tmp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", tmp.path().string());\n#endif\n\n    const std::string url = make_unique_url();\n    const std::filesystem::path destination =\n        Utils::make_default_path_to_file_from_download_url(url);\n    const std::filesystem::path metadata = destination.string() + \".aifs.meta\";\n\n    write_metadata(metadata, url, 16);\n\n    LLMDownloader downloader(url);\n    CHECK(downloader.get_real_content_length() == 16);\n    CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::NotStarted);\n    CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::NotStarted);\n    CHECK_FALSE(downloader.is_inited());\n}\n\nTEST_CASE(\"LLMDownloader treats full local file as complete with cached metadata\") {\n    TempDir tmp;\n    EnvVarGuard home_guard(\"HOME\", tmp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", tmp.path().string());\n#endif\n\n    const std::string url = make_unique_url();\n    const std::filesystem::path destination =\n        Utils::make_default_path_to_file_from_download_url(url);\n    const std::filesystem::path metadata = destination.string() + \".aifs.meta\";\n\n    write_bytes(destination, 16);\n    write_metadata(metadata, url, 16);\n\n    LLMDownloader downloader(url);\n    CHECK(downloader.get_real_content_length() == 16);\n    CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::Complete);\n    CHECK(downloader.get_download_status() == LLMDownloader::DownloadStatus::Complete);\n    CHECK_FALSE(downloader.is_inited());\n}\n\nTEST_CASE(\"LLMDownloader keeps final model intact while partial temp download exists\") {\n    TempDir tmp;\n    EnvVarGuard home_guard(\"HOME\", tmp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", tmp.path().string());\n#endif\n\n    const std::string url = make_unique_url();\n    const std::filesystem::path destination =\n        Utils::make_default_path_to_file_from_download_url(url);\n    const std::filesystem::path partial = destination.string() + \".part\";\n    const std::filesystem::path metadata = destination.string() + \".aifs.meta\";\n\n    write_bytes(destination, 16);\n    write_bytes(partial, 4);\n    write_metadata(metadata, url, 16);\n\n    LLMDownloader downloader(url);\n    CHECK(downloader.get_local_download_status() == LLMDownloader::DownloadStatus::InProgress);\n    CHECK_FALSE(downloader.is_download_complete());\n    CHECK(std::filesystem::file_size(destination) == 16);\n    CHECK(std::filesystem::file_size(partial) == 4);\n}\n"
  },
  {
    "path": "tests/unit/test_llm_selection_dialog_visual.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"LLMDownloader.hpp\"\n#include \"LLMSelectionDialog.hpp\"\n#include \"LLMSelectionDialogTestAccess.hpp\"\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"TestHooks.hpp\"\n#include \"Utils.hpp\"\n\n#include <QCoreApplication>\n#include <QEventLoop>\n#include <QLabel>\n#include <QPushButton>\n\n#include <curl/curl.h>\n#include <chrono>\n#include <filesystem>\n#include <fstream>\n#include <thread>\n\n#ifndef _WIN32\nnamespace {\n\nstd::string file_url_for(const std::filesystem::path& path)\n{\n    return std::string(\"file://\") + path.string();\n}\n\nvoid write_bytes(const std::filesystem::path& path, std::size_t count)\n{\n    std::filesystem::create_directories(path.parent_path());\n    std::ofstream out(path, std::ios::binary | std::ios::trunc);\n    for (std::size_t i = 0; i < count; ++i) {\n        out.put('x');\n    }\n}\n\nbool wait_for_label(QLabel* label, const QString& starts_with, std::chrono::milliseconds timeout)\n{\n    const auto deadline = std::chrono::steady_clock::now() + timeout;\n    while (std::chrono::steady_clock::now() < deadline) {\n        QCoreApplication::processEvents(QEventLoop::AllEvents, 25);\n        if (label && label->text().startsWith(starts_with)) {\n            return true;\n        }\n        std::this_thread::sleep_for(std::chrono::milliseconds(5));\n    }\n    return label && label->text().startsWith(starts_with);\n}\n\n} // namespace\n\nTEST_CASE(\"Visual LLaVA entry shows missing env var state\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard llava_model_guard(\"LLAVA_MODEL_URL\", std::nullopt);\n    EnvVarGuard llava_mmproj_guard(\"LLAVA_MMPROJ_URL\", std::nullopt);\n\n    Settings settings;\n    LLMSelectionDialog dialog(settings);\n\n    const auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog);\n    REQUIRE(entry.status_label != nullptr);\n    REQUIRE(entry.download_button != nullptr);\n    CHECK(entry.status_label->text() ==\n          QStringLiteral(\"Missing download URL environment variable (LLAVA_MODEL_URL).\"));\n    CHECK_FALSE(entry.download_button->isEnabled());\n}\n\nTEST_CASE(\"Visual LLaVA entry shows resume state for partial downloads\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    const std::filesystem::path source_file = temp.path() / \"llava-model.gguf\";\n    write_bytes(source_file, 16);\n    const std::string model_url = file_url_for(source_file);\n\n    EnvVarGuard llava_model_guard(\"LLAVA_MODEL_URL\", model_url);\n    EnvVarGuard llava_mmproj_guard(\"LLAVA_MMPROJ_URL\", std::nullopt);\n\n    Settings settings;\n    LLMSelectionDialog dialog(settings);\n\n    auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog);\n    REQUIRE(entry.download_button != nullptr);\n    REQUIRE(entry.status_label != nullptr);\n    REQUIRE(entry.downloader != nullptr);\n\n    const std::filesystem::path dest_path =\n        Utils::make_default_path_to_file_from_download_url(model_url);\n    write_bytes(dest_path, 4);\n    LLMDownloader::LLMDownloaderTestAccess::set_resume_headers(*entry.downloader, 16);\n\n    LLMSelectionDialogTestAccess::update_llava_model_entry(dialog);\n\n    CHECK(entry.status_label->text() == QStringLiteral(\"Partial download detected. You can resume.\"));\n    CHECK(entry.download_button->text() == QStringLiteral(\"Resume download\"));\n    CHECK(entry.download_button->isEnabled());\n}\n\nTEST_CASE(\"Visual LLaVA entry reports download errors\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    const std::filesystem::path source_file = temp.path() / \"llava-model.gguf\";\n    write_bytes(source_file, 16);\n    const std::string model_url = file_url_for(source_file);\n\n    EnvVarGuard llava_model_guard(\"LLAVA_MODEL_URL\", model_url);\n    EnvVarGuard llava_mmproj_guard(\"LLAVA_MMPROJ_URL\", std::nullopt);\n\n    Settings settings;\n    LLMSelectionDialog dialog(settings);\n    LLMSelectionDialogTestAccess::set_network_available_override(dialog, true);\n\n    auto entry = LLMSelectionDialogTestAccess::llava_model_entry(dialog);\n    REQUIRE(entry.status_label != nullptr);\n    REQUIRE(entry.downloader != nullptr);\n\n    TestHooks::set_llm_download_probe([](long, const std::string&) {\n        return CURLE_COULDNT_CONNECT;\n    });\n\n    LLMSelectionDialogTestAccess::start_llava_model_download(dialog);\n\n    const bool updated = wait_for_label(entry.status_label,\n                                        QStringLiteral(\"Download error:\"),\n                                        std::chrono::milliseconds(300));\n    CHECK(updated);\n\n    TestHooks::reset_llm_download_probe();\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_local_llm_backend.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"LocalLLMClient.hpp\"\n#include \"LocalLLMTestAccess.hpp\"\n#include \"TestHooks.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Utils.hpp\"\n\n#ifndef GGML_USE_METAL\n\nnamespace {\n\nstruct CudaProbeGuard {\n    ~CudaProbeGuard() {\n        TestHooks::reset_cuda_availability_probe();\n        TestHooks::reset_cuda_memory_probe();\n    }\n};\n\nstruct BackendProbeGuard {\n    ~BackendProbeGuard() {\n        TestHooks::reset_backend_memory_probe();\n        TestHooks::reset_backend_availability_probe();\n    }\n};\n\n} // namespace\n\nTEST_CASE(\"detect_preferred_backend reads environment\") {\n    EnvVarGuard guard(\"AI_FILE_SORTER_GPU_BACKEND\", \"cuda\");\n    REQUIRE(LocalLLMTestAccess::detect_preferred_backend() ==\n            LocalLLMTestAccess::BackendPreference::Cuda);\n}\n\nTEST_CASE(\"CPU backend is honored when forced\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"cpu\");\n    EnvVarGuard disable_cuda(\"GGML_DISABLE_CUDA\", std::nullopt);\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 0);\n}\n\nTEST_CASE(\"CUDA backend can be forced off via GGML_DISABLE_CUDA\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"cuda\");\n    EnvVarGuard disable_cuda(\"GGML_DISABLE_CUDA\", \"1\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n    CudaProbeGuard guard;\n    TestHooks::set_cuda_availability_probe([] { return true; });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 0);\n}\n\nTEST_CASE(\"CUDA override is applied when backend is available\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"cuda\");\n    EnvVarGuard disable_cuda(\"GGML_DISABLE_CUDA\", std::nullopt);\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"7\");\n    CudaProbeGuard guard;\n    TestHooks::set_cuda_availability_probe([] { return true; });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 7);\n}\n\nTEST_CASE(\"CUDA fallback when no GPU is available\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"cuda\");\n    EnvVarGuard disable_cuda(\"GGML_DISABLE_CUDA\", std::nullopt);\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n    CudaProbeGuard guard;\n    TestHooks::set_cuda_availability_probe([] { return false; });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE((params.n_gpu_layers == 0 || params.n_gpu_layers == -1));\n}\n\nTEST_CASE(\"Vulkan backend honors explicit override\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"12\");\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n    TestHooks::set_backend_memory_probe([](std::string_view) {\n        return std::nullopt;\n    });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 12);\n}\n\nTEST_CASE(\"Vulkan backend derives layer count from memory probe\") {\n    TempModelFile model(48, 8 * 1024 * 1024);\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n\n    TestHooks::set_backend_memory_probe([](std::string_view) {\n        TestHooks::BackendMemoryInfo info;\n        info.memory.free_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL;\n        info.memory.total_bytes = 3ULL * 1024ULL * 1024ULL * 1024ULL;\n        info.is_integrated = false;\n        info.name = \"Vulkan Test GPU\";\n        return info;\n    });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers > 0);\n    REQUIRE(params.n_gpu_layers <= 48);\n}\n\nTEST_CASE(\"Vulkan backend falls back to CPU when memory metrics are unavailable\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n    TestHooks::set_backend_memory_probe([](std::string_view) {\n        return std::nullopt;\n    });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 0);\n}\n\nTEST_CASE(\"Vulkan backend falls back to CPU when unavailable\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", std::nullopt);\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return false;\n    });\n\n    auto params = LocalLLMTestAccess::prepare_model_params_for_testing(\n        model.path().string());\n    REQUIRE(params.n_gpu_layers == 0);\n}\n\nTEST_CASE(\"LocalLLMClient declines GPU fallback when callback returns false\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"1\");\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n\n    bool called = false;\n    try {\n        LocalLLMClient client(model.path().string(),\n                              [&called](const std::string&) {\n                                  called = true;\n                                  return false;\n                              });\n        FAIL(\"Expected LocalLLMClient to throw when CPU fallback is declined\");\n    } catch (const std::runtime_error& ex) {\n        REQUIRE(called);\n        REQUIRE(std::string(ex.what()).find(\"CPU fallback was declined\") != std::string::npos);\n    }\n}\n\nTEST_CASE(\"LocalLLMClient retries on CPU when fallback is accepted\") {\n    TempModelFile model;\n    EnvVarGuard backend(\"AI_FILE_SORTER_GPU_BACKEND\", \"vulkan\");\n    EnvVarGuard override_ngl(\"AI_FILE_SORTER_N_GPU_LAYERS\", \"1\");\n    EnvVarGuard llama_device(\"LLAMA_ARG_DEVICE\", std::nullopt);\n    BackendProbeGuard guard;\n    TestHooks::set_backend_availability_probe([](std::string_view) {\n        return true;\n    });\n\n    bool called = false;\n    try {\n        LocalLLMClient client(model.path().string(),\n                              [&called](const std::string&) {\n                                  called = true;\n                                  return true;\n                              });\n        FAIL(\"Expected LocalLLMClient to throw due to invalid model\");\n    } catch (const std::runtime_error& ex) {\n        REQUIRE(called);\n        REQUIRE(std::string(ex.what()).find(\"Failed to load model\") != std::string::npos);\n    }\n}\n#endif // GGML_USE_METAL\n"
  },
  {
    "path": "tests/unit/test_main_app_image_options.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"MainApp.hpp\"\n#include \"MainAppTestAccess.hpp\"\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Utils.hpp\"\n\n#include <QApplication>\n#include <QCheckBox>\n#include <QToolButton>\n#include <algorithm>\n#include <filesystem>\n#include <fstream>\n#include <unordered_set>\n#include <vector>\n\n#ifndef _WIN32\nnamespace {\n\nvoid create_visual_llm_files()\n{\n    const std::string model_url = \"https://example.com/llava-model.gguf\";\n    const std::string mmproj_url = \"https://example.com/mmproj-model-f16.gguf\";\n\n    const std::filesystem::path model_path =\n        Utils::make_default_path_to_file_from_download_url(model_url);\n    const std::filesystem::path mmproj_path =\n        Utils::make_default_path_to_file_from_download_url(mmproj_url);\n\n    std::filesystem::create_directories(model_path.parent_path());\n    std::ofstream(model_path.string(), std::ios::binary).put('x');\n    std::ofstream(mmproj_path.string(), std::ios::binary).put('x');\n}\n\n} // namespace\n\nTEST_CASE(\"Image analysis checkboxes enable and enforce rename-only behavior\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    create_visual_llm_files();\n\n    Settings settings;\n    settings.set_analyze_images_by_content(false);\n    settings.set_offer_rename_images(false);\n    settings.set_rename_images_only(false);\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n\n    QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window);\n    QCheckBox* process_only = MainAppTestAccess::process_images_only_checkbox(window);\n    QCheckBox* add_date_category = MainAppTestAccess::add_image_date_to_category_checkbox(window);\n    QCheckBox* add_date_place = MainAppTestAccess::add_image_date_place_to_filename_checkbox(window);\n    QCheckBox* add_media_metadata =\n        MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(window);\n    QCheckBox* offer = MainAppTestAccess::offer_rename_images_checkbox(window);\n    QCheckBox* rename_only = MainAppTestAccess::rename_images_only_checkbox(window);\n\n    REQUIRE(analyze != nullptr);\n    REQUIRE(process_only != nullptr);\n    REQUIRE(add_date_category != nullptr);\n    REQUIRE(add_date_place != nullptr);\n    REQUIRE(add_media_metadata != nullptr);\n    REQUIRE(offer != nullptr);\n    REQUIRE(rename_only != nullptr);\n\n    REQUIRE_FALSE(analyze->isChecked());\n    REQUIRE_FALSE(process_only->isEnabled());\n    REQUIRE_FALSE(add_date_category->isEnabled());\n    REQUIRE_FALSE(add_date_place->isEnabled());\n    REQUIRE(add_media_metadata->isEnabled());\n    REQUIRE(add_media_metadata->isChecked());\n    REQUIRE_FALSE(offer->isEnabled());\n    REQUIRE_FALSE(rename_only->isEnabled());\n\n    analyze->setChecked(true);\n    REQUIRE(process_only->isEnabled());\n    REQUIRE(add_date_category->isEnabled());\n    REQUIRE_FALSE(add_date_place->isEnabled());\n    REQUIRE(add_media_metadata->isEnabled());\n    REQUIRE(offer->isEnabled());\n    REQUIRE(rename_only->isEnabled());\n\n    add_date_category->setChecked(true);\n    REQUIRE(settings.get_add_image_date_to_category());\n\n    add_media_metadata->setChecked(false);\n    REQUIRE_FALSE(settings.get_add_audio_video_metadata_to_filename());\n\n    offer->setChecked(true);\n    REQUIRE(add_date_place->isEnabled());\n    add_date_place->setChecked(true);\n    REQUIRE(settings.get_add_image_date_place_to_filename());\n\n    rename_only->setChecked(true);\n    REQUIRE(offer->isChecked());\n    REQUIRE_FALSE(add_date_category->isEnabled());\n\n    offer->setChecked(false);\n    REQUIRE_FALSE(add_date_place->isEnabled());\n    REQUIRE(add_date_place->isChecked());\n    REQUIRE_FALSE(rename_only->isChecked());\n    REQUIRE(add_date_category->isEnabled());\n    REQUIRE(add_date_category->isChecked());\n}\n\nTEST_CASE(\"Top-level analysis rows share the same leading edge\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n    window.show();\n    QApplication::processEvents();\n\n    QCheckBox* analyze_documents = MainAppTestAccess::analyze_documents_checkbox(window);\n    QCheckBox* analyze_images = MainAppTestAccess::analyze_images_checkbox(window);\n    QCheckBox* add_media_metadata =\n        MainAppTestAccess::add_audio_video_metadata_to_filename_checkbox(window);\n\n    REQUIRE(analyze_documents != nullptr);\n    REQUIRE(analyze_images != nullptr);\n    REQUIRE(add_media_metadata != nullptr);\n\n    CHECK(add_media_metadata->x() == analyze_documents->x());\n    CHECK(add_media_metadata->x() == analyze_images->x());\n}\n\nTEST_CASE(\"Analysis toggles use disclosure indicators instead of toolbutton arrows\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n\n    QToolButton* image_toggle = MainAppTestAccess::image_options_toggle_button(window);\n    QToolButton* document_toggle = MainAppTestAccess::document_options_toggle_button(window);\n\n    REQUIRE(image_toggle != nullptr);\n    REQUIRE(document_toggle != nullptr);\n\n    CHECK(image_toggle->arrowType() == Qt::NoArrow);\n    CHECK(document_toggle->arrowType() == Qt::NoArrow);\n    CHECK(image_toggle->isCheckable());\n    CHECK(document_toggle->isCheckable());\n}\n\nTEST_CASE(\"Image rename-only does not disable categorization unless processing images only\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    create_visual_llm_files();\n\n    Settings settings;\n    settings.set_analyze_images_by_content(false);\n    settings.set_offer_rename_images(false);\n    settings.set_rename_images_only(false);\n    settings.set_process_images_only(false);\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n\n    QCheckBox* categorize_files = MainAppTestAccess::categorize_files_checkbox(window);\n    QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window);\n    QCheckBox* process_only = MainAppTestAccess::process_images_only_checkbox(window);\n    QCheckBox* rename_only = MainAppTestAccess::rename_images_only_checkbox(window);\n\n    REQUIRE(categorize_files != nullptr);\n    REQUIRE(analyze != nullptr);\n    REQUIRE(process_only != nullptr);\n    REQUIRE(rename_only != nullptr);\n\n    analyze->setChecked(true);\n    rename_only->setChecked(true);\n    CHECK(categorize_files->isEnabled());\n\n    process_only->setChecked(true);\n    CHECK_FALSE(categorize_files->isEnabled());\n}\n\nTEST_CASE(\"Document rename-only does not disable categorization unless processing documents only\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    settings.set_analyze_documents_by_content(false);\n    settings.set_offer_rename_documents(false);\n    settings.set_rename_documents_only(false);\n    settings.set_process_documents_only(false);\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n\n    QCheckBox* categorize_files = MainAppTestAccess::categorize_files_checkbox(window);\n    QCheckBox* analyze = MainAppTestAccess::analyze_documents_checkbox(window);\n    QCheckBox* process_only = MainAppTestAccess::process_documents_only_checkbox(window);\n    QCheckBox* rename_only = MainAppTestAccess::rename_documents_only_checkbox(window);\n\n    REQUIRE(categorize_files != nullptr);\n    REQUIRE(analyze != nullptr);\n    REQUIRE(process_only != nullptr);\n    REQUIRE(rename_only != nullptr);\n\n    analyze->setChecked(true);\n    rename_only->setChecked(true);\n    CHECK(categorize_files->isEnabled());\n\n    process_only->setChecked(true);\n    CHECK_FALSE(categorize_files->isEnabled());\n}\n\nTEST_CASE(\"Document analysis ignores other files when categorize files is off\") {\n    std::vector<FileEntry> files = {\n        {\"/tmp/photo.jpg\", \"photo.jpg\", FileType::File},\n        {\"/tmp/report.pdf\", \"report.pdf\", FileType::File},\n        {\"/tmp/archive.bin\", \"archive.bin\", FileType::File},\n        {\"/tmp/folder\", \"folder\", FileType::Directory}\n    };\n    std::unordered_set<std::string> renamed_files;\n\n    auto contains = [](const std::vector<FileEntry>& entries, const std::string& name) {\n        return std::any_of(entries.begin(),\n                           entries.end(),\n                           [&name](const FileEntry& entry) { return entry.file_name == name; });\n    };\n\n    std::vector<FileEntry> image_entries;\n    std::vector<FileEntry> document_entries;\n    std::vector<FileEntry> other_entries;\n\n    MainAppTestAccess::split_entries_for_analysis(files,\n                                                  false,\n                                                  true,\n                                                  false,\n                                                  false,\n                                                  false,\n                                                  false,\n                                                  false,\n                                                  false,\n                                                  renamed_files,\n                                                  image_entries,\n                                                  document_entries,\n                                                  other_entries);\n\n    CHECK(image_entries.empty());\n    CHECK(contains(document_entries, \"report.pdf\"));\n    CHECK_FALSE(contains(other_entries, \"photo.jpg\"));\n    CHECK_FALSE(contains(other_entries, \"archive.bin\"));\n    CHECK(contains(other_entries, \"folder\"));\n}\n\nTEST_CASE(\"Image analysis toggle disables when dialog closes without downloads\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    Settings settings;\n    settings.set_analyze_images_by_content(false);\n    settings.set_offer_rename_images(false);\n    settings.set_rename_images_only(false);\n    REQUIRE(settings.save());\n\n    MainApp window(settings, /*development_mode=*/false);\n    MainAppTestAccess::set_visual_llm_available_probe(window, []() { return false; });\n    MainAppTestAccess::set_llm_selection_runner(window, []() {});\n    MainAppTestAccess::set_image_analysis_prompt_override(window, []() { return true; });\n\n    QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window);\n    REQUIRE(analyze != nullptr);\n\n    analyze->setChecked(true);\n    REQUIRE_FALSE(analyze->isChecked());\n    REQUIRE_FALSE(settings.get_analyze_images_by_content());\n}\n\nTEST_CASE(\"Image analysis toggle cancels when user declines download\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", std::string(\"offscreen\"));\n    QtAppContext qt_context;\n\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    Settings settings;\n    settings.set_analyze_images_by_content(false);\n    settings.set_offer_rename_images(false);\n    settings.set_rename_images_only(false);\n    REQUIRE(settings.save());\n\n    bool dialog_opened = false;\n    MainApp window(settings, /*development_mode=*/false);\n    MainAppTestAccess::set_visual_llm_available_probe(window, []() { return false; });\n    MainAppTestAccess::set_llm_selection_runner(window, [&dialog_opened]() { dialog_opened = true; });\n    MainAppTestAccess::set_image_analysis_prompt_override(window, []() { return false; });\n\n    QCheckBox* analyze = MainAppTestAccess::analyze_images_checkbox(window);\n    REQUIRE(analyze != nullptr);\n\n    analyze->setChecked(true);\n    REQUIRE_FALSE(analyze->isChecked());\n    REQUIRE_FALSE(settings.get_analyze_images_by_content());\n    REQUIRE_FALSE(dialog_opened);\n}\n\nTEST_CASE(\"Already-renamed images skip vision analysis\") {\n    std::vector<FileEntry> files = {\n        {\"/tmp/renamed.png\", \"renamed.png\", FileType::File},\n        {\"/tmp/other.png\", \"other.png\", FileType::File},\n        {\"/tmp/doc.txt\", \"doc.txt\", FileType::File},\n        {\"/tmp/folder\", \"folder\", FileType::Directory}\n    };\n    std::unordered_set<std::string> renamed_files = {\"renamed.png\"};\n\n    auto contains = [](const std::vector<FileEntry>& entries, const std::string& name) {\n        return std::any_of(entries.begin(),\n                           entries.end(),\n                           [&name](const FileEntry& entry) { return entry.file_name == name; });\n    };\n\n    std::vector<FileEntry> image_entries;\n    std::vector<FileEntry> document_entries;\n    std::vector<FileEntry> other_entries;\n\n    SECTION(\"categorization uses filename when already renamed\") {\n        MainAppTestAccess::split_entries_for_analysis(files,\n                                                      true,\n                                                      false,\n                                                      false,\n                                                      false,\n                                                      false,\n                                                      false,\n                                                      true,\n                                                      false,\n                                                      renamed_files,\n                                                      image_entries,\n                                                      document_entries,\n                                                      other_entries);\n\n        CHECK_FALSE(contains(image_entries, \"renamed.png\"));\n        CHECK_FALSE(contains(document_entries, \"renamed.png\"));\n        CHECK(contains(other_entries, \"renamed.png\"));\n        CHECK(contains(image_entries, \"other.png\"));\n        CHECK_FALSE(contains(document_entries, \"other.png\"));\n        CHECK(contains(other_entries, \"doc.txt\"));\n        CHECK(contains(other_entries, \"folder\"));\n    }\n\n    SECTION(\"rename-only skips already-renamed images entirely\") {\n        MainAppTestAccess::split_entries_for_analysis(files,\n                                                      true,\n                                                      false,\n                                                      false,\n                                                      false,\n                                                      true,\n                                                      false,\n                                                      true,\n                                                      false,\n                                                      renamed_files,\n                                                      image_entries,\n                                                      document_entries,\n                                                      other_entries);\n\n        CHECK_FALSE(contains(image_entries, \"renamed.png\"));\n        CHECK_FALSE(contains(document_entries, \"renamed.png\"));\n        CHECK_FALSE(contains(other_entries, \"renamed.png\"));\n        CHECK(contains(image_entries, \"other.png\"));\n        CHECK_FALSE(contains(document_entries, \"other.png\"));\n    }\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_main_app_translation.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"MainApp.hpp\"\n#include \"MainAppTestAccess.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"TranslationManager.hpp\"\n#include \"Language.hpp\"\n\n#include <QCoreApplication>\n\n#include <vector>\n\n#ifndef _WIN32\nTEST_CASE(\"MainApp retranslate reflects language changes\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    Settings settings;\n    settings.load();\n\n    MainApp window(settings, /*development_mode=*/false);\n    struct ExpectedTranslation {\n        Language language;\n        QString analyze_label;\n        QString folder_label;\n    };\n\n    const std::vector<ExpectedTranslation> expected = {\n        {Language::English, QStringLiteral(\"Analyze folder\"), QStringLiteral(\"Folder:\")},\n        {Language::French, QStringLiteral(\"Analyser le dossier\"), QStringLiteral(\"Dossier :\")},\n        {Language::German, QStringLiteral(\"Ordner analysieren\"), QStringLiteral(\"Ordner:\")},\n        {Language::Italian, QStringLiteral(\"Analizza cartella\"), QStringLiteral(\"Cartella:\")},\n        {Language::Spanish, QStringLiteral(\"Analizar carpeta\"), QStringLiteral(\"Carpeta:\")},\n        {Language::Dutch, QStringLiteral(\"Map analyseren\"), QStringLiteral(\"Map:\")},\n        {Language::Turkish, QStringLiteral(\"Klasörü analiz et\"), QStringLiteral(\"Klasör:\")},\n        {Language::Korean, QStringLiteral(\"폴더 분석\"), QStringLiteral(\"폴더:\")}\n    };\n\n    for (const auto& entry : expected) {\n        settings.set_language(entry.language);\n        TranslationManager::instance().set_language(entry.language);\n        MainAppTestAccess::trigger_retranslate(window);\n\n        const auto analyze_text = MainAppTestAccess::analyze_button_text(window);\n        const auto folder_text = MainAppTestAccess::path_label_text(window);\n        CAPTURE(static_cast<int>(entry.language), analyze_text, folder_text);\n\n        REQUIRE(analyze_text == entry.analyze_label);\n        REQUIRE(folder_text == entry.folder_label);\n    }\n}\n\nTEST_CASE(\"Updater strings are translated for all supported UI languages\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    struct ExpectedTranslation {\n        Language language;\n        QString update_failed;\n        QString update_manually;\n        QString prepare_failed;\n        QString installer_launch_failed;\n        QString no_download_target;\n        QString downloading_update;\n        QString downloading_installer;\n        QString installer_ready;\n        QString quit_and_launch_message;\n        QString quit_and_launch_button;\n    };\n\n    const std::vector<ExpectedTranslation> expected = {\n        {Language::English,\n         QStringLiteral(\"Update Failed\"),\n         QStringLiteral(\"Update manually\"),\n         QStringLiteral(\"Failed to prepare the update installer.\\n%1\"),\n         QStringLiteral(\"The installer could not be launched.\"),\n         QStringLiteral(\"No download target is available for this update.\"),\n         QStringLiteral(\"Downloading Update\"),\n         QStringLiteral(\"Downloading the update installer...\"),\n         QStringLiteral(\"Installer Ready\"),\n         QStringLiteral(\"Quit the app and launch the installer to update\"),\n         QStringLiteral(\"Quit and Launch Installer\")},\n        {Language::French,\n         QStringLiteral(\"Échec de la mise à jour\"),\n         QStringLiteral(\"Mettre à jour manuellement\"),\n         QStringLiteral(\"Échec de la préparation du programme d'installation de la mise à jour.\\n%1\"),\n         QStringLiteral(\"Le programme d'installation n'a pas pu être lancé.\"),\n         QStringLiteral(\"Aucune cible de téléchargement n'est disponible pour cette mise à jour.\"),\n         QStringLiteral(\"Téléchargement de la mise à jour\"),\n         QStringLiteral(\"Téléchargement du programme d'installation de la mise à jour...\"),\n         QStringLiteral(\"Programme d'installation prêt\"),\n         QStringLiteral(\"Quittez l'application et lancez le programme d'installation pour effectuer la mise à jour\"),\n         QStringLiteral(\"Quitter et lancer le programme d'installation\")},\n        {Language::German,\n         QStringLiteral(\"Update fehlgeschlagen\"),\n         QStringLiteral(\"Manuell aktualisieren\"),\n         QStringLiteral(\"Das Update-Installationsprogramm konnte nicht vorbereitet werden.\\n%1\"),\n         QStringLiteral(\"Das Installationsprogramm konnte nicht gestartet werden.\"),\n         QStringLiteral(\"Für dieses Update ist kein Download-Ziel verfügbar.\"),\n         QStringLiteral(\"Update wird heruntergeladen\"),\n         QStringLiteral(\"Das Update-Installationsprogramm wird heruntergeladen...\"),\n         QStringLiteral(\"Installationsprogramm bereit\"),\n         QStringLiteral(\"Beenden Sie die App und starten Sie das Installationsprogramm, um zu aktualisieren\"),\n         QStringLiteral(\"Beenden und Installationsprogramm starten\")},\n        {Language::Italian,\n         QStringLiteral(\"Aggiornamento non riuscito\"),\n         QStringLiteral(\"Aggiorna manualmente\"),\n         QStringLiteral(\"Impossibile preparare il programma di installazione dell'aggiornamento.\\n%1\"),\n         QStringLiteral(\"Impossibile avviare il programma di installazione.\"),\n         QStringLiteral(\"Nessuna destinazione di download disponibile per questo aggiornamento.\"),\n         QStringLiteral(\"Download aggiornamento\"),\n         QStringLiteral(\"Download del programma di installazione dell'aggiornamento...\"),\n         QStringLiteral(\"Programma di installazione pronto\"),\n         QStringLiteral(\"Chiudi l'app e avvia il programma di installazione per aggiornare\"),\n         QStringLiteral(\"Chiudi e avvia il programma di installazione\")},\n        {Language::Spanish,\n         QStringLiteral(\"La actualización falló\"),\n         QStringLiteral(\"Actualizar manualmente\"),\n         QStringLiteral(\"No se pudo preparar el instalador de la actualización.\\n%1\"),\n         QStringLiteral(\"No se pudo ejecutar el instalador.\"),\n         QStringLiteral(\"No hay un destino de descarga disponible para esta actualización.\"),\n         QStringLiteral(\"Descargando actualización\"),\n         QStringLiteral(\"Descargando el instalador de la actualización...\"),\n         QStringLiteral(\"Instalador listo\"),\n         QStringLiteral(\"Cierra la aplicación y ejecuta el instalador para actualizar\"),\n         QStringLiteral(\"Cerrar y ejecutar instalador\")},\n        {Language::Dutch,\n         QStringLiteral(\"Bijwerken mislukt\"),\n         QStringLiteral(\"Handmatig bijwerken\"),\n         QStringLiteral(\"Het installatieprogramma van de update kon niet worden voorbereid.\\n%1\"),\n         QStringLiteral(\"Het installatieprogramma kon niet worden gestart.\"),\n         QStringLiteral(\"Er is geen downloaddoel beschikbaar voor deze update.\"),\n         QStringLiteral(\"Update downloaden\"),\n         QStringLiteral(\"Het installatieprogramma van de update wordt gedownload...\"),\n         QStringLiteral(\"Installatieprogramma gereed\"),\n         QStringLiteral(\"Sluit de app af en start het installatieprogramma om bij te werken\"),\n         QStringLiteral(\"Afsluiten en installatieprogramma starten\")},\n        {Language::Turkish,\n         QStringLiteral(\"Güncelleme başarısız oldu\"),\n         QStringLiteral(\"Elle güncelle\"),\n         QStringLiteral(\"Güncelleme yükleyicisi hazırlanamadı.\\n%1\"),\n         QStringLiteral(\"Yükleyici başlatılamadı.\"),\n         QStringLiteral(\"Bu güncelleme için kullanılabilir bir indirme hedefi yok.\"),\n         QStringLiteral(\"Güncelleme indiriliyor\"),\n         QStringLiteral(\"Güncelleme yükleyicisi indiriliyor...\"),\n         QStringLiteral(\"Yükleyici hazır\"),\n         QStringLiteral(\"Güncellemek için uygulamadan çıkın ve yükleyiciyi başlatın\"),\n         QStringLiteral(\"Çık ve yükleyiciyi başlat\")},\n        {Language::Korean,\n         QStringLiteral(\"업데이트 실패\"),\n         QStringLiteral(\"수동으로 업데이트\"),\n         QStringLiteral(\"업데이트 설치 프로그램을 준비하지 못했습니다.\\n%1\"),\n         QStringLiteral(\"설치 프로그램을 실행할 수 없습니다.\"),\n         QStringLiteral(\"이 업데이트에 사용할 다운로드 대상이 없습니다.\"),\n         QStringLiteral(\"업데이트 다운로드 중\"),\n         QStringLiteral(\"업데이트 설치 프로그램을 다운로드하는 중...\"),\n         QStringLiteral(\"설치 프로그램 준비 완료\"),\n         QStringLiteral(\"업데이트하려면 앱을 종료하고 설치 프로그램을 실행하세요\"),\n         QStringLiteral(\"종료 후 설치 프로그램 실행\")}\n    };\n\n    for (const auto& entry : expected) {\n        TranslationManager::instance().set_language(entry.language);\n\n        const auto update_failed = QCoreApplication::translate(\"QObject\", \"Update Failed\");\n        const auto update_manually = QCoreApplication::translate(\"QObject\", \"Update manually\");\n        const auto prepare_failed = QCoreApplication::translate(\"QObject\", \"Failed to prepare the update installer.\\n%1\");\n        const auto installer_launch_failed = QCoreApplication::translate(\"QObject\", \"The installer could not be launched.\");\n        const auto no_download_target = QCoreApplication::translate(\"QObject\", \"No download target is available for this update.\");\n        const auto downloading_update = QCoreApplication::translate(\"QObject\", \"Downloading Update\");\n        const auto downloading_installer = QCoreApplication::translate(\"QObject\", \"Downloading the update installer...\");\n        const auto installer_ready = QCoreApplication::translate(\"QObject\", \"Installer Ready\");\n        const auto quit_and_launch_message = QCoreApplication::translate(\"QObject\", \"Quit the app and launch the installer to update\");\n        const auto quit_and_launch_button = QCoreApplication::translate(\"QObject\", \"Quit and Launch Installer\");\n\n        CAPTURE(static_cast<int>(entry.language),\n                update_failed,\n                update_manually,\n                prepare_failed,\n                installer_launch_failed,\n                no_download_target,\n                downloading_update,\n                downloading_installer,\n                installer_ready,\n                quit_and_launch_message,\n                quit_and_launch_button);\n\n        REQUIRE(update_failed == entry.update_failed);\n        REQUIRE(update_manually == entry.update_manually);\n        REQUIRE(prepare_failed == entry.prepare_failed);\n        REQUIRE(installer_launch_failed == entry.installer_launch_failed);\n        REQUIRE(no_download_target == entry.no_download_target);\n        REQUIRE(downloading_update == entry.downloading_update);\n        REQUIRE(downloading_installer == entry.downloading_installer);\n        REQUIRE(installer_ready == entry.installer_ready);\n        REQUIRE(quit_and_launch_message == entry.quit_and_launch_message);\n        REQUIRE(quit_and_launch_button == entry.quit_and_launch_button);\n    }\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_main_app_visual_fallback.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"MainAppTestAccess.hpp\"\n\n#include <string>\n\nTEST_CASE(\"Visual CPU fallback detection recognizes retryable GPU failures\") {\n    CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback(\n        \"Failed to create llama_context (try AI_FILE_SORTER_VISUAL_USE_GPU=0 to force CPU)\"));\n    CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback(\"mtmd_helper_eval_chunks failed\"));\n    CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback(\"VK_ERROR_OUT_OF_DEVICE_MEMORY\"));\n    CHECK(MainAppTestAccess::should_offer_visual_cpu_fallback(\"CUDA error out of memory\"));\n}\n\nTEST_CASE(\"Visual CPU fallback detection ignores non-retryable startup failures\") {\n    CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback(\n        \"Failed to load mmproj file at C:/models/mmproj.gguf\"));\n    CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback(\n        \"Failed to load LLaVA text model at C:/models/model.gguf\"));\n    CHECK_FALSE(MainAppTestAccess::should_offer_visual_cpu_fallback(\n        \"The provided mmproj file does not expose vision capabilities\"));\n}\n"
  },
  {
    "path": "tests/unit/test_media_rename_metadata_service.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"MediaRenameMetadataService.hpp\"\n\n#include <algorithm>\n#include <array>\n#include <chrono>\n#include <cstdint>\n#include <filesystem>\n#include <fstream>\n#include <string>\n#include <vector>\n\nTEST_CASE(\"MediaRenameMetadataService composes year-artist-album-title filenames\") {\n    MediaRenameMetadataService::MetadataFields metadata;\n    metadata.year = \"2014\";\n    metadata.artist = \"Massive Attack\";\n    metadata.album = \"Mezzanine\";\n    metadata.title = \"Teardrop\";\n\n    const std::filesystem::path input{\"/tmp/track01.mp3\"};\n    const std::string output = MediaRenameMetadataService::compose_filename(input, metadata);\n\n    REQUIRE(output == \"2014_massive_attack_mezzanine_teardrop.mp3\");\n}\n\nTEST_CASE(\"MediaRenameMetadataService falls back to source stem when title is missing\") {\n    MediaRenameMetadataService::MetadataFields metadata;\n    metadata.year = \"1997\";\n    metadata.artist = \"Daft Punk\";\n\n    const std::filesystem::path input{\"/tmp/Around The World.flac\"};\n    const std::string output = MediaRenameMetadataService::compose_filename(input, metadata);\n\n    REQUIRE(output == \"1997_daft_punk_around_the_world.flac\");\n}\n\nTEST_CASE(\"MediaRenameMetadataService keeps original filename when metadata is absent\") {\n    const MediaRenameMetadataService::MetadataFields metadata{};\n    const std::filesystem::path input{\"/tmp/video_clip.mp4\"};\n\n    const std::string output = MediaRenameMetadataService::compose_filename(input, metadata);\n\n    REQUIRE(output == \"video_clip.mp4\");\n}\n\n#ifndef AI_FILE_SORTER_USE_MEDIAINFOLIB\nnamespace {\n\nclass TempMediaFile {\npublic:\n    explicit TempMediaFile(const std::string& file_name)\n    {\n        const auto now = std::chrono::steady_clock::now().time_since_epoch().count();\n        path_ = std::filesystem::temp_directory_path() /\n                (\"aifs_media_meta_\" + std::to_string(now) + \"_\" + file_name);\n    }\n\n    ~TempMediaFile()\n    {\n        std::error_code ec;\n        std::filesystem::remove(path_, ec);\n    }\n\n    const std::filesystem::path& path() const\n    {\n        return path_;\n    }\n\nprivate:\n    std::filesystem::path path_;\n};\n\nvoid write_binary_file(const std::filesystem::path& path, const std::vector<std::uint8_t>& bytes)\n{\n    std::ofstream output(path, std::ios::binary | std::ios::trunc);\n    REQUIRE(output.is_open());\n    output.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));\n    REQUIRE(output.good());\n}\n\nvoid append_le_u32(std::vector<std::uint8_t>& output, std::uint32_t value)\n{\n    output.push_back(static_cast<std::uint8_t>(value & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>((value >> 8) & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>((value >> 16) & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>((value >> 24) & 0xFFU));\n}\n\nvoid append_be_u32(std::vector<std::uint8_t>& output, std::uint32_t value)\n{\n    output.push_back(static_cast<std::uint8_t>((value >> 24) & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>((value >> 16) & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>((value >> 8) & 0xFFU));\n    output.push_back(static_cast<std::uint8_t>(value & 0xFFU));\n}\n\nvoid append_le_u64(std::vector<std::uint8_t>& output, std::uint64_t value)\n{\n    for (int index = 0; index < 8; ++index) {\n        output.push_back(static_cast<std::uint8_t>((value >> (index * 8)) & 0xFFU));\n    }\n}\n\nstd::vector<std::uint8_t> make_mp4_atom(const std::array<std::uint8_t, 4>& type,\n                                        const std::vector<std::uint8_t>& payload)\n{\n    std::vector<std::uint8_t> atom;\n    append_be_u32(atom, static_cast<std::uint32_t>(8 + payload.size()));\n    atom.insert(atom.end(), type.begin(), type.end());\n    atom.insert(atom.end(), payload.begin(), payload.end());\n    return atom;\n}\n\nstd::vector<std::uint8_t> make_mp4_data_atom(const std::string& value)\n{\n    std::vector<std::uint8_t> payload;\n    append_be_u32(payload, 1); // UTF-8 data type\n    append_be_u32(payload, 0); // locale\n    payload.insert(payload.end(), value.begin(), value.end());\n    return make_mp4_atom({'d', 'a', 't', 'a'}, payload);\n}\n\nstd::vector<std::uint8_t> make_mp4_metadata_atom(const std::array<std::uint8_t, 4>& key,\n                                                 const std::string& value)\n{\n    return make_mp4_atom(key, make_mp4_data_atom(value));\n}\n\nvoid write_fixed_id3v1_field(std::array<char, 128>& tag,\n                             std::size_t offset,\n                             std::size_t length,\n                             const std::string& value)\n{\n    const std::size_t copy_length = std::min(length, value.size());\n    std::copy_n(value.begin(), copy_length, tag.begin() + static_cast<std::ptrdiff_t>(offset));\n}\n\nstd::vector<std::uint8_t> make_mp3_with_id3v1()\n{\n    std::vector<std::uint8_t> bytes(64, 0);\n    std::array<char, 128> tag{};\n    tag[0] = 'T';\n    tag[1] = 'A';\n    tag[2] = 'G';\n    write_fixed_id3v1_field(tag, 3, 30, \"Celestial Echoes\");\n    write_fixed_id3v1_field(tag, 33, 30, \"Synth Unit\");\n    write_fixed_id3v1_field(tag, 63, 30, \"Moon Tides\");\n    write_fixed_id3v1_field(tag, 93, 4, \"2024\");\n    bytes.insert(bytes.end(), tag.begin(), tag.end());\n    return bytes;\n}\n\nstd::vector<std::uint8_t> make_vorbis_comment_payload(const std::vector<std::string>& comments)\n{\n    std::vector<std::uint8_t> payload;\n    const std::string vendor = \"AIFileSorterTests\";\n    append_le_u32(payload, static_cast<std::uint32_t>(vendor.size()));\n    payload.insert(payload.end(), vendor.begin(), vendor.end());\n    append_le_u32(payload, static_cast<std::uint32_t>(comments.size()));\n    for (const auto& comment : comments) {\n        append_le_u32(payload, static_cast<std::uint32_t>(comment.size()));\n        payload.insert(payload.end(), comment.begin(), comment.end());\n    }\n    return payload;\n}\n\nstd::vector<std::uint8_t> make_flac_with_vorbis_comments()\n{\n    const std::vector<std::uint8_t> comments = make_vorbis_comment_payload({\n        \"TITLE=Celestial Echoes Continued\",\n        \"ARTIST=Synth Unit\",\n        \"ALBUM=Moon Tides\",\n        \"DATE=2023-04-09\"\n    });\n\n    std::vector<std::uint8_t> bytes;\n    bytes.insert(bytes.end(), {'f', 'L', 'a', 'C'});\n    bytes.push_back(0x84); // last metadata block + vorbis comment block type\n    bytes.push_back(static_cast<std::uint8_t>((comments.size() >> 16) & 0xFFU));\n    bytes.push_back(static_cast<std::uint8_t>((comments.size() >> 8) & 0xFFU));\n    bytes.push_back(static_cast<std::uint8_t>(comments.size() & 0xFFU));\n    bytes.insert(bytes.end(), comments.begin(), comments.end());\n    return bytes;\n}\n\nstd::vector<std::uint8_t> make_opus_with_tags()\n{\n    std::vector<std::uint8_t> opus_head = {\n        'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',\n        1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    };\n\n    std::vector<std::uint8_t> opus_tags = {'O', 'p', 'u', 's', 'T', 'a', 'g', 's'};\n    const std::vector<std::uint8_t> comments = make_vorbis_comment_payload({\n        \"TITLE=Celestial Echoes 2\",\n        \"ARTIST=Synth Unit\",\n        \"ALBUM=Celestial Sets\",\n        \"YEAR=2022\"\n    });\n    opus_tags.insert(opus_tags.end(), comments.begin(), comments.end());\n\n    REQUIRE(opus_head.size() < 255);\n    REQUIRE(opus_tags.size() < 255);\n\n    std::vector<std::uint8_t> bytes;\n    bytes.insert(bytes.end(), {'O', 'g', 'g', 'S'});\n    bytes.push_back(0);     // version\n    bytes.push_back(0x02);  // BOS page\n    append_le_u64(bytes, 0);\n    append_le_u32(bytes, 1); // serial number\n    append_le_u32(bytes, 0); // sequence number\n    append_le_u32(bytes, 0); // checksum (not validated by parser)\n    bytes.push_back(2);      // segment count\n    bytes.push_back(static_cast<std::uint8_t>(opus_head.size()));\n    bytes.push_back(static_cast<std::uint8_t>(opus_tags.size()));\n    bytes.insert(bytes.end(), opus_head.begin(), opus_head.end());\n    bytes.insert(bytes.end(), opus_tags.begin(), opus_tags.end());\n    return bytes;\n}\n\nstd::vector<std::uint8_t> make_mp4_with_ilst_tags()\n{\n    std::vector<std::uint8_t> ilst_payload;\n    const std::uint8_t copyright = 0xA9;\n    const std::array<std::uint8_t, 4> title_tag = {copyright, 'n', 'a', 'm'};\n    const std::array<std::uint8_t, 4> artist_tag = {copyright, 'A', 'R', 'T'};\n    const std::array<std::uint8_t, 4> album_tag = {copyright, 'a', 'l', 'b'};\n    const std::array<std::uint8_t, 4> date_tag = {copyright, 'd', 'a', 'y'};\n\n    const auto title_atom = make_mp4_metadata_atom(title_tag, \"Celestial Echoes Video\");\n    ilst_payload.insert(ilst_payload.end(), title_atom.begin(), title_atom.end());\n    const auto artist_atom = make_mp4_metadata_atom(artist_tag, \"Synth Unit\");\n    ilst_payload.insert(ilst_payload.end(), artist_atom.begin(), artist_atom.end());\n    const auto album_atom = make_mp4_metadata_atom(album_tag, \"Moon Tides Live\");\n    ilst_payload.insert(ilst_payload.end(), album_atom.begin(), album_atom.end());\n    const auto date_atom = make_mp4_metadata_atom(date_tag, \"2021-06-30\");\n    ilst_payload.insert(ilst_payload.end(), date_atom.begin(), date_atom.end());\n\n    const auto ilst_atom = make_mp4_atom({'i', 'l', 's', 't'}, ilst_payload);\n\n    std::vector<std::uint8_t> meta_payload(4, 0); // version + flags\n    meta_payload.insert(meta_payload.end(), ilst_atom.begin(), ilst_atom.end());\n    const auto meta_atom = make_mp4_atom({'m', 'e', 't', 'a'}, meta_payload);\n    const auto udta_atom = make_mp4_atom({'u', 'd', 't', 'a'}, meta_atom);\n    const auto moov_atom = make_mp4_atom({'m', 'o', 'o', 'v'}, udta_atom);\n\n    std::vector<std::uint8_t> ftyp_payload = {\n        'i', 's', 'o', 'm', 0, 0, 0, 1, 'i', 's', 'o', 'm', 'm', 'p', '4', '1'\n    };\n    const auto ftyp_atom = make_mp4_atom({'f', 't', 'y', 'p'}, ftyp_payload);\n\n    std::vector<std::uint8_t> file;\n    file.insert(file.end(), ftyp_atom.begin(), ftyp_atom.end());\n    file.insert(file.end(), moov_atom.begin(), moov_atom.end());\n    return file;\n}\n\n} // namespace\n\nTEST_CASE(\"MediaRenameMetadataService extracts MP3 ID3v1 metadata when MediaInfo is unavailable\")\n{\n    TempMediaFile file(\"raw_track.mp3\");\n    write_binary_file(file.path(), make_mp3_with_id3v1());\n\n    MediaRenameMetadataService service;\n    const auto suggestion = service.suggest_name(file.path());\n\n    REQUIRE(suggestion.has_value());\n    REQUIRE(*suggestion == \"2024_synth_unit_moon_tides_celestial_echoes.mp3\");\n}\n\nTEST_CASE(\"MediaRenameMetadataService extracts FLAC Vorbis comments when MediaInfo is unavailable\")\n{\n    TempMediaFile file(\"raw_track.flac\");\n    write_binary_file(file.path(), make_flac_with_vorbis_comments());\n\n    MediaRenameMetadataService service;\n    const auto suggestion = service.suggest_name(file.path());\n\n    REQUIRE(suggestion.has_value());\n    REQUIRE(*suggestion == \"2023_synth_unit_moon_tides_celestial_echoes_continued.flac\");\n}\n\nTEST_CASE(\"MediaRenameMetadataService extracts OpusTags when MediaInfo is unavailable\")\n{\n    TempMediaFile file(\"raw_track.opus\");\n    write_binary_file(file.path(), make_opus_with_tags());\n\n    MediaRenameMetadataService service;\n    const auto suggestion = service.suggest_name(file.path());\n\n    REQUIRE(suggestion.has_value());\n    REQUIRE(*suggestion == \"2022_synth_unit_celestial_sets_celestial_echoes_2.opus\");\n}\n\nTEST_CASE(\"MediaRenameMetadataService extracts MP4 tags when MediaInfo is unavailable\")\n{\n    TempMediaFile file(\"video_clip.mp4\");\n    write_binary_file(file.path(), make_mp4_with_ilst_tags());\n\n    MediaRenameMetadataService service;\n    const auto suggestion = service.suggest_name(file.path());\n\n    REQUIRE(suggestion.has_value());\n    REQUIRE(*suggestion == \"2021_synth_unit_moon_tides_live_celestial_echoes_video.mp4\");\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_review_dialog_rename_gate.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"CategorizationDialog.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Types.hpp\"\n\n#include <QCheckBox>\n#include <QTimer>\n\n#ifndef _WIN32\nnamespace {\n\nQCheckBox* find_checkbox_by_text(QWidget& dialog, const QString& text) {\n    const auto boxes = dialog.findChildren<QCheckBox*>();\n    for (auto* box : boxes) {\n        if (box && box->text() == text) {\n            return box;\n        }\n    }\n    return nullptr;\n}\n\nstd::vector<CategorizedFile> make_sample_files(const std::string& base_dir) {\n    CategorizedFile image;\n    image.file_path = base_dir;\n    image.file_name = \"photo.png\";\n    image.type = FileType::File;\n    image.category = \"Photos\";\n    image.suggested_name = \"sunset.png\";\n\n    CategorizedFile document;\n    document.file_path = base_dir;\n    document.file_name = \"report.pdf\";\n    document.type = FileType::File;\n    document.category = \"Docs\";\n    document.suggested_name = \"report-2024.pdf\";\n\n    return {image, document};\n}\n\n} // namespace\n\nTEST_CASE(\"Review dialog rename-only toggles disabled when renames are not allowed\") {\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir base_dir;\n    const auto files = make_sample_files(base_dir.path().string());\n\n    TempDir undo_dir_disabled;\n    CategorizationDialog dialog_disabled(nullptr, true, undo_dir_disabled.path().string());\n    QTimer::singleShot(0, &dialog_disabled, &QDialog::accept);\n    dialog_disabled.show_results(files, std::string(), false, false, false);\n\n    QCheckBox* image_disabled = find_checkbox_by_text(\n        dialog_disabled,\n        QStringLiteral(\"Do not categorize picture files (only rename)\"));\n    QCheckBox* document_disabled = find_checkbox_by_text(\n        dialog_disabled,\n        QStringLiteral(\"Do not categorize document files (only rename)\"));\n\n    REQUIRE(image_disabled != nullptr);\n    REQUIRE(document_disabled != nullptr);\n    CHECK_FALSE(image_disabled->isEnabled());\n    CHECK_FALSE(document_disabled->isEnabled());\n\n    TempDir undo_dir_enabled;\n    CategorizationDialog dialog_enabled(nullptr, true, undo_dir_enabled.path().string());\n    QTimer::singleShot(0, &dialog_enabled, &QDialog::accept);\n    dialog_enabled.show_results(files, std::string(), false, true, true);\n\n    QCheckBox* image_enabled = find_checkbox_by_text(\n        dialog_enabled,\n        QStringLiteral(\"Do not categorize picture files (only rename)\"));\n    QCheckBox* document_enabled = find_checkbox_by_text(\n        dialog_enabled,\n        QStringLiteral(\"Do not categorize document files (only rename)\"));\n\n    REQUIRE(image_enabled != nullptr);\n    REQUIRE(document_enabled != nullptr);\n    CHECK(image_enabled->isEnabled());\n    CHECK(document_enabled->isEnabled());\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_settings_image_options.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Utils.hpp\"\n\n#include <filesystem>\n#include <fstream>\n\nnamespace {\n\nvoid create_visual_llm_files()\n{\n    const std::string model_url = \"https://example.com/llava-model.gguf\";\n    const std::string mmproj_url = \"https://example.com/mmproj-model-f16.gguf\";\n\n    const std::filesystem::path model_path =\n        Utils::make_default_path_to_file_from_download_url(model_url);\n    const std::filesystem::path mmproj_path =\n        Utils::make_default_path_to_file_from_download_url(mmproj_url);\n\n    std::filesystem::create_directories(model_path.parent_path());\n    std::ofstream(model_path.string(), std::ios::binary).put('x');\n    std::ofstream(mmproj_path.string(), std::ios::binary).put('x');\n}\n\n} // namespace\n\nTEST_CASE(\"Settings defaults image analysis off even when visual LLM files exist\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    create_visual_llm_files();\n\n    Settings settings;\n    const bool loaded = settings.load();\n    REQUIRE_FALSE(loaded);\n    REQUIRE_FALSE(settings.get_analyze_images_by_content());\n    REQUIRE_FALSE(settings.get_offer_rename_images());\n}\n\nTEST_CASE(\"Settings defaults image analysis off when visual LLM files are missing\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    Settings settings;\n    const bool loaded = settings.load();\n    REQUIRE_FALSE(loaded);\n    REQUIRE_FALSE(settings.get_analyze_images_by_content());\n    REQUIRE_FALSE(settings.get_offer_rename_images());\n}\n\nTEST_CASE(\"Settings enforces rename-only implies offer rename\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n    EnvVarGuard model_guard(\"LLAVA_MODEL_URL\", std::string(\"https://example.com/llava-model.gguf\"));\n    EnvVarGuard mmproj_guard(\"LLAVA_MMPROJ_URL\", std::string(\"https://example.com/mmproj-model-f16.gguf\"));\n\n    Settings settings;\n    settings.set_analyze_images_by_content(true);\n    settings.set_offer_rename_images(false);\n    settings.set_rename_images_only(true);\n    settings.set_process_images_only(true);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    REQUIRE(reloaded.load());\n    REQUIRE(reloaded.get_offer_rename_images());\n    REQUIRE(reloaded.get_rename_images_only());\n    REQUIRE(reloaded.get_process_images_only());\n}\n\nTEST_CASE(\"Settings persists options group expansion state\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    settings.set_image_options_expanded(true);\n    settings.set_document_options_expanded(false);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    REQUIRE(reloaded.load());\n    REQUIRE(reloaded.get_image_options_expanded());\n    REQUIRE_FALSE(reloaded.get_document_options_expanded());\n}\n\nTEST_CASE(\"Settings persists image EXIF date/place rename toggle\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    settings.set_offer_rename_images(true);\n    settings.set_add_image_date_place_to_filename(true);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    REQUIRE(reloaded.load());\n    REQUIRE(reloaded.get_offer_rename_images());\n    REQUIRE(reloaded.get_add_image_date_place_to_filename());\n}\n\nTEST_CASE(\"Settings defaults audio/video metadata rename toggle to enabled\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    const bool loaded = settings.load();\n    REQUIRE_FALSE(loaded);\n    REQUIRE(settings.get_add_audio_video_metadata_to_filename());\n}\n\nTEST_CASE(\"Settings persists audio/video metadata rename toggle\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    settings.set_add_audio_video_metadata_to_filename(false);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    REQUIRE(reloaded.load());\n    REQUIRE_FALSE(reloaded.get_add_audio_video_metadata_to_filename());\n}\n\nTEST_CASE(\"Settings persists image date-to-category toggle\") {\n    TempDir temp;\n    EnvVarGuard home_guard(\"HOME\", temp.path().string());\n#ifdef _WIN32\n    EnvVarGuard appdata_guard(\"APPDATA\", temp.path().string());\n#endif\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", temp.path().string());\n\n    Settings settings;\n    settings.set_analyze_images_by_content(true);\n    settings.set_add_image_date_to_category(true);\n    REQUIRE(settings.save());\n\n    Settings reloaded;\n    REQUIRE(reloaded.load());\n    REQUIRE(reloaded.get_analyze_images_by_content());\n    REQUIRE(reloaded.get_add_image_date_to_category());\n}\n"
  },
  {
    "path": "tests/unit/test_support_prompt.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"MainApp.hpp\"\n#include \"MainAppTestAccess.hpp\"\n#include \"SupportCodeManager.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Settings.hpp\"\n#include <algorithm>\n#include <filesystem>\n\nnamespace {\n\nstruct TestEnvironment {\n    TempDir home_dir;\n    EnvVarGuard home_guard;\n    EnvVarGuard config_guard;\n    Settings settings;\n    bool prompt_state{false};\n\n    TestEnvironment()\n        : home_dir(),\n          home_guard(\"HOME\", home_dir.path().string()),\n          config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", (home_dir.path() / \".config\").string()),\n          settings() {\n        std::filesystem::create_directories(home_dir.path() / \".config\" / \"AIFileSorter\");\n        settings.load();\n    }\n};\n\n} // namespace\n\nstatic void run_support_prompt_case(MainAppTestAccess::SimulatedSupportResult response) {\n    TestEnvironment env;\n    std::vector<int> totals;\n\n    auto callback = [&](int total) {\n        totals.push_back(total);\n        return response;\n    };\n\n    REQUIRE(env.settings.get_total_categorized_files() == 0);\n    const int base_threshold = env.settings.get_next_support_prompt_threshold();\n    REQUIRE(base_threshold > 0);\n\n    const int first_step = std::max(1, base_threshold / 2);\n    const int second_step = base_threshold - first_step;\n\n    MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, first_step, callback);\n    CHECK(env.settings.get_total_categorized_files() == first_step);\n    CHECK(totals.empty());\n\n    MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, second_step, callback);\n    CHECK(env.settings.get_total_categorized_files() == base_threshold);\n    REQUIRE(totals.size() == 1);\n    CHECK(totals.front() == base_threshold);\n    const int next_threshold = env.settings.get_next_support_prompt_threshold();\n    CHECK(next_threshold == base_threshold + 50);\n    const int increment = next_threshold - base_threshold;\n\n    if (increment > 1) {\n        MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, increment - 1, callback);\n        CHECK(totals.size() == 1);\n\n        MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, 1, callback);\n    } else {\n        MainAppTestAccess::simulate_support_prompt(env.settings, env.prompt_state, 1, callback);\n    }\n    CHECK(env.settings.get_total_categorized_files() == base_threshold + increment);\n    REQUIRE(totals.size() == 2);\n    CHECK(totals.back() == base_threshold + increment);\n    CHECK(env.settings.get_next_support_prompt_threshold() == next_threshold + 50);\n}\n\nTEST_CASE(\"Support prompt thresholds advance in fixed 50-file steps\") {\n    run_support_prompt_case(MainAppTestAccess::SimulatedSupportResult::NotSure);\n}\n\nTEST_CASE(\"Zero categorized increments do not change totals or trigger prompts\") {\n    TestEnvironment env;\n    bool callback_invoked = false;\n    const int base_threshold = env.settings.get_next_support_prompt_threshold();\n\n    MainAppTestAccess::simulate_support_prompt(\n        env.settings,\n        env.prompt_state,\n        0,\n        [&](int) {\n            callback_invoked = true;\n            return MainAppTestAccess::SimulatedSupportResult::NotSure;\n        });\n\n    CHECK(env.settings.get_total_categorized_files() == 0);\n    CHECK_FALSE(callback_invoked);\n    CHECK(env.settings.get_next_support_prompt_threshold() == base_threshold);\n}\n\nTEST_CASE(\"Donation code redemption suppresses future support prompts\") {\n    TestEnvironment env;\n    SupportCodeManager support_codes(std::filesystem::path(env.settings.get_config_dir()));\n\n    REQUIRE_FALSE(support_codes.is_prompt_permanently_disabled());\n    REQUIRE_FALSE(SupportCodeManager::is_valid_code(\"not-a-real-code\"));\n    REQUIRE(support_codes.force_disable_prompt_for_testing());\n    CHECK(support_codes.is_prompt_permanently_disabled());\n\n    bool callback_invoked = false;\n    const int threshold = env.settings.get_next_support_prompt_threshold();\n    MainAppTestAccess::simulate_support_prompt(\n        env.settings,\n        env.prompt_state,\n        threshold,\n        [&](int) {\n            callback_invoked = true;\n            return MainAppTestAccess::SimulatedSupportResult::NotSure;\n        });\n\n    CHECK_FALSE(callback_invoked);\n}\n\nTEST_CASE(\"Support response creates suppression state and stops future prompts\") {\n    TestEnvironment env;\n    int callback_count = 0;\n    const int threshold = env.settings.get_next_support_prompt_threshold();\n\n    MainAppTestAccess::simulate_support_prompt(\n        env.settings,\n        env.prompt_state,\n        threshold,\n        [&](int) {\n            ++callback_count;\n            return MainAppTestAccess::SimulatedSupportResult::Support;\n        });\n\n    CHECK(callback_count == 1);\n    CHECK(SupportCodeManager(std::filesystem::path(env.settings.get_config_dir()))\n              .is_prompt_permanently_disabled());\n    CHECK(env.settings.get_next_support_prompt_threshold() == threshold);\n\n    MainAppTestAccess::simulate_support_prompt(\n        env.settings,\n        env.prompt_state,\n        threshold,\n        [&](int) {\n            ++callback_count;\n            return MainAppTestAccess::SimulatedSupportResult::NotSure;\n        });\n\n    CHECK(callback_count == 1);\n}\n"
  },
  {
    "path": "tests/unit/test_ui_translator.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Language.hpp\"\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"UiTranslator.hpp\"\n\n#include <QAction>\n#include <QActionGroup>\n#include <QChar>\n#include <QCheckBox>\n#include <QComboBox>\n#include <QDockWidget>\n#include <QLabel>\n#include <QMainWindow>\n#include <QMenu>\n#include <QPushButton>\n#include <QComboBox>\n#include <QRadioButton>\n#include <QStandardItem>\n#include <QStandardItemModel>\n#include <QStatusBar>\n#include <QString>\n#include <QToolButton>\n\n#ifndef _WIN32\nnamespace {\n\nstruct UiTranslatorTestHarness {\n    EnvVarGuard platform_guard{\"QT_QPA_PLATFORM\", \"offscreen\"};\n    QtAppContext qt_context{};\n    Settings settings{};\n    QMainWindow window{};\n\n    QPointer<QLabel> path_label{new QLabel(&window)};\n    QPointer<QPushButton> browse_button{new QPushButton(&window)};\n    QPointer<QPushButton> analyze_button{new QPushButton(&window)};\n    QPointer<QCheckBox> subcategories_checkbox{new QCheckBox(&window)};\n    QPointer<QLabel> style_heading{new QLabel(&window)};\n    QPointer<QRadioButton> style_refined{new QRadioButton(&window)};\n    QPointer<QRadioButton> style_consistent{new QRadioButton(&window)};\n    QPointer<QCheckBox> use_whitelist{new QCheckBox(&window)};\n    QPointer<QComboBox> whitelist_selector{new QComboBox(&window)};\n    QPointer<QCheckBox> files_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> directories_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> include_subdirectories_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> analyze_images_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> process_images_only_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> add_image_date_to_category_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> add_image_date_place_to_filename_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> add_audio_video_metadata_to_filename_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> offer_rename_images_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> rename_images_only_checkbox{new QCheckBox(&window)};\n    QPointer<QToolButton> image_options_toggle_button{new QToolButton(&window)};\n    QPointer<QCheckBox> analyze_documents_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> process_documents_only_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> offer_rename_documents_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> rename_documents_only_checkbox{new QCheckBox(&window)};\n    QPointer<QCheckBox> add_document_date_to_category_checkbox{new QCheckBox(&window)};\n    QPointer<QToolButton> document_options_toggle_button{new QToolButton(&window)};\n\n    QPointer<QStandardItemModel> tree_model{new QStandardItemModel(0, 5, &window)};\n    QMenu* file_menu = new QMenu(&window);\n    QMenu* edit_menu = new QMenu(&window);\n    QMenu* view_menu = new QMenu(&window);\n    QMenu* settings_menu = new QMenu(&window);\n    QMenu* development_menu = new QMenu(&window);\n    QMenu* development_settings_menu = new QMenu(&window);\n    QMenu* language_menu = new QMenu(&window);\n    QMenu* category_language_menu = new QMenu(&window);\n    QMenu* help_menu = new QMenu(&window);\n\n    QAction* file_quit_action = new QAction(&window);\n    QAction* run_benchmark_action = new QAction(&window);\n    QAction* copy_action = new QAction(&window);\n    QAction* cut_action = new QAction(&window);\n    QAction* undo_last_run_action = new QAction(&window);\n    QAction* paste_action = new QAction(&window);\n    QAction* delete_action = new QAction(&window);\n    QAction* toggle_explorer_action = new QAction(&window);\n    QAction* toggle_llm_action = new QAction(&window);\n    QAction* manage_whitelists_action = new QAction(&window);\n    QAction* development_prompt_logging_action = new QAction(&window);\n    QAction* consistency_pass_action = new QAction(&window);\n    QAction* english_action = new QAction(&window);\n    QAction* dutch_action = new QAction(&window);\n    QAction* french_action = new QAction(&window);\n    QAction* german_action = new QAction(&window);\n    QAction* italian_action = new QAction(&window);\n    QAction* spanish_action = new QAction(&window);\n    QAction* turkish_action = new QAction(&window);\n    QAction* korean_action = new QAction(&window);\n    QAction* category_language_english = new QAction(&window);\n    QAction* category_language_french = new QAction(&window);\n    QAction* category_language_german = new QAction(&window);\n    QAction* category_language_italian = new QAction(&window);\n    QAction* category_language_dutch = new QAction(&window);\n    QAction* category_language_polish = new QAction(&window);\n    QAction* category_language_portuguese = new QAction(&window);\n    QAction* category_language_spanish = new QAction(&window);\n    QAction* category_language_turkish = new QAction(&window);\n    QAction* about_action = new QAction(&window);\n    QAction* about_qt_action = new QAction(&window);\n    QAction* about_agpl_action = new QAction(&window);\n    QAction* support_project_action = new QAction(&window);\n\n    QActionGroup* language_group = new QActionGroup(&window);\n    QActionGroup* category_language_group = new QActionGroup(&window);\n    QPointer<QDockWidget> file_explorer_dock{new QDockWidget(&window)};\n\n    UiTranslator translator;\n    UiTranslator::State state{.analysis_in_progress = false,\n                              .stop_analysis_requested = false,\n                              .status_is_ready = true};\n\n    UiTranslatorTestHarness()\n        : translator(build_deps())\n    {\n        settings.set_language(Language::French);\n        setup_tree_model();\n        setup_language_actions();\n    }\n\n    void setup_tree_model()\n    {\n        tree_model->setRowCount(1);\n        auto* type_item = new QStandardItem();\n        type_item->setData(QStringLiteral(\"D\"), Qt::UserRole);\n        tree_model->setItem(0, 1, type_item);\n        auto* status_item = new QStandardItem();\n        status_item->setData(QStringLiteral(\"ready\"), Qt::UserRole);\n        tree_model->setItem(0, 4, status_item);\n    }\n\n    void setup_language_actions()\n    {\n        language_group->setExclusive(true);\n        english_action->setCheckable(true);\n        english_action->setData(static_cast<int>(Language::English));\n        dutch_action->setCheckable(true);\n        dutch_action->setData(static_cast<int>(Language::Dutch));\n        french_action->setCheckable(true);\n        french_action->setData(static_cast<int>(Language::French));\n        german_action->setCheckable(true);\n        german_action->setData(static_cast<int>(Language::German));\n        italian_action->setCheckable(true);\n        italian_action->setData(static_cast<int>(Language::Italian));\n        spanish_action->setCheckable(true);\n        turkish_action->setCheckable(true);\n        spanish_action->setData(static_cast<int>(Language::Spanish));\n        turkish_action->setData(static_cast<int>(Language::Turkish));\n        korean_action->setCheckable(true);\n        korean_action->setData(static_cast<int>(Language::Korean));\n        language_group->addAction(english_action);\n        language_group->addAction(dutch_action);\n        language_group->addAction(french_action);\n        language_group->addAction(german_action);\n        language_group->addAction(italian_action);\n        language_group->addAction(spanish_action);\n        language_group->addAction(turkish_action);\n        language_group->addAction(korean_action);\n    }\n\n    UiTranslator::Dependencies build_deps()\n    {\n        return UiTranslator::Dependencies{\n            .window = window,\n            .primary = UiTranslator::PrimaryControls{\n                path_label,\n                browse_button,\n                analyze_button,\n                subcategories_checkbox,\n                style_heading,\n                style_refined,\n                style_consistent,\n                use_whitelist,\n                whitelist_selector,\n                files_checkbox,\n                directories_checkbox,\n                include_subdirectories_checkbox,\n                analyze_images_checkbox,\n                process_images_only_checkbox,\n                add_image_date_to_category_checkbox,\n                add_image_date_place_to_filename_checkbox,\n                add_audio_video_metadata_to_filename_checkbox,\n                offer_rename_images_checkbox,\n                rename_images_only_checkbox,\n                image_options_toggle_button,\n                analyze_documents_checkbox,\n                process_documents_only_checkbox,\n                offer_rename_documents_checkbox,\n                rename_documents_only_checkbox,\n                add_document_date_to_category_checkbox,\n                document_options_toggle_button},\n            .tree_model = tree_model,\n            .menus = UiTranslator::MenuControls{\n                file_menu,\n                edit_menu,\n                view_menu,\n                settings_menu,\n                development_menu,\n                development_settings_menu,\n                language_menu,\n                category_language_menu,\n                help_menu},\n            .actions = UiTranslator::ActionControls{\n                file_quit_action,\n                run_benchmark_action,\n                copy_action,\n                cut_action,\n                undo_last_run_action,\n                paste_action,\n                delete_action,\n                toggle_explorer_action,\n                toggle_llm_action,\n                manage_whitelists_action,\n                development_prompt_logging_action,\n                consistency_pass_action,\n                english_action,\n                dutch_action,\n                french_action,\n                german_action,\n                italian_action,\n                spanish_action,\n                turkish_action,\n                korean_action,\n                category_language_english,\n                category_language_french,\n                category_language_german,\n                category_language_italian,\n                category_language_dutch,\n                category_language_polish,\n                category_language_portuguese,\n                category_language_spanish,\n                category_language_turkish,\n                about_action,\n                about_qt_action,\n                about_agpl_action,\n                support_project_action},\n            .language = UiTranslator::LanguageControls{\n                language_group,\n                english_action,\n                dutch_action,\n                french_action,\n                german_action,\n                italian_action,\n                spanish_action,\n                turkish_action,\n                korean_action},\n            .category_language = UiTranslator::CategoryLanguageControls{\n                category_language_group,\n                category_language_dutch,\n                category_language_english,\n                category_language_french,\n                category_language_german,\n                category_language_italian,\n                category_language_polish,\n                category_language_portuguese,\n                category_language_spanish,\n                category_language_turkish},\n            .file_explorer_dock = file_explorer_dock,\n            .settings = settings,\n            .translator = [](const char* source) {\n                return QString::fromUtf8(source);\n            }\n        };\n    }\n};\n\nvoid verify_primary_controls(const UiTranslatorTestHarness& h)\n{\n    REQUIRE(h.path_label->text() == QStringLiteral(\"Folder:\"));\n    REQUIRE(h.browse_button->text() == QStringLiteral(\"Browse…\"));\n    REQUIRE(h.analyze_button->text() == QStringLiteral(\"Analyze folder\"));\n    REQUIRE(h.subcategories_checkbox->text() == QStringLiteral(\"Use subcategories\"));\n    REQUIRE(h.style_heading->text() == QStringLiteral(\"Categorization type\"));\n    REQUIRE(h.style_refined->text() == QStringLiteral(\"More refined\"));\n    REQUIRE(h.style_consistent->text() == QStringLiteral(\"More consistent\"));\n    REQUIRE(h.use_whitelist->text() == QStringLiteral(\"Use a whitelist\"));\n    REQUIRE(h.files_checkbox->text() == QStringLiteral(\"Categorize files\"));\n    REQUIRE(h.directories_checkbox->text() == QStringLiteral(\"Categorize folders\"));\n    REQUIRE(h.include_subdirectories_checkbox->text() == QStringLiteral(\"Scan subfolders\"));\n    REQUIRE(h.analyze_images_checkbox->text() == QStringLiteral(\"Analyze picture files by content (can be slow)\"));\n    REQUIRE(h.process_images_only_checkbox->text() ==\n            QStringLiteral(\"Process picture files only (ignore any other files)\"));\n    REQUIRE(h.add_image_date_to_category_checkbox->text() ==\n            QStringLiteral(\"Add image creation date (if available) to category name\"));\n    REQUIRE(h.add_image_date_place_to_filename_checkbox->text() ==\n            QStringLiteral(\"Add photo date and place to filename (if available)\"));\n    REQUIRE(h.add_audio_video_metadata_to_filename_checkbox->text() ==\n            QStringLiteral(\"Add audio/video metadata to file name (if available)\"));\n    REQUIRE(h.offer_rename_images_checkbox->text() == QStringLiteral(\"Offer to rename picture files\"));\n    REQUIRE(h.rename_images_only_checkbox->text() == QStringLiteral(\"Do not categorize picture files (only rename)\"));\n    REQUIRE(h.analyze_documents_checkbox->text() == QStringLiteral(\"Analyze document files by content\"));\n    REQUIRE(h.process_documents_only_checkbox->text() ==\n            QStringLiteral(\"Process document files only (ignore any other files)\"));\n    REQUIRE(h.offer_rename_documents_checkbox->text() == QStringLiteral(\"Offer to rename document files\"));\n    REQUIRE(h.rename_documents_only_checkbox->text() == QStringLiteral(\"Do not categorize document files (only rename)\"));\n    REQUIRE(h.add_document_date_to_category_checkbox->text() ==\n            QStringLiteral(\"Add document creation date (if available) to category name\"));\n}\n\nvoid verify_menus_and_actions(const UiTranslatorTestHarness& h)\n{\n    REQUIRE(h.file_menu->title() == QStringLiteral(\"&File\"));\n    REQUIRE(h.settings_menu->title() == QStringLiteral(\"&Settings\"));\n    REQUIRE(h.run_benchmark_action->text() == QStringLiteral(\"System compatibility check…\"));\n    REQUIRE(h.toggle_llm_action->text() == QStringLiteral(\"Select &LLM…\"));\n    REQUIRE(h.manage_whitelists_action->text() == QStringLiteral(\"Manage category whitelists…\"));\n    REQUIRE(h.development_prompt_logging_action->text() ==\n            QStringLiteral(\"Log prompts and responses to stdout\"));\n\n    const QString help_title = h.help_menu->title();\n    REQUIRE(help_title.endsWith(QStringLiteral(\"&Help\")));\n    REQUIRE(help_title.startsWith(QString(QChar(0x200B))));\n}\n\nvoid verify_tree_and_status(const UiTranslatorTestHarness& h)\n{\n    REQUIRE(h.file_explorer_dock->windowTitle() == QStringLiteral(\"File Explorer\"));\n    REQUIRE(h.tree_model->horizontalHeaderItem(0)->text() == QStringLiteral(\"File\"));\n    REQUIRE(h.tree_model->item(0, 1)->text() == QStringLiteral(\"Directory\"));\n    REQUIRE(h.tree_model->item(0, 4)->text() == QStringLiteral(\"Ready\"));\n    REQUIRE_FALSE(h.english_action->isChecked());\n    REQUIRE(h.french_action->isChecked());\n    REQUIRE(h.window.statusBar()->currentMessage() == QStringLiteral(\"Ready\"));\n}\n\n} // namespace\n\nTEST_CASE(\"UiTranslator updates menus, actions, and controls\")\n{\n    UiTranslatorTestHarness h;\n    h.translator.retranslate_all(h.state);\n    verify_primary_controls(h);\n    verify_menus_and_actions(h);\n    verify_tree_and_status(h);\n}\n#endif\n"
  },
  {
    "path": "tests/unit/test_update_feed.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"UpdateFeed.hpp\"\n#include \"UpdateInstaller.hpp\"\n#include \"UpdateInstallerTestAccess.hpp\"\n#include \"TestHelpers.hpp\"\n\n#include <QByteArrayView>\n#include <QCryptographicHash>\n\n#include <filesystem>\n#include <fstream>\n#include <vector>\n\n#include <zip.h>\n\nnamespace {\n\nstd::string sha256_hex(std::string_view payload)\n{\n    QCryptographicHash hash(QCryptographicHash::Sha256);\n    hash.addData(QByteArrayView(payload.data(), static_cast<qsizetype>(payload.size())));\n    return hash.result().toHex().toStdString();\n}\n\nstd::string read_file(const std::filesystem::path& path)\n{\n    std::ifstream in(path, std::ios::binary);\n    return std::string(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());\n}\n\nvoid create_zip_archive(const std::filesystem::path& archive_path,\n                        const std::vector<std::pair<std::string, std::string>>& entries)\n{\n    int error_code = 0;\n    zip_t* archive = zip_open(archive_path.string().c_str(), ZIP_CREATE | ZIP_TRUNCATE, &error_code);\n    REQUIRE(archive != nullptr);\n\n    for (const auto& [name, payload] : entries) {\n        zip_source_t* source = zip_source_buffer(archive,\n                                                 payload.data(),\n                                                 static_cast<zip_uint64_t>(payload.size()),\n                                                 0);\n        REQUIRE(source != nullptr);\n        const zip_int64_t index = zip_file_add(archive,\n                                               name.c_str(),\n                                               source,\n                                               ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8);\n        REQUIRE(index >= 0);\n    }\n\n    REQUIRE(zip_close(archive) == 0);\n}\n\n} // namespace\n\nTEST_CASE(\"UpdateFeed selects the correct platform stream\") {\n    const std::string json = R\"json(\n        {\n            \"update\": {\n                \"windows\": {\n                    \"current_version\": \"1.8.0\",\n                    \"min_version\": \"1.7.0\",\n                    \"download_url\": \"https://filesorter.app/windows\",\n                    \"installer_url\": \"https://filesorter.app/aifs-1.8.0.exe\",\n                    \"installer_sha256\": \"ABCDEF\"\n                },\n                \"macos\": {\n                    \"current_version\": \"1.8.1\",\n                    \"min_version\": \"1.6.0\",\n                    \"download_url\": \"https://filesorter.app/macos\"\n                },\n                \"linux\": {\n                    \"current_version\": \"1.8.2\",\n                    \"min_version\": \"1.5.0\",\n                    \"download_url\": \"https://filesorter.app/linux\"\n                }\n            }\n        }\n    )json\";\n\n    const auto windows = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Windows);\n    REQUIRE(windows.has_value());\n    CHECK(windows->current_version == \"1.8.0\");\n    CHECK(windows->min_version == \"1.7.0\");\n    CHECK(windows->download_url == \"https://filesorter.app/windows\");\n    CHECK(windows->installer_url == \"https://filesorter.app/aifs-1.8.0.exe\");\n    CHECK(windows->installer_sha256 == \"abcdef\");\n\n    const auto macos = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::MacOS);\n    REQUIRE(macos.has_value());\n    CHECK(macos->current_version == \"1.8.1\");\n    CHECK(macos->download_url == \"https://filesorter.app/macos\");\n    CHECK(macos->installer_url.empty());\n\n    const auto linux = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Linux);\n    REQUIRE(linux.has_value());\n    CHECK(linux->current_version == \"1.8.2\");\n    CHECK(linux->download_url == \"https://filesorter.app/linux\");\n}\n\nTEST_CASE(\"UpdateFeed falls back to the legacy single-stream schema\") {\n    const std::string json = R\"json(\n        {\n            \"update\": {\n                \"current_version\": \"1.7.1\",\n                \"min_version\": \"1.6.0\",\n                \"download_url\": \"https://filesorter.app/download\"\n            }\n        }\n    )json\";\n\n    const auto info = UpdateFeed::parse_for_platform(json, UpdateFeed::Platform::Windows);\n    REQUIRE(info.has_value());\n    CHECK(info->current_version == \"1.7.1\");\n    CHECK(info->min_version == \"1.6.0\");\n    CHECK(info->download_url == \"https://filesorter.app/download\");\n}\n\nTEST_CASE(\"UpdateInstaller downloads, verifies, and reuses a cached installer\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    const std::string payload = \"signed-installer-payload\";\n    const std::string expected_sha256 = sha256_hex(payload);\n\n    int download_calls = 0;\n    std::filesystem::path prepared_path;\n    std::filesystem::path launched_path;\n\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback progress_cb,\n            UpdateInstaller::CancelCheck) {\n            ++download_calls;\n            prepared_path = destination_path;\n            if (progress_cb) {\n                progress_cb(0.5, \"Downloading\");\n                progress_cb(1.0, \"Downloaded\");\n            }\n            std::ofstream out(destination_path, std::ios::binary | std::ios::trunc);\n            out << payload;\n        },\n        [&](const std::filesystem::path& path) {\n            launched_path = path;\n            return true;\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = expected_sha256;\n\n    const auto first = installer.prepare(info);\n    REQUIRE(first.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 1);\n    CHECK(std::filesystem::exists(first.installer_path));\n    CHECK(first.installer_path.extension() == \".exe\");\n    CHECK(prepared_path.extension() == \".part\");\n\n    const auto second = installer.prepare(info);\n    REQUIRE(second.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 1);\n    CHECK(second.installer_path == first.installer_path);\n\n    CHECK(installer.launch(second.installer_path));\n    CHECK(launched_path == second.installer_path);\n}\n\nTEST_CASE(\"UpdateInstaller rejects installers that fail SHA-256 verification\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback,\n            UpdateInstaller::CancelCheck) {\n            std::ofstream out(destination_path, std::ios::binary | std::ios::trunc);\n            out << \"tampered\";\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = sha256_hex(\"expected\");\n\n    const auto result = installer.prepare(info);\n    REQUIRE(result.status == UpdatePreparationResult::Status::Failed);\n    CHECK(result.message.find(\"SHA-256\") != std::string::npos);\n    CHECK(result.installer_path.empty());\n}\n\nTEST_CASE(\"UpdateInstaller extracts installer payloads from ZIP update packages\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    const std::string installer_payload = \"installer-from-zip\";\n    const auto archive_path = tmp.path() / \"AIFileSorterSetup.zip\";\n    create_zip_archive(archive_path, {{\"nested/AIFileSorterSetup.exe\", installer_payload}});\n    const std::string expected_sha256 = sha256_hex(read_file(archive_path));\n\n    int download_calls = 0;\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback,\n            UpdateInstaller::CancelCheck) {\n            ++download_calls;\n            std::filesystem::copy_file(\n                archive_path,\n                destination_path,\n                std::filesystem::copy_options::overwrite_existing);\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.zip\";\n    info.installer_sha256 = expected_sha256;\n\n    const auto first = installer.prepare(info);\n    REQUIRE(first.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 1);\n    CHECK(first.installer_path.extension() == \".exe\");\n    CHECK(first.installer_path.filename() == \"AIFileSorterSetup.exe\");\n    CHECK(read_file(first.installer_path) == installer_payload);\n\n    const auto second = installer.prepare(info);\n    REQUIRE(second.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 1);\n    CHECK(second.installer_path == first.installer_path);\n}\n\nTEST_CASE(\"UpdateInstaller rejects ZIP update packages without an installer payload\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    const auto archive_path = tmp.path() / \"AIFileSorterSetup.zip\";\n    create_zip_archive(archive_path, {{\"README.txt\", \"no installer here\"}});\n    const std::string expected_sha256 = sha256_hex(read_file(archive_path));\n\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback,\n            UpdateInstaller::CancelCheck) {\n            std::filesystem::copy_file(\n                archive_path,\n                destination_path,\n                std::filesystem::copy_options::overwrite_existing);\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.zip\";\n    info.installer_sha256 = expected_sha256;\n\n    const auto result = installer.prepare(info);\n    REQUIRE(result.status == UpdatePreparationResult::Status::Failed);\n    CHECK(result.message.find(\"ZIP archive\") != std::string::npos);\n    CHECK(result.installer_path.empty());\n}\n\nTEST_CASE(\"UpdateInstaller redownloads cached installers that fail verification\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    const std::string payload = \"fresh-installer-payload\";\n    const std::string expected_sha256 = sha256_hex(payload);\n\n    int download_calls = 0;\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback,\n            UpdateInstaller::CancelCheck) {\n            ++download_calls;\n            std::ofstream out(destination_path, std::ios::binary | std::ios::trunc);\n            out << payload;\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = expected_sha256;\n\n    const auto first = installer.prepare(info);\n    REQUIRE(first.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 1);\n\n    {\n        std::ofstream out(first.installer_path, std::ios::binary | std::ios::trunc);\n        out << \"tampered-cache\";\n    }\n\n    const auto second = installer.prepare(info);\n    REQUIRE(second.status == UpdatePreparationResult::Status::Ready);\n    CHECK(download_calls == 2);\n    CHECK(second.installer_path == first.installer_path);\n    CHECK(read_file(second.installer_path) == payload);\n}\n\nTEST_CASE(\"UpdateInstaller reports canceled downloads and removes partial files\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    std::filesystem::path partial_path;\n    UpdateInstaller installer(\n        settings,\n        [&](const std::string&,\n            const std::filesystem::path& destination_path,\n            UpdateInstaller::ProgressCallback,\n            UpdateInstaller::CancelCheck cancel_check) {\n            partial_path = destination_path;\n            std::ofstream out(destination_path, std::ios::binary | std::ios::trunc);\n            out << \"partial\";\n            if (cancel_check && cancel_check()) {\n                throw UpdateInstaller::DownloadCanceledError();\n            }\n        });\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = sha256_hex(\"payload\");\n\n    const auto result = installer.prepare(info, {}, []() { return true; });\n    REQUIRE(result.status == UpdatePreparationResult::Status::Canceled);\n    CHECK(result.message.find(\"cancel\") != std::string::npos);\n    CHECK(result.installer_path.empty());\n    CHECK_FALSE(partial_path.empty());\n    CHECK_FALSE(std::filesystem::exists(partial_path));\n}\n\nTEST_CASE(\"UpdateInstaller requires installer metadata before preparing\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    UpdateInstaller installer(settings);\n\n    UpdateInfo missing_url;\n    missing_url.current_version = \"1.8.0\";\n    missing_url.installer_sha256 = sha256_hex(\"payload\");\n\n    const auto missing_url_result = installer.prepare(missing_url);\n    REQUIRE(missing_url_result.status == UpdatePreparationResult::Status::Failed);\n    CHECK(missing_url_result.message.find(\"URL\") != std::string::npos);\n\n    UpdateInfo missing_sha;\n    missing_sha.current_version = \"1.8.0\";\n    missing_sha.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n\n    const auto missing_sha_result = installer.prepare(missing_sha);\n    REQUIRE(missing_sha_result.status == UpdatePreparationResult::Status::Failed);\n    CHECK(missing_sha_result.message.find(\"SHA-256\") != std::string::npos);\n}\n\nTEST_CASE(\"UpdateInstaller builds launch requests for EXE and MSI installers\") {\n    const auto exe_request = UpdateInstallerTestAccess::build_launch_request(\n        std::filesystem::path(\"C:/Program Files/AI File Sorter/AIFileSorterSetup.exe\"));\n    CHECK(exe_request.program == \"C:/Program Files/AI File Sorter/AIFileSorterSetup.exe\");\n    CHECK(exe_request.arguments.empty());\n\n    const auto msi_request = UpdateInstallerTestAccess::build_launch_request(\n        std::filesystem::path(\"C:/Program Files/AI File Sorter/AIFileSorterSetup.MSI\"));\n    CHECK(msi_request.program == \"msiexec.exe\");\n    REQUIRE(msi_request.arguments.size() == 2);\n    CHECK(msi_request.arguments[0] == \"/i\");\n    CHECK(msi_request.arguments[1] == \"C:/Program Files/AI File Sorter/AIFileSorterSetup.MSI\");\n}\n\nTEST_CASE(\"UpdateInstaller auto-install support remains Windows-only\") {\n    TempDir tmp;\n    EnvVarGuard config_root(\"AI_FILE_SORTER_CONFIG_DIR\", tmp.path().string());\n\n    Settings settings;\n    UpdateInstaller installer(settings);\n\n    UpdateInfo info;\n    info.current_version = \"1.8.0\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = sha256_hex(\"payload\");\n\n#ifdef _WIN32\n    CHECK(installer.supports_auto_install(info));\n#else\n    CHECK_FALSE(installer.supports_auto_install(info));\n#endif\n}\n"
  },
  {
    "path": "tests/unit/test_updater.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Updater.hpp\"\n#include \"UpdaterLaunchOptions.hpp\"\n#include \"UpdaterLiveTestConfig.hpp\"\n#include \"UpdaterTestAccess.hpp\"\n#include \"app_version.hpp\"\n\n#include <QAbstractButton>\n#include <QMessageBox>\n#include <QTimer>\n\n#include <filesystem>\n#include <fstream>\n#include <memory>\n\nnamespace {\n\nvoid schedule_message_box_button_click(const QString& target_text, bool* saw_button = nullptr)\n{\n    auto clicker = std::make_shared<std::function<void(int)>>();\n    *clicker = [clicker, target_text, saw_button](int attempts_remaining) {\n        auto* box = qobject_cast<QMessageBox*>(QApplication::activeModalWidget());\n        if (!box) {\n            if (attempts_remaining > 0) {\n                QTimer::singleShot(0, [clicker, attempts_remaining]() {\n                    (*clicker)(attempts_remaining - 1);\n                });\n                return;\n            }\n            if (saw_button) {\n                *saw_button = false;\n            }\n            return;\n        }\n\n        for (auto* button : box->buttons()) {\n            if (button && button->text() == target_text) {\n                if (saw_button) {\n                    *saw_button = true;\n                }\n                button->click();\n                return;\n            }\n        }\n\n        if (saw_button) {\n            *saw_button = false;\n        }\n        if (auto* ok_button = box->button(QMessageBox::Ok)) {\n            ok_button->click();\n        }\n    };\n\n    QTimer::singleShot(0, [clicker]() {\n        (*clicker)(10);\n    });\n}\n\n} // namespace\n\nTEST_CASE(\"Updater live test mode synthesizes a newer update without a feed URL\")\n{\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", std::nullopt);\n    EnvVarGuard live_test_mode_guard(UpdaterLaunchOptions::kLiveTestModeEnv, std::string(\"1\"));\n    EnvVarGuard live_test_url_guard(UpdaterLaunchOptions::kLiveTestUrlEnv,\n                                    std::string(\"https://filesorter.app/downloads/AIFileSorterSetup.zip\"));\n    EnvVarGuard live_test_sha_guard(UpdaterLaunchOptions::kLiveTestSha256Env,\n                                    std::string(\"AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899\"));\n    EnvVarGuard live_test_version_guard(UpdaterLaunchOptions::kLiveTestVersionEnv, std::nullopt);\n    EnvVarGuard live_test_min_guard(UpdaterLaunchOptions::kLiveTestMinVersionEnv, std::nullopt);\n\n    Settings settings;\n    Updater updater(settings);\n\n    REQUIRE(UpdaterTestAccess::is_update_available(updater));\n    const auto info = UpdaterTestAccess::current_update_info(updater);\n    REQUIRE(info.has_value());\n    CHECK(info->current_version == APP_VERSION.to_string() + \".1\");\n    CHECK(info->min_version == \"0.0.0\");\n    CHECK(info->download_url == \"https://filesorter.app/downloads/AIFileSorterSetup.zip\");\n    CHECK(info->installer_url == info->download_url);\n    CHECK(info->installer_sha256 == \"aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899\");\n}\n\nTEST_CASE(\"Updater live test mode can read missing values from live-test.ini next to the executable\")\n{\n    TempDir temp_dir;\n    const auto exe_dir = temp_dir.path() / \"bin\";\n    std::filesystem::create_directories(exe_dir);\n\n    {\n        std::ofstream out(exe_dir / \"live-test.ini\", std::ios::binary | std::ios::trunc);\n        out << \"[LiveTest]\\n\";\n        out << \"download_url = https://filesorter.app/downloads/from-ini.zip\\n\";\n        out << \"sha256 = 11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\\n\";\n        out << \"current_version = 9.9.9\\n\";\n        out << \"min_version = 1.0.0\\n\";\n    }\n\n    UpdaterLiveTestConfig config;\n    config.enabled = true;\n\n    const auto loaded = load_missing_values_from_live_test_ini(config, exe_dir / \"aifilesorter.exe\");\n    REQUIRE(loaded.has_value());\n    CHECK(loaded->filename() == \"live-test.ini\");\n    REQUIRE(config.installer_url.has_value());\n    REQUIRE(config.installer_sha256.has_value());\n    REQUIRE(config.current_version.has_value());\n    REQUIRE(config.min_version.has_value());\n    CHECK(*config.installer_url == \"https://filesorter.app/downloads/from-ini.zip\");\n    CHECK(*config.installer_sha256 == \"11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\");\n    CHECK(*config.current_version == \"9.9.9\");\n    CHECK(*config.min_version == \"1.0.0\");\n}\n\nTEST_CASE(\"Updater live test flags override live-test.ini values\")\n{\n    TempDir temp_dir;\n    const auto exe_dir = temp_dir.path() / \"bin\";\n    std::filesystem::create_directories(exe_dir);\n\n    {\n        std::ofstream out(exe_dir / \"live-test.ini\", std::ios::binary | std::ios::trunc);\n        out << \"[LiveTest]\\n\";\n        out << \"download_url = https://filesorter.app/downloads/from-ini.zip\\n\";\n        out << \"sha256 = 11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\\n\";\n    }\n\n    UpdaterLiveTestConfig config;\n    config.enabled = true;\n    config.installer_url = \"https://filesorter.app/downloads/from-flag.zip\";\n\n    const auto loaded = load_missing_values_from_live_test_ini(config, exe_dir / \"aifilesorter.exe\");\n    REQUIRE(loaded.has_value());\n    REQUIRE(config.installer_url.has_value());\n    REQUIRE(config.installer_sha256.has_value());\n    CHECK(*config.installer_url == \"https://filesorter.app/downloads/from-flag.zip\");\n    CHECK(*config.installer_sha256 == \"11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF\");\n}\n\nTEST_CASE(\"Updater error dialog offers manual update fallback without quitting when not requested\")\n{\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", \"https://example.com/aifs_version.json\");\n\n    Settings settings;\n    Updater updater(settings);\n\n    std::string opened_url;\n    bool quit_called = false;\n    bool saw_manual_button = false;\n\n    UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) {\n        opened_url = url;\n    });\n    UpdaterTestAccess::set_quit_handler(updater, [&]() {\n        quit_called = true;\n    });\n\n    UpdateInfo info;\n    info.download_url = \"https://filesorter.app/download\";\n\n    schedule_message_box_button_click(QStringLiteral(\"Update manually\"), &saw_manual_button);\n\n    const bool result = UpdaterTestAccess::handle_update_error(\n        updater,\n        info,\n        QStringLiteral(\"Failed to prepare the update installer.\"),\n        nullptr,\n        false);\n\n    CHECK(result);\n    CHECK(saw_manual_button);\n    CHECK(opened_url == info.download_url);\n    CHECK_FALSE(quit_called);\n}\n\nTEST_CASE(\"Updater error dialog can request quit after manual fallback\")\n{\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", \"https://example.com/aifs_version.json\");\n\n    Settings settings;\n    Updater updater(settings);\n\n    std::string opened_url;\n    bool quit_called = false;\n\n    UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) {\n        opened_url = url;\n    });\n    UpdaterTestAccess::set_quit_handler(updater, [&]() {\n        quit_called = true;\n    });\n\n    UpdateInfo info;\n    info.download_url = \"https://filesorter.app/download\";\n\n    schedule_message_box_button_click(QStringLiteral(\"Update manually\"));\n\n    const bool result = UpdaterTestAccess::handle_update_error(\n        updater,\n        info,\n        QStringLiteral(\"The installer could not be launched.\"),\n        nullptr,\n        true);\n\n    CHECK(result);\n    CHECK(opened_url == info.download_url);\n    CHECK(quit_called);\n}\n\nTEST_CASE(\"Updater error dialog omits manual fallback when no download URL is available\")\n{\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    QtAppContext qt_context;\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", \"https://example.com/aifs_version.json\");\n\n    Settings settings;\n    Updater updater(settings);\n\n    std::string opened_url;\n    bool quit_called = false;\n    bool saw_manual_button = true;\n\n    UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) {\n        opened_url = url;\n    });\n    UpdaterTestAccess::set_quit_handler(updater, [&]() {\n        quit_called = true;\n    });\n\n    UpdateInfo info;\n\n    schedule_message_box_button_click(QStringLiteral(\"Update manually\"), &saw_manual_button);\n\n    const bool result = UpdaterTestAccess::handle_update_error(\n        updater,\n        info,\n        QStringLiteral(\"No download target is available for this update.\"),\n        nullptr,\n        true);\n\n    CHECK_FALSE(result);\n    CHECK_FALSE(saw_manual_button);\n    CHECK(opened_url.empty());\n    CHECK_FALSE(quit_called);\n}\n"
  },
  {
    "path": "tests/unit/test_updater_build_modes.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"Settings.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"UpdateFeed.hpp\"\n#include \"Updater.hpp\"\n#include \"UpdaterBuildConfig.hpp\"\n#include \"UpdaterLaunchOptions.hpp\"\n#include \"UpdaterTestAccess.hpp\"\n\n#include <QApplication>\n\nnamespace {\n\nconstexpr UpdaterBuildConfig::Mode expected_mode()\n{\n#if defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_DISABLED)\n    return UpdaterBuildConfig::Mode::Disabled;\n#elif defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_NOTIFY_ONLY)\n    return UpdaterBuildConfig::Mode::NotifyOnly;\n#elif defined(AI_FILE_SORTER_EXPECTED_UPDATE_MODE_AUTO_INSTALL)\n    return UpdaterBuildConfig::Mode::AutoInstall;\n#else\n    static_assert(false, \"Expected updater mode macro is not defined for this test target.\");\n#endif\n}\n\nvoid ensure_qt_application()\n{\n    if (QApplication::instance()) {\n        return;\n    }\n\n    static int argc = 1;\n    static char arg0[] = \"updater-build-mode-tests\";\n    static char* argv[] = {arg0, nullptr};\n    static QApplication app(argc, argv);\n    Q_UNUSED(app);\n}\n\n} // namespace\n\nTEST_CASE(\"Updater build config matches the expected mode for this target\")\n{\n    CHECK(UpdaterBuildConfig::current_mode() == expected_mode());\n    CHECK(UpdaterBuildConfig::update_checks_enabled()\n          == (expected_mode() != UpdaterBuildConfig::Mode::Disabled));\n    CHECK(UpdaterBuildConfig::auto_install_enabled()\n          == (expected_mode() == UpdaterBuildConfig::Mode::AutoInstall));\n}\n\nTEST_CASE(\"Updater begin schedules work only when update checks are enabled\")\n{\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    ensure_qt_application();\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", std::nullopt);\n\n    Settings settings;\n    Updater updater(settings);\n\n    updater.begin();\n\n    CHECK(UpdaterTestAccess::has_update_task(updater)\n          == (expected_mode() != UpdaterBuildConfig::Mode::Disabled));\n    UpdaterTestAccess::wait_for_update_task(updater);\n}\n\nTEST_CASE(\"Notify-only updater opens the download page instead of preparing an installer\")\n{\n    if constexpr (expected_mode() != UpdaterBuildConfig::Mode::NotifyOnly) {\n        SUCCEED(\"This target is not built in notify-only mode.\");\n        return;\n    }\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n\n    Settings settings;\n    Updater updater(settings);\n\n    std::string opened_url;\n    bool quit_called = false;\n\n    UpdaterTestAccess::set_open_download_url_handler(updater, [&](const std::string& url) {\n        opened_url = url;\n    });\n    UpdaterTestAccess::set_quit_handler(updater, [&]() {\n        quit_called = true;\n    });\n\n    UpdateInfo info;\n    info.current_version = \"9.9.9\";\n    info.download_url = \"https://filesorter.app/downloads/AIFileSorterSetup.zip\";\n    info.installer_url = \"https://filesorter.app/downloads/AIFileSorterSetup.exe\";\n    info.installer_sha256 = \"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\";\n\n    const bool result = UpdaterTestAccess::trigger_update_action(updater, info, nullptr, true);\n\n    CHECK(result);\n    CHECK(opened_url == info.download_url);\n    CHECK(quit_called);\n}\n\nTEST_CASE(\"Disabled updater mode ignores live-test environment when startup checks are blocked\")\n{\n    if constexpr (expected_mode() != UpdaterBuildConfig::Mode::Disabled) {\n        SUCCEED(\"This target still allows updater startup checks.\");\n        return;\n    }\n\n    EnvVarGuard platform_guard(\"QT_QPA_PLATFORM\", \"offscreen\");\n    ensure_qt_application();\n\n    TempDir config_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", config_dir.path().string());\n    EnvVarGuard update_spec_guard(\"UPDATE_SPEC_FILE_URL\", std::nullopt);\n    EnvVarGuard live_test_mode_guard(UpdaterLaunchOptions::kLiveTestModeEnv, std::string(\"1\"));\n    EnvVarGuard live_test_url_guard(UpdaterLaunchOptions::kLiveTestUrlEnv,\n                                    std::string(\"https://filesorter.app/downloads/AIFileSorterSetup.zip\"));\n    EnvVarGuard live_test_sha_guard(UpdaterLaunchOptions::kLiveTestSha256Env,\n                                    std::string(\"AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899\"));\n\n    Settings settings;\n    Updater updater(settings);\n\n    updater.begin();\n\n    CHECK_FALSE(UpdaterTestAccess::has_update_task(updater));\n    CHECK_FALSE(UpdaterTestAccess::current_update_info(updater).has_value());\n}\n"
  },
  {
    "path": "tests/unit/test_utils.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n#include \"Utils.hpp\"\n#include \"TestHooks.hpp\"\n#include \"TestHelpers.hpp\"\n#include <optional>\n#include <filesystem>\n#include <fstream>\n\nTEST_CASE(\"get_file_name_from_url extracts filename\") {\n    const std::string url = \"https://example.com/models/mistral-7b.gguf\";\n    REQUIRE(Utils::get_file_name_from_url(url) == \"mistral-7b.gguf\");\n}\n\nTEST_CASE(\"get_file_name_from_url rejects malformed input\") {\n    REQUIRE_THROWS_AS(Utils::get_file_name_from_url(\"https://example.com/\"), std::runtime_error);\n}\n\nTEST_CASE(\"is_cuda_available honors probe overrides\") {\n    struct ProbeGuard {\n        ~ProbeGuard() { TestHooks::reset_cuda_availability_probe(); }\n    } guard;\n\n    TestHooks::set_cuda_availability_probe([] { return true; });\n    REQUIRE(Utils::is_cuda_available());\n\n    TestHooks::set_cuda_availability_probe([] { return false; });\n    REQUIRE_FALSE(Utils::is_cuda_available());\n}\n\nTEST_CASE(\"abbreviate_user_path strips home prefix\") {\n    TempDir temp_home;\n    EnvVarGuard home_guard(\"HOME\", temp_home.path().string());\n    const auto file = temp_home.path() / \"Documents\" / \"taxes.pdf\";\n    std::filesystem::create_directories(file.parent_path());\n    std::ofstream(file).put('x');\n\n    const std::string abbreviated =\n        Utils::abbreviate_user_path(file.string());\n    REQUIRE(abbreviated == \"Documents/taxes.pdf\");\n}\n\nTEST_CASE(\"sanitize_path_label strips invalid UTF-8 bytes\") {\n    std::string invalid = \"Alpha\";\n    invalid.push_back(static_cast<char>(0xFF));\n    invalid += \"Beta\";\n\n    REQUIRE(Utils::sanitize_path_label(invalid) == \"AlphaBeta\");\n}\n"
  },
  {
    "path": "tests/unit/test_whitelist_and_prompt.cpp",
    "content": "#include <catch2/catch_test_macros.hpp>\n\n#include \"CategorizationService.hpp\"\n#include \"CategorizationServiceTestAccess.hpp\"\n#include \"DatabaseManager.hpp\"\n#include \"ILLMClient.hpp\"\n#include \"MainAppTestAccess.hpp\"\n#include \"CategoryLanguage.hpp\"\n#include \"LocalLLMTestAccess.hpp\"\n#include \"Settings.hpp\"\n#include \"WhitelistStore.hpp\"\n#include \"TestHelpers.hpp\"\n#include \"Utils.hpp\"\n\n#include <atomic>\n#include <deque>\n#include <memory>\n\nnamespace {\nclass FixedResponseLLM : public ILLMClient {\npublic:\n    FixedResponseLLM(std::shared_ptr<int> calls, std::string response)\n        : calls_(std::move(calls)), response_(std::move(response)) {}\n\n    std::string categorize_file(const std::string&,\n                                const std::string&,\n                                FileType,\n                                const std::string&) override {\n        ++(*calls_);\n        return response_;\n    }\n\n    std::string complete_prompt(const std::string&, int) override {\n        return std::string();\n    }\n\n    void set_prompt_logging_enabled(bool) override {\n    }\n\nprivate:\n    std::shared_ptr<int> calls_;\n    std::string response_;\n};\n\nclass TranslationAwareLLM : public ILLMClient {\npublic:\n    TranslationAwareLLM(std::shared_ptr<int> categorize_calls,\n                        std::shared_ptr<int> translation_calls,\n                        std::string categorize_response,\n                        std::deque<std::string> translation_responses)\n        : categorize_calls_(std::move(categorize_calls)),\n          translation_calls_(std::move(translation_calls)),\n          categorize_response_(std::move(categorize_response)),\n          translation_responses_(std::move(translation_responses)) {}\n\n    std::string categorize_file(const std::string&,\n                                const std::string&,\n                                FileType,\n                                const std::string&) override {\n        ++(*categorize_calls_);\n        return categorize_response_;\n    }\n\n    std::string complete_prompt(const std::string&, int) override {\n        ++(*translation_calls_);\n        if (translation_responses_.empty()) {\n            return std::string();\n        }\n        std::string response = translation_responses_.front();\n        translation_responses_.pop_front();\n        return response;\n    }\n\n    void set_prompt_logging_enabled(bool) override {\n    }\n\nprivate:\n    std::shared_ptr<int> categorize_calls_;\n    std::shared_ptr<int> translation_calls_;\n    std::string categorize_response_;\n    std::deque<std::string> translation_responses_;\n};\n} // namespace\n\nTEST_CASE(\"WhitelistStore initializes from settings and persists defaults\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    settings.set_active_whitelist(\"MyList\");\n\n    WhitelistStore store(settings.get_config_dir());\n    store.set(\"MyList\", WhitelistEntry{{\"Alpha\", \"Beta\"}, {\"One\", \"Two\"}});\n    store.save();\n\n    store.initialize_from_settings(settings);\n\n    auto names = store.list_names();\n    REQUIRE(std::find(names.begin(), names.end(), \"MyList\") != names.end());\n    auto entry = store.get(\"MyList\");\n    REQUIRE(entry.has_value());\n    REQUIRE(entry->categories == std::vector<std::string>{\"Alpha\", \"Beta\"});\n    REQUIRE(entry->subcategories == std::vector<std::string>{\"One\", \"Two\"});\n\n    REQUIRE(settings.get_active_whitelist() == \"MyList\");\n    REQUIRE(settings.get_allowed_categories() == entry->categories);\n    REQUIRE(settings.get_allowed_subcategories() == entry->subcategories);\n\n    WhitelistStore reloaded(settings.get_config_dir());\n    REQUIRE(reloaded.load());\n    auto persisted = reloaded.get(\"MyList\");\n    REQUIRE(persisted.has_value());\n    REQUIRE(persisted->categories == entry->categories);\n    REQUIRE(persisted->subcategories == entry->subcategories);\n}\n\nTEST_CASE(\"CategorizationService builds numbered whitelist context\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    settings.set_allowed_categories({\"CatA\", \"CatB\"});\n    settings.set_allowed_subcategories({});\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    const std::string context = CategorizationServiceTestAccess::build_whitelist_context(service);\n\n    REQUIRE(context.find(\"Allowed main categories\") != std::string::npos);\n    REQUIRE(context.find(\"1) CatA\") != std::string::npos);\n    REQUIRE(context.find(\"2) CatB\") != std::string::npos);\n    REQUIRE(context.find(\"Allowed subcategories: any\") != std::string::npos);\n}\n\nTEST_CASE(\"CategorizationService builds category language context when non-English selected\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    settings.set_category_language(CategoryLanguage::French);\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    const std::string context = CategorizationServiceTestAccess::build_category_language_context(service);\n\n    REQUIRE_FALSE(context.empty());\n    REQUIRE(context.find(\"English only\") != std::string::npos);\n    REQUIRE(context.find(\"French\") != std::string::npos);\n}\n\nTEST_CASE(\"CategorizationService builds category language context for Spanish\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    settings.set_category_language(CategoryLanguage::Spanish);\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    const std::string context = CategorizationServiceTestAccess::build_category_language_context(service);\n\n    REQUIRE_FALSE(context.empty());\n    REQUIRE(context.find(\"English only\") != std::string::npos);\n    REQUIRE(context.find(\"Spanish\") != std::string::npos);\n}\n\nTEST_CASE(\"LocalLLM sanitizer keeps labeled multi-line replies intact\") {\n    const std::string output =\n        \"Category: Images\\n\"\n        \"Subcategory: Screenshots\\n\"\n        \"Reason: macOS screenshot naming pattern\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Images : Screenshots\");\n}\n\nTEST_CASE(\"LocalLLM sanitizer prefers the last inline pair\") {\n    const std::string output =\n        \"Texts : Documents\\n\"\n        \"Productivity : File managers\\n\"\n        \"Archives : CAD assets\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Archives : CAD assets\");\n}\n\nTEST_CASE(\"LocalLLM sanitizer strips rationale and natural language lead-ins\") {\n    const std::string output =\n        \"Based on the file name and context provided, the file falls under the Finances category : Credit reports\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Finances : Credit reports\");\n}\n\nTEST_CASE(\"LocalLLM sanitizer ignores trailing note lines\") {\n    const std::string output =\n        \"Images : Screenshots\\n\"\n        \"(Note: Since the file is an image and not an installer, this question should not have been directed to me.)\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Images : Screenshots\");\n}\n\nTEST_CASE(\"LocalLLM sanitizer strips translated parenthetical glosses\") {\n    const std::string output =\n        \"Traitement de texte. (Text documents) : Installateurs. (Software installation)\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Traitement de texte : Installateurs\");\n}\n\nTEST_CASE(\"LocalLLM sanitizer strips inline subcategory label artifacts from category values\") {\n    const std::string output = \"Category: Images, subcategory: Funny seals\";\n\n    REQUIRE(LocalLLMTestAccess::sanitize_output_for_testing(output) == \"Images : Funny seals\");\n}\n\nTEST_CASE(\"CategorizationService parses category output without spaced colon delimiters\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"report.xlsx\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(calls, \"Documents:Spreadsheets\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Documents\");\n    CHECK(categorized.front().subcategory == \"Spreadsheets\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService parses labeled category and subcategory lines\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"photo.jpg\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(calls, \"Category: Images\\nSubcategory: Photos\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Photos\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService extracts the trailing pair from verbose responses\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"Screenshot 2026-03-10 at 12.07.00.png\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(\n            calls,\n            \"Based on the filename and extension, the most appropriate categorization is: Images : Screenshots\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Screenshots\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService prefers the final pair when the model echoes examples\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"iphone14_pro_magsafe_stls.zip\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(\n            calls,\n            \"Texts : Documents\\n\"\n            \"Productivity : File managers\\n\"\n            \"Archives : CAD assets\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Archives\");\n    CHECK(categorized.front().subcategory == \"CAD assets\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService strips rationale from subcategory text\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"balenaEtcher-2.1.4-arm64.dmg\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(\n            calls,\n            \"Operating system : MacOS (based on the .dmg file extension) - This file is an installer for macOS software\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Operating system\");\n    CHECK(categorized.front().subcategory == \"MacOS\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService extracts a short category from natural language lead-ins\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"credit_excerpt.pdf\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(\n            calls,\n            \"Based on the file name and context provided, the file falls under the Finances category : Credit reports\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Finances\");\n    CHECK(categorized.front().subcategory == \"Credit reports\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService ignores trailing note lines after a valid answer\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"Capture d'ecran.png\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(\n            calls,\n            \"Images : Screenshots\\n\"\n            \"(Note: Since the file is an image and not an installer, this question should not have been directed to me.)\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Screenshots\");\n    CHECK(*calls == 1);\n}\n\nTEST_CASE(\"CategorizationService progress shows current and categorization paths\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"legacy_name.pdf\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::string suggested_name = \"new_suggested_file_name.pdf\";\n    const std::string prompt_path =\n        (data_dir.path() / suggested_name).generic_string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(calls, \"Category: Security\\nSubcategory: PCI DSS guidelines\");\n    };\n\n    std::vector<std::string> progress_messages;\n    const auto categorized = service.categorize_entries(\n        files,\n        true,\n        stop_flag,\n        [&progress_messages](const std::string& message) { progress_messages.push_back(message); },\n        {},\n        {},\n        {},\n        factory,\n        [suggested_name, prompt_path](const FileEntry&) {\n            return CategorizationService::PromptOverride{suggested_name, prompt_path};\n        });\n\n    REQUIRE(categorized.size() == 1);\n    REQUIRE(progress_messages.size() == 1);\n    CHECK(progress_messages.front().find(\"Category            : Security\") != std::string::npos);\n    CHECK(progress_messages.front().find(\"Subcat              : PCI DSS guidelines\") != std::string::npos);\n    CHECK(progress_messages.front().find(\"Current Path        : \" +\n                                         Utils::abbreviate_user_path(full_path)) != std::string::npos);\n    CHECK(progress_messages.front().find(\"Categorization Path : \" +\n                                         Utils::abbreviate_user_path(prompt_path)) != std::string::npos);\n}\n\nTEST_CASE(\"Document prompt helpers use the suggested filename for categorization\") {\n    CHECK(MainAppTestAccess::resolve_document_prompt_name(\"legacy_name.pdf\", \"cached_name.pdf\") ==\n          \"cached_name.pdf\");\n    CHECK(MainAppTestAccess::resolve_document_prompt_name(\"legacy_name.pdf\", \"\") ==\n          \"legacy_name.pdf\");\n}\n\nTEST_CASE(\"Document prompt path uses the suggested filename and preserves summaries\") {\n    TempDir data_dir;\n    const std::filesystem::path original_path = data_dir.path() / \"legacy_name.pdf\";\n    const std::string prompt_name = \"new_suggested_name.pdf\";\n    const std::string summary = \"PCI DSS quick reference\";\n    const std::string expected_path = Utils::path_to_utf8(data_dir.path() / prompt_name);\n    const std::string prompt_path = MainAppTestAccess::build_document_prompt_path(\n        original_path.string(),\n        prompt_name,\n        summary);\n\n    CHECK(prompt_path.find(expected_path) == 0);\n    CHECK(prompt_path.find(\"\\nDocument summary: \" + summary) != std::string::npos);\n    CHECK(prompt_path.find(\"legacy_name.pdf\") == std::string::npos);\n}\n\nTEST_CASE(\"CategorizationService stores canonical English labels and persists translated taxonomy labels\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    settings.set_category_language(CategoryLanguage::French);\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"setup_game.exe\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto categorize_calls = std::make_shared<int>(0);\n    auto translation_calls = std::make_shared<int>(0);\n    auto factory = [categorize_calls, translation_calls]() {\n        return std::make_unique<TranslationAwareLLM>(\n            categorize_calls,\n            translation_calls,\n            \"Software : Installers\",\n            std::deque<std::string>{\n                \"{\\\"category\\\":\\\"Logiciels\\\",\\\"subcategory\\\":\\\"Installateurs\\\"}\"\n            });\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Logiciels\");\n    CHECK(categorized.front().subcategory == \"Installateurs\");\n    CHECK(categorized.front().canonical_category == \"Software\");\n    CHECK(categorized.front().canonical_subcategory == \"Installers\");\n    CHECK(*categorize_calls == 1);\n    CHECK(*translation_calls == 1);\n\n    const auto cached = db.get_categorization_from_db(data_dir.path().string(), file_name, FileType::File);\n    REQUIRE(cached.size() == 2);\n    CHECK(cached[0] == \"Software\");\n    CHECK(cached[1] == \"Installers\");\n\n    const auto translated = db.get_category_translation(categorized.front().taxonomy_id, CategoryLanguage::French);\n    REQUIRE(translated.has_value());\n    CHECK(translated->category == \"Logiciels\");\n    CHECK(translated->subcategory == \"Installateurs\");\n\n    const auto resolved_french = db.resolve_category_for_language(\"Logiciels\", \"Installateurs\", CategoryLanguage::French);\n    CHECK(resolved_french.taxonomy_id == categorized.front().taxonomy_id);\n    CHECK(resolved_french.category == \"Software\");\n    CHECK(resolved_french.subcategory == \"Installers\");\n\n    const auto cached_entries = service.load_cached_entries(data_dir.path().string());\n    REQUIRE(cached_entries.size() == 1);\n    CHECK(cached_entries.front().category == \"Logiciels\");\n    CHECK(cached_entries.front().subcategory == \"Installateurs\");\n    CHECK(cached_entries.front().canonical_category == \"Software\");\n    CHECK(cached_entries.front().canonical_subcategory == \"Installers\");\n}\n\nTEST_CASE(\"CategorizationService strips inline subcategory label artifacts when parsing service output\") {\n    TempDir base_dir;\n    EnvVarGuard config_guard(\"AI_FILE_SORTER_CONFIG_DIR\", base_dir.path().string());\n    Settings settings;\n    DatabaseManager db(settings.get_config_dir());\n    CategorizationService service(settings, db, nullptr);\n\n    TempDir data_dir;\n    const std::string file_name = \"seal_photo.jpg\";\n    const std::string full_path = (data_dir.path() / file_name).string();\n    const std::vector<FileEntry> files = {FileEntry{full_path, file_name, FileType::File}};\n\n    std::atomic<bool> stop_flag{false};\n    auto calls = std::make_shared<int>(0);\n    auto factory = [calls]() {\n        return std::make_unique<FixedResponseLLM>(calls, \"Category: Images, subcategory: Funny seals\");\n    };\n\n    const auto categorized = service.categorize_entries(files,\n                                                        true,\n                                                        stop_flag,\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        {},\n                                                        factory);\n\n    REQUIRE(categorized.size() == 1);\n    CHECK(categorized.front().category == \"Images\");\n    CHECK(categorized.front().subcategory == \"Funny seals\");\n    CHECK(*calls == 1);\n}\n"
  }
]